SwiftyJD
SwiftyJD

Reputation: 5441

Spritekit- DidBeginContact not being called

I noticed this issue has happened to a lot of people. I made sure to have the self.physicsWorld.contactDelegate = self in the didMove function but it still doesn't work. Here is my code:

class PoolTableScene: SKScene, SKPhysicsContactDelegate {

  struct PhysicsCatagory {

    static let None : UInt32 = 0 //0
    static let OrangeBall : UInt32 = 0b1 //1
    static let BlueBall : UInt32 = 0b10 //2
    static let PokeBall : UInt32 = 0b100 //3
    static let Border : UInt32 = 0b1000 //4
    static let All : UInt32 = UInt32.max

  }


  let ballPoke = SKSpriteNode(imageNamed:"pokeBall")
  let ballBlue = SKSpriteNode(imageNamed:"blueBall")
  let ballOrange = SKSpriteNode(imageNamed: "orangeBall")
  //var lastTouch: CGPoint? = nil


  override func didMove(to view: SKView) {

    self.physicsWorld.contactDelegate = self

    self.physicsWorld.gravity = CGVector(dx: 0, dy: -9.8)

    //used to set gravity


    //creates body for sprite that will lock the objects to a specific area
    let sceneBody = SKPhysicsBody(edgeLoopFrom: self.frame)
    sceneBody.friction = 0 //This will make the ball bounce naturally off the edges of the scenBody
    self.physicsBody = sceneBody // make physics only affect whats in sceneBody - NEED PHYSICS BODY UNLESS IT WON'T BE AFFECTED BY PHYSICS
    self.physicsBody?.categoryBitMask = PhysicsCatagory.Border
    self.physicsBody?.collisionBitMask = PhysicsCatagory.BlueBall | PhysicsCatagory.OrangeBall | PhysicsCatagory.PokeBall
    self.physicsBody?.contactTestBitMask = PhysicsCatagory.None

    ballPoke.name = "ballPoke"
    ballPoke.size = CGSize(width: 50, height: 50)
    ballPoke.anchorPoint = CGPoint(x:0.5, y:0.5)
    ballPoke.position = CGPoint(x: self.frame.size.width*0.25, y:self.frame.size.height/2)
    ballPoke.zPosition = 100
    ballPoke.physicsBody = SKPhysicsBody(circleOfRadius: 25)//need this so the ball can be affected by physics
    ballPoke.physicsBody?.affectedByGravity = true //ball will be affected by gravity determined by the scene's physics
    ballPoke.physicsBody?.restitution = 1 // sets bounciness of ball
    ballPoke.physicsBody?.linearDamping = 0 //used to set how air resistence will affect ball
    ballPoke.physicsBody?.categoryBitMask = PhysicsCatagory.PokeBall
    ballPoke.physicsBody?.collisionBitMask = PhysicsCatagory.BlueBall | PhysicsCatagory.Border
    ballPoke.physicsBody?.contactTestBitMask = PhysicsCatagory.OrangeBall

    self.addChild(ballPoke)


    ballBlue.name = "ballBlue"
    ballBlue.size = CGSize(width: 50, height: 50)
    ballBlue.anchorPoint = CGPoint(x:0.5, y:0.5)
    ballBlue.position = CGPoint(x: self.frame.size.width*0.50, y:self.frame.size.height/3)
    ballBlue.zPosition = 100
    ballBlue.physicsBody = SKPhysicsBody(circleOfRadius: 25)//need this so the ball can be affected by physics
    ballBlue.physicsBody?.affectedByGravity = true //ball will be affected by gravity determined by the scene's physics
    ballBlue.physicsBody?.restitution = 1 // sets bounciness of ball
    ballBlue.physicsBody?.linearDamping = 0 //used to set how air resistence will affect ball
    ballBlue.physicsBody?.categoryBitMask = PhysicsCatagory.BlueBall
    ballBlue.physicsBody?.collisionBitMask = PhysicsCatagory.OrangeBall | PhysicsCatagory.PokeBall | PhysicsCatagory.Border
    ballBlue.physicsBody?.contactTestBitMask = PhysicsCatagory.None

    self.addChild(ballBlue)

    ballOrange.name = "ballOrange"
    ballOrange.size = CGSize(width: 50, height: 50)
    ballOrange.anchorPoint = CGPoint(x:0.5, y:0.5)
    ballOrange.position = CGPoint(x: self.frame.size.width*0.75, y:self.frame.size.height/2)
    ballOrange.zPosition = 100
    ballOrange.physicsBody = SKPhysicsBody(circleOfRadius: 25)//need this so the ball can be affected by physics
    ballOrange.physicsBody?.affectedByGravity = true //ball will be affected by gravity determined by the scene's physics
    ballOrange.physicsBody?.restitution = 1 // sets bounciness of ball
    ballOrange.physicsBody?.linearDamping = 0 //used to set how air resistence will affect ball
    ballOrange.physicsBody?.categoryBitMask = PhysicsCatagory.OrangeBall
    ballOrange.physicsBody?.collisionBitMask = PhysicsCatagory.BlueBall | PhysicsCatagory.Border
    ballOrange.physicsBody?.contactTestBitMask = PhysicsCatagory.PokeBall

    self.addChild(ballOrange)

  }

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

    //Finds the position where user touches screen
    for touch: AnyObject in touches {

      let positionOfTouch = touch.location(in: self)

      //drags ball to where user touches screen
      let dragBallAction = SKAction.move(to: CGPoint(x: positionOfTouch.x, y: positionOfTouch.y), duration: 0.5)
      ballOrange.run(dragBallAction)

    }

  }


  func didBeginContact(contact: SKPhysicsContact) {

    print("contact")

    var contactBody1: SKPhysicsBody
    var contactBody2: SKPhysicsBody

    if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {

      contactBody1 = contact.bodyA
      contactBody2 = contact.bodyB
    }
    else// else almost never gets called but still add it to function

    {
      contactBody1 = contact.bodyB
      contactBody2 = contact.bodyA
    }

    //this uses the catagories set up in above struct (1 = Square, 2 = Ball)
    if ((contactBody1.categoryBitMask == 1) && (contactBody2.categoryBitMask == 3)) {

      //if the ball contact the square, remove the ball
      contactBody2.node!.removeFromParent()


    }


  }

}

Upvotes: 1

Views: 312

Answers (3)

Steve Ives
Steve Ives

Reputation: 8134

Read my answer on this question SpriteKit - Making certain SpriteNodes NOT collide without disabling their physics bodies which describes the difference between collisions and contacts.

Also try implementing my checkPhysics() function (source is in the same answer) which will analyse your scene and list which nodes collide with which other nodes and also which nodes notify when contacting other nodes.

The output will be something like this for a physicsDemo I have with 4 SKSPriteNodes called shape_blueSquare, shape_redCircle, shape_purpleSquare, shape_greenRect & shape_yellowTriangle and a border around the screen called "Screen_edge".

Optional("shape_blueSquare") collides with Optional("Screen_edge")
Optional("shape_blueSquare") collides with Optional("shape_redCircle")
Optional("shape_blueSquare") collides with Optional("shape_purpleSquare")
Optional("shape_blueSquare") collides with Optional("shape_greenRect")
Optional("shape_redCircle") collides with Optional("Screen_edge")
Optional("shape_redCircle") collides with Optional("shape_blueSquare")
Optional("shape_redCircle") notifies when contacting Optional("shape_purpleSquare")
Optional("shape_redCircle") collides with Optional("shape_greenRect")
Optional("shape_redCircle") notifies when contacting Optional("shape_greenRect")
Optional("shape_purpleSquare") collides with Optional("Screen_edge")
Optional("shape_purpleSquare") collides with Optional("shape_greenRect")
Category for Optional("shape_greenRect") does not appear to be set correctly as 4294967295
ptional("shape_greenRect") collides with Optional("Screen_edge")
Optional("shape_yellowTriangle") collides with Optional("Screen_edge")
Optional("shape_yellowTriangle") notifies when contacting Optional("shape_redCircle")
Optional("shape_yellowTriangle") collides with Optional("shape_greenRect")
Optional("shape_yellowTriangle") notifies when contacting Optional("shape_greenRect")

Upvotes: 1

Chris Hutchison
Chris Hutchison

Reputation: 611

the property that detects collision is contact test bit mask that is why its just passing through i think you have collision bit mask and contact test bit mask confused with each other

contact test is what detects contact while collision bit mask allows bodies to pass through each other

Upvotes: 0

Cyril
Cyril

Reputation: 2818

I had that same problem and because I'm not too familiar with how ContactA and ContactB works, I gave each object a name and check if those two objects collide like so.

func didMoveToView(view: SKView) {

       objectA = self.childNodeWithName("ObjectA") as! SKSpriteNode!
       objectB = self.childNodeWithName("ObjectB") as! SKSpriteNode!
}

 func didBeginContact(contact: SKPhysicsContact) {

        let contactA: SKPhysicsBody = contact.bodyA
        let contactB: SKPhysicsBody = contact.bodyB

        let nodeA = contactA.node as! SKSpriteNode
        let nodeB = contactB.node as! SKSpriteNode

        if nodeA.name == "ObjectA" && nodeB.name == "ObjectB" {

               //do something
        }

    }

Upvotes: 1

Related Questions