Josh Schlabach
Josh Schlabach

Reputation: 411

Why won't this detect collisions and contacts?

I have been working at this for about a week now, and I am in need of help. Please figure out why this won't work!

(P.S. I have SKPhysicsContactDelegate in my GameScene. Also, I have self.physicsWorld.contactDelegate = self in my didMoveToView.)

Here is my code:

This is out outside of the didMoveToView:

let squareGroup: UInt32 = 1
let obstacleGroup: UInt32 = 2

This is inside my didMoveToView:

square.position = CGPointMake(self.size.width/2, self.size.height/1.5)
square.zPosition = 35
square.size = CGSize(width: 40, height: 40)
square.physicsBody = SKPhysicsBody(rectangleOfSize: square.size)
square.physicsBody?.affectedByGravity = false
square.physicsBody?.dynamic = true
square.physicsBody?.allowsRotation = false
square.physicsBody?.categoryBitMask = squareGroup
square.physicsBody?.collisionBitMask = obstacleGroup
square.physicsBody?.contactTestBitMask = obstacleGroup
square.name = "Square"
self.addChild(square)

This is also inside my didMoveToView: *AND: Nothing happens when the square and obstacle touch. It doesn't print contact or anything.

func didBeginContact(contact: SKPhysicsContact) {

    print("contact")

    let newScene = GameplayScene(size: self.size)
    _ = SKTransition.fadeWithDuration(1)
    self.view?.presentScene(newScene)

}

Lastly, this is my obstacle code, which is outside of the didMoveToView: Please NOTE: I am only trying out Obstacle 2 at the moment to get it to work.

func addObstacles() {

    let obstacle1 = SKSpriteNode(imageNamed: "Obstacle")
    let obstacle2 = SKSpriteNode(imageNamed: "Obstacle")
    obstacle1.xScale = 2
    obstacle2.xScale = 2


    func randInRange(range: Range<Int>) -> Int {
        return  Int(arc4random_uniform(UInt32(range.endIndex - range.startIndex))) + range.startIndex
    }

    let random = randInRange(205...470)
    let moveDown1 = SKAction.moveByX(0, y: -self.size.width, duration: 2.5)
    let repeatAction1 = SKAction.repeatActionForever(moveDown1)
    let removeObstacle1 = SKAction.removeFromParent()
    let moveAndRemove1 = SKAction.sequence([repeatAction1, removeObstacle1])


    obstacle1.position = CGPointMake(CGFloat(random), self.frame.size.height * 2)
    obstacle1.zPosition = 40
    obstacle1.physicsBody = SKPhysicsBody(rectangleOfSize: obstacle1.size)
    obstacle1.physicsBody?.affectedByGravity = false
    obstacle1.physicsBody?.dynamic = false
    obstacle1.runAction(moveAndRemove1)
    self.addChild(obstacle1)

    let moveDown2 = SKAction.moveByX(0, y: -self.size.width, duration: 2.5)
    let repeatAction2 = SKAction.repeatActionForever(moveDown2)
    let removeObstacle2 = SKAction.removeFromParent()
    let moveAndRemove2 = SKAction.sequence([repeatAction2, removeObstacle2])


    obstacle2.position = CGPointMake(CGFloat(random) + 460, self.frame.size.height * 2)
    obstacle2.zPosition = 40
    obstacle2.physicsBody = SKPhysicsBody(rectangleOfSize: obstacle2.size)
    obstacle2.physicsBody?.affectedByGravity = false
    obstacle2.physicsBody?.dynamic = false
    obstacle2.physicsBody?.categoryBitMask = obstacleGroup


    obstacle2.name = "Obstacle2"


    obstacle2.runAction(moveAndRemove2)
    self.addChild(obstacle2)

}


func repeatObstacles() {
    let generateObstacles = SKAction.sequence([SKAction.runBlock(self.addObstacles), SKAction.waitForDuration(1.3)])
    let endlessAction = SKAction.repeatActionForever(generateObstacles)
    runAction(endlessAction)

}

I've been stuck on this for a while now. If you need more information just ask me! I need help.

Upvotes: 1

Views: 78

Answers (2)

Knight0fDragon
Knight0fDragon

Reputation: 16837

First: change your contact code to look like this

func didBeginContact(contact: SKPhysicsContact) {

    print("contact")

    if ((contact.bodyA.categoryBitMask == squareGroup &&   contact.bodyB.categoryBitMask == obstacleGroup) ||
    (contact.bodyA.categoryBitMask == obstacleGroup && contact.bodyB.categoryBitMask == squareGroup)) {

      NSNotificationCenter.defaultCenter().postNotificationName("Gameover",object:nil,userInfo:nil);
    }
}     

It is bad practice to assign a new scene inside of your current scene, this is something that you should be telling the view to do. Start a chat with me on here and I will go over how to set this up in your view, since this is not part of the current answer. There are better ways to handle this, posting a notification is the easiest way to get you started with communicating your view, lets get this working, then you can research how to create delegates.

Second, add the contact and collision groups to your obstacle 2 object: obstacle2.physicsBody?.collisionBitMask = obstacleGroup obstacle2.physicsBody?.contactTestBitMask = squareGroup as pointed out by @Darvydas

Third, switch obstacle2 dynamic to true since you want this to interact with other items: obstacle2.physicsBody?.dynamic = false

Now you should be getting into the didBeginContact method, put a breakpoint on the print("contact") to see if you are getting in there.

Fourth, take the didBeginContact function out of the didMoveToView otherwise it will never get called. (If we had seen this code in the question correctly, it would have been solved)

Upvotes: 1

Darvas
Darvas

Reputation: 974

categoryBitMask should be defined like this:

let squareGroup: UInt32 = 0x1 << 1
let obstacleGroup: UInt32 = 0x1 << 2

Also define obstacles collisionBitMask

obstacle2.physicsBody?.collisionBitMask = obstacleGroup

And your obstacle contactTestBitMask

obstacle2.physicsBody?.contactTestBitMask = squareGroup

Check for contact:

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

        // Handle Contact
    }
}

Upvotes: 2

Related Questions