Search code examples
swiftsprite-kitcollisionskphysicsbodybounce

Certain physicsBody collisions not registering


I'm practising what I have learnt in swift so far and I'm trying to make a simple game where a ball bounces on a platform that you can move. I have a floor underneath the platform, which will eventually allow the game to end. At the moment, the ball can bounce off the floor, and the barrier I have put around the scene, but just passes through the platform that you can move across the screen. Apart from category names, the code for the floor and platform are basically the same, I can't tell why this isn't working. Here is my code:

class GameScene: SKScene, SKPhysicsContactDelegate {


    let ballGroup: UInt32 = 0b001
    let platformGroup: UInt32 = 0b010
    let floorGroup: UInt32 = 0b100
    let sceneEdgeGroup : UInt32 = 0b101

    var platform = SKShapeNode()
    var floor = SKShapeNode()
    var ball = SKShapeNode()

    var i = 0

    override func didMoveToView(view: SKView) {

        self.size = view.bounds.size
        self.physicsWorld.contactDelegate = self
        self.physicsWorld.gravity = CGVectorMake(0, -5)

        let physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
        self.physicsBody = physicsBody
        self.physicsBody?.categoryBitMask = sceneEdgeGroup
        self.physicsBody?.friction = 0
        self.physicsBody?.restitution = 1


        platform = SKShapeNode(rectOfSize: CGSizeMake(100, 15))
        platform.fillColor = SKColor.redColor()

        platform.position = CGPointMake(CGRectGetMidX(self.frame)  -  (CGRectGetMidX(self.frame)), CGRectGetMidY(self.frame) * 0.4)
        platform.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(100, 15))
        platform.physicsBody?.dynamic = false
        platform.physicsBody?.allowsRotation = false

        platform.physicsBody?.categoryBitMask = platformGroup
        platform.physicsBody?.friction = 0


        self.addChild(platform)


        floor = SKShapeNode(rectOfSize: CGSizeMake(self.frame.size.width, 200))
        floor.fillColor = SKColor.blueColor()
        floor.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) - CGRectGetMidY(self.frame))
        floor.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(self.frame.size.width, 200))
        floor.physicsBody?.dynamic = false

        floor.physicsBody?.categoryBitMask = floorGroup
        floor.physicsBody?.friction = 0

        self.addChild(floor)


        ball = SKShapeNode(circleOfRadius: 5)
        ball.fillColor = SKColor.blackColor()
        ball.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) * 1.5 )
        ball.physicsBody = SKPhysicsBody(circleOfRadius: 5)
        ball.physicsBody?.dynamic = true
        ball.physicsBody?.categoryBitMask = ballGroup
        ball.physicsBody?.collisionBitMask = platformGroup
        ball.physicsBody?.collisionBitMask = floorGroup
        ball.physicsBody?.collisionBitMask = sceneEdgeGroup

        ball.physicsBody?.contactTestBitMask = floorGroup
        ball.physicsBody?.contactTestBitMask = platformGroup
        ball.physicsBody?.contactTestBitMask = sceneEdgeGroup

        ball.physicsBody?.friction = 0
        ball.physicsBody?.restitution = 0
        ball.physicsBody?.mass = 0.5
        ball.physicsBody?.linearDamping = 0
        ball.physicsBody?.allowsRotation = false

        self.addChild(ball)

        //start ball movement
        ball.physicsBody?.applyImpulse(CGVectorMake(-5, 0))
    }

    override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {

        let moveAction1 = SKAction.moveByX((self.frame.width) , y: 0, duration: 1)
        let moveAction2 = SKAction.moveByX((-self.frame.width) , y: 0, duration: 1)


        if(i == 0){
            platform.runAction(moveAction1)
            i++
        }else if (i == 1){
            platform.runAction(moveAction2)
            i = 0
        }
    }


    func didBeginContact(contact: SKPhysicsContact) {
        if(contact.bodyB.categoryBitMask == ballGroup && contact.bodyA.categoryBitMask == floorGroup || (contact.bodyA.categoryBitMask == ballGroup && contact.bodyB.categoryBitMask == floorGroup)){

            //this contact works
           // ball.physicsBody?.restitution = 0.5
            //ball.physicsBody?.applyImpulse(CGVectorMake(0, 350))

        }

        if(contact.bodyB.categoryBitMask == ballGroup && contact.bodyA.categoryBitMask == platformGroup || (contact.bodyA.categoryBitMask == ballGroup && contact.bodyB.categoryBitMask == platformGroup)){

            //this contact doesn't work
            //should make ball bounce
            ball.physicsBody?.applyImpulse(CGVectorMake(0, 300))
        }

    }

}


Solution

  • Currently you overwrite the Bitmasks:

        ball.physicsBody?.contactTestBitMask = floorGroup
        ball.physicsBody?.contactTestBitMask = platformGroup
        ball.physicsBody?.contactTestBitMask = sceneEdgeGroup
    

    You have to combine them:

        ball.physicsBody?.contactTestBitMask = floorGroup | platformGroup | sceneEdgeGroup
    

    Same here:

        ball.physicsBody?.collisionBitMask = platformGroup
        ball.physicsBody?.collisionBitMask = floorGroup
        ball.physicsBody?.collisionBitMask = sceneEdgeGroup