Reputation: 215
I am making an iOS app and running into some problems with physics. As you can tell by the .GIF below, when I rotate the hexagon and the ball hits the rectangle at an angle, it loses some of its velocity and doesn't bounce as high. This is because of the reason shared here (basically because I am constraining the balls horizontal position, it's only using the vertical velocity when hitting an angle, thus losing speed).
I cannot for the life of me figure out a solution to fix this problem. Does anybody have any ideas??
Code for Ball node:
func createBallNode(ballColor: String) -> SKSpriteNode {
let ball = SKSpriteNode(imageNamed: ballColor)
ball.position = CGPoint(x: CGRectGetMidX(frame), y: CGRectGetMidY(frame)+30)
ball.zPosition = 1
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.width/2)
ball.physicsBody?.affectedByGravity = true
ball.physicsBody?.restitution = 1
ball.physicsBody?.linearDamping = 0
ball.physicsBody?.friction = 0
ball.physicsBody?.categoryBitMask = ColliderType.Ball.rawValue
ball.physicsBody?.contactTestBitMask = ColliderType.Rect.rawValue
ball.physicsBody?.collisionBitMask = ColliderType.Rect.rawValue
let centerX = ball.position.x
let range = SKRange(lowerLimit: centerX, upperLimit: centerX)
let constraint = SKConstraint.positionX(range)
ball.constraints = [constraint]
return ball
}
Upvotes: 4
Views: 309
Reputation: 59496
Yes, the problem is probably causes by the ball hitting the hexagon when it is not perfectly "aligned". In this case the ball loses vertical speed in favour of the horizontal axis.
Since you want a "discrete logic" I believe in this scenario your should avoid physics (at least for the bouncing part). It would be much easier repeating an SKAction
that moves the ball vertically.
I prepared a simple example
class GameScene: SKScene {
override func didMove(to view: SKView) {
super.didMove(to: view)
let ball = createBallNode()
self.addChild(ball)
}
func createBallNode() -> SKSpriteNode {
let ball = SKSpriteNode(imageNamed: "ball")
ball.position = CGPoint(x: frame.midX, y: frame.minY + ball.frame.height / 2)
let goUp = SKAction.move(by: CGVector(dx: 0, dy: 600), duration: 1)
goUp.timingMode = .easeOut
let goDown = SKAction.move(by: CGVector(dx: 0, dy: -600), duration: 1)
goDown.timingMode = .easeIn
let goUpAndDown = SKAction.sequence([goUp, goDown])
let forever = SKAction.repeatForever(goUpAndDown)
ball.run(forever)
return ball
}
}
If you need to perform a check every time the ball touches the base of the Hexagon you can use this code
class GameScene: SKScene {
override func didMove(to view: SKView) {
super.didMove(to: view)
let ball = createBallNode()
self.addChild(ball)
}
func createBallNode() -> SKSpriteNode {
let ball = SKSpriteNode(imageNamed: "ball")
ball.position = CGPoint(x: frame.midX, y: frame.minY + ball.frame.height / 2)
let goUp = SKAction.move(by: CGVector(dx: 0, dy: 600), duration: 1)
goUp.timingMode = .easeOut
let goDown = SKAction.move(by: CGVector(dx: 0, dy: -600), duration: 1)
goDown.timingMode = .easeIn
let check = SKAction.customAction(withDuration: 0) { (node, elapsedTime) in
self.ballTouchesBase()
}
let goUpAndDown = SKAction.sequence([goUp, goDown, check])
let forever = SKAction.repeatForever(goUpAndDown)
ball.run(forever)
return ball
}
private func ballTouchesBase() {
print("The ball touched the base")
}
}
As you can see now the method ballTouchesBase
is called every time the ball is a te lower y coordinate. This is the right place to add a check for the color of your hexagon.
Upvotes: 1