Naiem Salib
Naiem Salib

Reputation: 121

contact and collision detection in swift

I am working on a game of falling objects and a ball that avoids those objects ,

let ballCatogary:UInt32 = 0x1 << 0
let objectsCatogary:UInt32 = 0x1 << 1
let bottomWallCatogary:UInt32 = 0x1 << 3

1)the ballcatogary is for the ball node that the user controls 2)the objects category is for the right and left walls , and the falling objects that when the user interacts with ,the game stops 3) the bottomcatogary is a sknode that the objects doesn't interact with , but when it passes through it the score value increases

I assigned each node to its categoryBitMask, but now I don't know what to write in the didBeginContact, all i need is help with the did begin collision method, not how to increase the score or end the game, I got that covered.

my code:

//
//  PlayScene.swift
//  WalkRun
//
//  Created by naeim on 7/10/15.
//  Copyright (c) 2015 naeim. All rights reserved.
//

import Foundation
import SpriteKit

class PlayScene: SKScene, SKPhysicsContactDelegate{

    var ball = SKSpriteNode(imageNamed: "ball")
    var wall = SKNode()
    var wallRight = SKNode()
    var ballSpeed = CGFloat()

    let ballCatogary:UInt32 = 0x1 << 0
    let objectsCatogary:UInt32 = 0x1 << 1
    let bottomWallCatogary:UInt32 = 0x1 << 3

    var endOfScreenRight = CGFloat()

    var gameOver = 0

    var movingObjects = SKNode()

    var score = 0
    var scoreLabel = SKLabelNode()

    var bigWall = SKSpriteNode()
    var tallWall = SKSpriteNode()



    override func didMoveToView(view: SKView) {

        endOfScreenRight = 100

        self.physicsWorld.contactDelegate = self

        backgroundColor = UIColor(hex: 0x80d9ff)
        self.physicsWorld.gravity = CGVectorMake(-9,0)

        self.addChild(movingObjects)

        //creating the ball
        ball.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMinY(self.frame) + self.ball.size.height * 2)
        ball.physicsBody = SKPhysicsBody(circleOfRadius: self.ball.size.width / 2)
        ball.zPosition = 10
        ball.physicsBody?.categoryBitMask = ballCatogary
        ball.physicsBody?.collisionBitMask =  objectsCatogary
        ball.physicsBody?.contactTestBitMask =  objectsCatogary


        self.addChild(ball)

        //creating the wall of the left
        wall.position = CGPointMake(CGRectGetMinX(self.frame),CGRectGetMinY(self.frame))
        wall.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(2, self.frame.size.height * 2.0))
        wall.physicsBody?.dynamic = false
        wall.physicsBody?.categoryBitMask = objectsCatogary

        self.addChild(wall)

        //creating the wall of the right
        wallRight.position = CGPointMake(CGRectGetMaxX(self.frame), CGRectGetMinY(self.frame))
        wallRight.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(2, self.frame.size.height * 2.0))
        wallRight.physicsBody?.dynamic = false
        wallRight.physicsBody?.categoryBitMask = objectsCatogary


        self.addChild(wallRight)


        //creating the label
        scoreLabel.fontName = "Helvetica"
        scoreLabel.fontSize = 60
        scoreLabel.text = "0"
        scoreLabel.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame)  )
        self.addChild(scoreLabel)

        //bottom wall
        var bottomWall = SKNode()
        bottomWall.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMinY(self.frame) + ball.position.y / 1.4)
        bottomWall.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(self.frame.size.width , 1))
        bottomWall.physicsBody?.dynamic = false
        bottomWall.physicsBody?.affectedByGravity = false
        bottomWall.physicsBody?.categoryBitMask = bottomWallCatogary


        self.addChild(bottomWall)




        var timer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: Selector("randObject"), userInfo: nil, repeats: true)



    }



    //function to randomly choose which object

    func randObject(){
        if gameOver == 0{


        var rand = arc4random_uniform(6)+1


        switch(rand){

        case 1:
            leftObject()

        case 2:
            middleObject()

        case 3:
            rightObject()

        case 4:
            LeftAndMiddleObject()

        case 5:
            rightAndLeftObject()

        case 6:
            rightAndMiddleObject()

        default:
            println("error !! non a number other than 0, 1, 2 has been choosen .")

            }


        }
    }

    //function that creates a Bigwall
    func createBigWall(PositionX:CGFloat , PositionY:CGFloat){
        bigWall = SKSpriteNode(imageNamed: "shortwall")
        bigWall.position = CGPointMake(PositionX, PositionY)
        bigWall.physicsBody = SKPhysicsBody(rectangleOfSize: self.bigWall.size)
        bigWall.physicsBody?.dynamic = false
        bigWall.physicsBody?.affectedByGravity = false
        bigWall.physicsBody?.categoryBitMask = objectsCatogary
        bigWall.physicsBody?.collisionBitMask = ballCatogary
        bigWall.physicsBody?.contactTestBitMask = ballCatogary

        var moveObjects = SKAction.moveByX(0, y: -self.frame.size.height * 2, duration: NSTimeInterval(self.frame.size.height / 100))
        var removeObjects = SKAction.removeFromParent()
        var moveAndRemoveObjects = SKAction.sequence([moveObjects,removeObjects])
        bigWall.runAction(moveAndRemoveObjects)
        movingObjects.addChild(bigWall)

    }
    //function that creates a Tallwall
    func createTallWall(PositionX:CGFloat , PositionY:CGFloat ){
        tallWall = SKSpriteNode(imageNamed: "tallwall")
        tallWall.position = CGPointMake(PositionX, PositionY)
        tallWall.physicsBody = SKPhysicsBody(rectangleOfSize: self.tallWall.size)
        tallWall.physicsBody?.dynamic = false
        tallWall.physicsBody?.affectedByGravity = false
        tallWall.physicsBody?.categoryBitMask = objectsCatogary
        tallWall.physicsBody?.collisionBitMask = ballCatogary
        tallWall.physicsBody?.contactTestBitMask = ballCatogary
        var moveObjects = SKAction.moveByX(0, y: -self.frame.size.height * 2, duration: NSTimeInterval(self.frame.size.height / 100))
        var removeObjects = SKAction.removeFromParent()
        var moveAndRemoveObjects = SKAction.sequence([moveObjects,removeObjects])
        tallWall.runAction(moveAndRemoveObjects)
        movingObjects.addChild(tallWall)

    }

    //function to create the left objects

    func leftObject(){
        var rand = arc4random_uniform(2) + 1
        if rand == 1
        {


           createBigWall(CGRectGetMinX(self.frame) + 30, PositionY: CGRectGetMaxY(self.frame))

        }

        else
        {
            createTallWall(CGRectGetMinX(self.frame) - 60, PositionY: CGRectGetMaxY(self.frame))




        }


    }

    //function to create the middle objects

    func middleObject(){

        var rand = arc4random_uniform(2) + 1
        if rand == 1
        {
            createBigWall(CGRectGetMidX(self.frame) , PositionY: CGRectGetMaxY(self.frame))

        }
        else
        {

            createTallWall(CGRectGetMidX(self.frame), PositionY: CGRectGetMaxY(self.frame))

        }

    }

    //function to create the right objects

    func rightObject(){
        var rand = arc4random_uniform(2) + 1
        if rand == 1
        {
            createBigWall(CGRectGetMaxX(self.frame) - 30, PositionY: CGRectGetMaxY(self.frame))



        }
        else
        {
      createTallWall(CGRectGetMaxX(self.frame) - 60, PositionY: CGRectGetMaxY(self.frame))

        }


    }

    //function to create a right and left object

    func rightAndLeftObject(){

        var rand = arc4random_uniform(2) + 1
        if rand == 1
        {
            createBigWall(CGRectGetMaxX(self.frame) - 30 , PositionY: CGRectGetMaxY(self.frame))
            createTallWall(CGRectGetMinX(self.frame) + 60, PositionY: CGRectGetMaxY(self.frame))
        }
        else
        {

            createBigWall(CGRectGetMinX(self.frame) - 30, PositionY: CGRectGetMaxY(self.frame))
            createTallWall(CGRectGetMaxX(self.frame) + 60, PositionY: CGRectGetMaxY(self.frame))

                    }


    }

    func rightAndMiddleObject(){

        var rand = arc4random_uniform(2) + 1
        if rand == 1
        {
            createBigWall(CGRectGetMidX(self.frame) - 30, PositionY: CGRectGetMaxY(self.frame))
            createTallWall(CGRectGetMaxX(self.frame) + 60, PositionY: CGRectGetMaxY(self.frame))
        }
        else
        {
            createBigWall(CGRectGetMaxX(self.frame) - 30, PositionY: CGRectGetMaxY(self.frame))
            createTallWall(CGRectGetMinX(self.frame) + 60, PositionY: CGRectGetMaxY(self.frame))
        }


    }

    func LeftAndMiddleObject(){

        var rand = arc4random_uniform(2) + 1
        if rand == 1
        {
            createBigWall(CGRectGetMinX(self.frame) - 30, PositionY: CGRectGetMaxY(self.frame))
            createTallWall(CGRectGetMidX(self.frame) + 60, PositionY: CGRectGetMaxY(self.frame))
        }
        else
        {
            createBigWall(CGRectGetMidX(self.frame) - 30, PositionY: CGRectGetMaxY(self.frame))
            createTallWall(CGRectGetMinX(self.frame) + 60, PositionY: CGRectGetMaxY(self.frame))
        }


    }




    func didBeginContact(contact: SKPhysicsContact) {


        // 1. Create local variables for two physics bodies
        var firstBody: SKPhysicsBody
        var secondBody: SKPhysicsBody

        // 2. Assign the two physics bodies so that the one with the lower category is always stored in firstBody
        if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
            firstBody = contact.bodyA
            secondBody = contact.bodyB
        } else {
            firstBody = contact.bodyB
            secondBody = contact.bodyA
        }

        // 3. react to the contact between ball and bottom
        if firstBody.categoryBitMask == ballCatogary && secondBody.categoryBitMask == objectsCatogary {

            gameOver = 1
            movingObjects.speed = 0


        }
        else
        {
            println("score ++")
        }
    }

    override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
        if gameOver == 0 {

        ball.physicsBody?.velocity = CGVectorMake(0, 0)
        ball.physicsBody?.applyImpulse(CGVectorMake(70,0))

        }

    }

    override func update(currentTime: NSTimeInterval) {

         if gameOver == 0 {

        }


    }
}

Upvotes: 1

Views: 130

Answers (1)

Dharmesh Kheni
Dharmesh Kheni

Reputation: 71854

I am not sure what are you asking but check this example code:

    //This delegate function will call when two body collide with each other
    func didBeginContact(contact: SKPhysicsContact) {


        // 1. Create local variables for two physics bodies
        var firstBody: SKPhysicsBody
        var secondBody: SKPhysicsBody

        // 2. Assign the two physics bodies so that the one with the lower category is always stored in firstBody
        if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
            firstBody = contact.bodyA
            secondBody = contact.bodyB
        } else {
            firstBody = contact.bodyB
            secondBody = contact.bodyA
        }

        // 3. react to the contact between ball and bottom
        if firstBody.categoryBitMask == ballCatogary && secondBody.categoryBitMask == bottomWallCatogary {
            //TODO: Replace the log statement with display of Game Over Scene
            //add your code here.

        }
    }

And don't forget to add SKPhysicsContactDelegate at your class declaration and it will look like:

class playScene : SKScene, SKPhysicsContactDelegate {

    //your code
}

If you want to detect another collision the you can do it this way:

if firstBody.categoryBitMask == ballCatogary && secondBody.categoryBitMask == objectsCatogary {

        gameOver = 1
        movingObjects.speed = 0


    }
    else if firstBody.categoryBitMask == objectsCatogary && secondBody.categoryBitMask == bottomWallCatogary{
         score++
         println(score)
    }

Hope this will help.

Upvotes: 1

Related Questions