Jimmy Lee Jimmy Lee - 1 year ago 73
Swift Question

SKSpriteNode losing velocity upon collision

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

enter image description here

Answer Source

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()

    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)
        return ball

enter image description here