Seed12
Seed12

Reputation: 83

Collisions in SpriteKit

I have an object kept between two bars. I have collisions set up but I'm not getting the print message "We have Contact" when making contact with either the top or bottom bar and I'm not sure why? I think it might have something to do with the boundary physicsBody. The image below is to give an example of the bars, where the object is kept between them.enter image description here

     var gameOver = false



override func didMoveToView(view: SKView) {
    scene?.scaleMode = SKSceneScaleMode.AspectFill


    self.physicsWorld.gravity = CGVectorMake(0.0, 2.0)
    physicsWorld.contactDelegate = self

    object = SKSpriteNode( imageNamed: "object")
    object.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
    object.physicsBody = SKPhysicsBody(circleOfRadius: object.size.width / 0.32)

    object.physicsBody?.dynamic = true
    object.physicsBody?.allowsRotation = true
    self.addChild(object)
    object.zPosition = 2


    struct ColliderType {

        static let object: UInt32 = 0x1 << 0
        static let boundary: UInt32 = 0x1 << 1


    }
   let boundary = SKPhysicsBody(edgeLoopFromRect: CGRect(x: 253, y: 138, width:515, height:354))
   self.physicsBody = boundary
    self.physicsBody?.friction = 0
    let push = CGVectorMake(10, 10)
   object.physicsBody?.applyImpulse(push)


   object.physicsBody?.categoryBitMask = ColliderType.object
   object.physicsBody?.contactTestBitMask = ColliderType.boundary
   object.physicsBody?.collisionBitMask = ColliderType.boundary


    boundary.contactTestBitMask = ColliderType.object
    boundary.categoryBitMask = ColliderType.boundary
    boundary.collisionBitMask = ColliderType.object


    func didBeginContact(contact:SKPhysicsContact) {
        print("We have Contact")

        gameOver = true
        self.speed = 0

    }

Upvotes: 1

Views: 229

Answers (2)

crashoverride777
crashoverride777

Reputation: 10664

Try browsing the web and stackoverflow before asking a question because there is a lot of tutorials on the web and even stack overflow about this. This question might even be closed because collision detection is one of the basics in SpriteKit and has been asked a lot about on SO.

Anyway there is some errors/omissions in your code, so lets have a look.

1) You need to set the physics world contact delegate in your scenes "didMoveToView" method, so that it is actually listening for contacts. This is the number 1 thing people, including me, forget and than wonder for hours why nothing is working.

 physicsWorld.contactDelegate = self

2) You are also not giving your sprites a physicsBody

 object.physicsBody = SKPhysicsBody(...)

You have to always give them a physics body first and than set properties such as contactTestBitMasks etc.

3) Try using ? instead of ! when dealing with optionals to avoid nil crashes. Try to always do this even though you know that it is not nil. So say

...physicsBody?.contactTestBitMask...

instead of

...physicsBody!.contactTestBitMask...

You are sometimes doing it, and sometimes not.

In your current code you could get a crash because object has no physicsBody but you are force unwrapping it, essentially telling it that it does have a physics body, which is dangerous.

For example that line in your code should not work

 object.physicsBody?.applyImpulse(push)

as there is no physics body on the object, but because it is not force unwrapping (?) nothing happens. Try changing that line using a ! and you should get a crash. So always use ? when dealing with optionals and when the compiler allows you too.

Also that line should be after you have set up the object sprite not before.

4) Try to write your physics categories differently, your way will get confusing very quick when adding more categories because you cannot just increment the last number. So in your example the next collider type will have to be 4, 8, 16 etc.

Try this instead where you only need to increment the last number by 1.

 struct ColliderType {
    static let object: UInt32 = 0x1 << 0
    static let boundary: UInt32 = 0x1 << 1
    ....
 }

Than use it like so

...contactTestBitMask = ColliderType.object
...

You whole code should look like this

  struct ColliderType {

static let object: UInt32 = 0x1 << 0
static let boundary: UInt32 = 0x1 << 1


 }

  class GameScene: SKScene, SKPhysicsContactDelegate {

var gameOver = false

var object: SKSpriteNode!


override func didMoveToView(view: SKView) {
    scene?.scaleMode = SKSceneScaleMode.AspectFill


    self.physicsWorld.gravity = CGVectorMake(0.0, 2.0)
    physicsWorld.contactDelegate = self

    object = SKSpriteNode( imageNamed: "Spaceship")
    object.zPosition = 2
    object.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
    object.physicsBody = SKPhysicsBody(circleOfRadius: object.size.width / 0.32)

    object.physicsBody?.dynamic = true
    object.physicsBody?.allowsRotation = true
    object.physicsBody?.categoryBitMask = ColliderType.object
    object.physicsBody?.contactTestBitMask = ColliderType.boundary
    object.physicsBody?.collisionBitMask = ColliderType.boundary
    self.addChild(object)


    let boundary = SKPhysicsBody(edgeLoopFromRect: CGRect(x: 253, y: 138, width:515, height:354))
    self.physicsBody = boundary
    self.physicsBody?.friction = 0 
    boundary.contactTestBitMask = ColliderType.object
    boundary.categoryBitMask = ColliderType.boundary
    boundary.collisionBitMask = ColliderType.object

    let push = CGVectorMake(10, 10)
    object.physicsBody?.applyImpulse(push)
}


func didBeginContact(contact:SKPhysicsContact) {
    print("We have Contact")

    gameOver = true
    self.speed = 0
    }
 }

Hope this helps

Upvotes: 2

Mikhail Zoline
Mikhail Zoline

Reputation: 1

You must be sure that the two collision shapes are in the same collision space, if they are not in the same space, then collision detection algorithm will be never invoked. About the comment of Seed12, the two objects do not need to be a rigid body (physicsBody) to be checked for the presence of collisions between them.

Upvotes: 0

Related Questions