Search code examples
swiftsprite-kitskphysicsbody

SKPhysics Contact not functioning properly


I am trying to use the SKPhysicsContactDelegate function in SpriteKit and it will not seem to work. I want one sprite to perform an action when it hits the other. I have set up breakpoints at the didBeginContact function and for some reason my application never calls this function. All help appreciated. Code posted below.

struct PhysicsCatagory {
    static let Enemy :UInt32 = 0x1 << 0
    static let Slider :UInt32 = 0x1 << 1
    static let Circle :UInt32 = 0x1 << 2
}

class GameScene: SKScene, SKPhysicsContactDelegate {

    var EnemyTimer = NSTimer()

    var Circle = SKSpriteNode()
    var Slider = SKSpriteNode()
    var FastButton = SKNode()

    var Title = SKSpriteNode()
    var Text = SKSpriteNode()

    var Path = UIBezierPath()

    var gameStarted = Bool()

    override func didMoveToView(view: SKView) {

        self.physicsWorld.contactDelegate = self

        self.backgroundColor = UIColor.whiteColor()


        Circle = SKSpriteNode(imageNamed:"blueCircle")
        Circle.size = CGSize(width: 140, height: 140)
        Circle.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
        Circle.zPosition = 1.0
        self.addChild(Circle)

        Slider = SKSpriteNode(imageNamed: "blocker1")
        Slider.size = CGSize(width: 15, height: 50)
        Slider.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2 + 80)
        addChild(Slider)
        Slider.zPosition = 1.0


        moveClockWise()



            }


    func didBeginContact(contact: SKPhysicsContact) {
        if contact.bodyA.node != nil && contact.bodyB.node != nil{
            let firstBody = contact.bodyA.node as! SKSpriteNode
            let secondBody = contact.bodyB.node as! SKSpriteNode

        if ((firstBody.name == "Enemy") && (secondBody.name == "Slider")){

            collisionBall(firstBody, Slider: secondBody)

        }
        else if  ((firstBody.name == "Slider") && (secondBody.name == "Enemy")) {

            collisionBall(secondBody, Slider: firstBody)

        }


    }

    }

    func collisionBall(Enemy : SKSpriteNode, Slider : SKSpriteNode){

        Enemy.physicsBody?.dynamic = true
        Enemy.physicsBody?.affectedByGravity = true
        Enemy.physicsBody?.mass = 4.0
        Slider.physicsBody?.mass = 4.0

        Enemy.removeAllActions()

        Enemy.physicsBody?.contactTestBitMask = 0
        Enemy.physicsBody?.collisionBitMask = 0
        Enemy.name = nil



    }


    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

        //Slider.hidden = false
        FastButton.hidden = false
        Title.hidden = true
        Text.hidden = true

        EnemyTimer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: #selector(GameScene.Enemies), userInfo: nil, repeats: true)

        //Physics
        Slider.physicsBody?.categoryBitMask = PhysicsCatagory.Slider
        Slider.physicsBody?.collisionBitMask = PhysicsCatagory.Enemy
        Slider.physicsBody?.contactTestBitMask = PhysicsCatagory.Enemy
        Slider.name = "Slider"
        Slider.physicsBody?.dynamic = true
        Slider.physicsBody?.affectedByGravity = true




        if gameStarted == false{

            gameStarted = true



        }
        else if gameStarted == true{


        }


    }

    func moveClockWise(){

        let dx = Slider.position.x / 2
        let dy = Slider.position.y / 2

        let rad = atan2(dy, dx)


        let Path = UIBezierPath(arcCenter: CGPoint(x: self.frame.width / 2, y: self.frame.height / 2), radius: 90, startAngle: rad, endAngle: rad + CGFloat(M_PI * 4), clockwise: true)

        let follow = SKAction.followPath(Path.CGPath, asOffset: false, orientToPath: true, speed: 150)
        //let rotate = SKAction.rotateByAngle(75, duration: 100)

        Slider.runAction(SKAction.repeatActionForever(follow).reversedAction())
        //Slider.runAction(SKAction.repeatActionForever(rotate).reversedAction())


    }


    func Enemies(){

        let Enemy = SKSpriteNode(imageNamed: "darkRedDot")
        Enemy.size = CGSize(width: 20, height: 20)


        //Physics
        Enemy.physicsBody = SKPhysicsBody(circleOfRadius: Enemy.size.width / 2)
        Enemy.physicsBody?.categoryBitMask = PhysicsCatagory.Enemy
        Enemy.physicsBody?.contactTestBitMask = PhysicsCatagory.Slider //| PhysicsCatagory.Circle
        Enemy.physicsBody?.collisionBitMask = PhysicsCatagory.Slider //| PhysicsCatagory.Circle
        Enemy.physicsBody?.dynamic = true
        Enemy.physicsBody?.affectedByGravity = false
        Enemy.name = "Enemy"

Solution

  • The contact is not beginning because your slider has no physics body, making it impossible to recognize contact. Unless, it's not in this code, your slider has no physics body, but your enemy does. Try declaring Slider.phisicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "blocker1"), size: Slider.size)

    Also, you should read about standard naming conventions in Swift. It is recommended that your variables always start with lowercase letters (eg. enemyTimer, circle, slider, fastButton, etc...).