Niall Kehoe
Niall Kehoe

Reputation: 379

Not detecting Collisions properly in Swift

I'm making a game that spawns cubes from the top of the screen, when they are touched they disappear. I'm setting an objects position to the point touched by the user. It runs the function DidBeginContact , but it doesn't seem to detect my two views:

func didBeginContact(contact: SKPhysicsContact) {
        var firstBody : SKPhysicsBody = contact.bodyA
        var secondBody : SKPhysicsBody = contact.bodyB

        print("didbegincontact")
        if ((firstBody.categoryBitMask == PhysicsCategory.RedSquare) && (secondBody.categoryBitMask == PhysicsCategory.touchlocation)) || ((firstBody.categoryBitMask == PhysicsCategory.touchlocation) && (secondBody.categoryBitMask == PhysicsCategory.RedSquare)) {
            collisionwithredsquare(firstBody.node as! SKSpriteNode)
            print("Done")

        }
    }

It's printing "didBegincontact" so I know that the function is working but the if statement is not.

Here's all the code:

import SpriteKit

struct PhysicsCategory {
    static let RedSquare : UInt32 = 1
    static let touchlocation : UInt32 = 2
    static let BlueSquare : UInt32 = 3
}

class GameScene: SKScene, SKPhysicsContactDelegate {

     var animator : UIDynamicAnimator?
     let blueSquare = SKSpriteNode()
     let redSquare = SKSpriteNode()
    var scorenumber = 0
    var ground = SKSpriteNode()
    var touchpoint = SKSpriteNode()

    override func didMoveToView(view: SKView) {
        /* Setup your scene here */
        physicsWorld.contactDelegate = self
        physicsWorld.gravity = CGVector(dx: 1.0, dy: -9.0)


       /* let borderBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
        // 2. Set the friction of that physicsBody to 0
        borderBody.friction = 0
        // 3. Set physicsBody of scene to borderBody
        self.physicsBody = borderBody */


        touchpoint = SKSpriteNode(imageNamed:"Spaceship")
        touchpoint.physicsBody?.categoryBitMask = PhysicsCategory.touchlocation
        touchpoint.physicsBody?.contactTestBitMask = PhysicsCategory.RedSquare
        touchpoint.physicsBody?.affectedByGravity = false

        touchpoint.xScale = 0.5
        touchpoint.yScale = 0.5


       self.addChild(touchpoint)

        let width = UInt32(self.frame.size.width)

        let X = arc4random() % width


        ground = SKSpriteNode(imageNamed: "Ground")
        ground.setScale(1.0)
        ground.position = CGPoint(x: self.frame.width / 2, y: 5)
        ground.physicsBody = SKPhysicsBody(rectangleOfSize: ground.size)
        ground.physicsBody?.affectedByGravity = false
        ground.physicsBody?.dynamic = false

        ground.zPosition = 3

        self.addChild(ground)


        //INizialize
        animator = UIDynamicAnimator(referenceView: self.view!)

        //Add Gravity

        //animator?.addBehavior(gravity, sprite)


        var test = arc4random() % 90

        blueSquare.size = CGSize(width: 100, height: 100)
        blueSquare.position = CGPoint(x: CGFloat(X), y: 1000)
                blueSquare.zRotation = 34
        blueSquare.name = "bluecube"
        blueSquare.physicsBody = SKPhysicsBody(circleOfRadius: 20)
        blueSquare.physicsBody?.affectedByGravity = true
        blueSquare.physicsBody?.dynamic = false
        blueSquare.color = SKColor.blueColor()
       // BlueSquare.physicsBody?.velocity = CGVectorMake(0, 0)

        //BlueSquare.physicsBody?.applyImpulse(CGVectorMake(0, -90))
        self.addChild(blueSquare)

        let X2 = arc4random() % width
        redSquare.size = CGSize(width: 100, height: 100)
        redSquare.position = CGPoint(x: CGFloat(X2), y: 1000)
        redSquare.name = "redcube"
        redSquare.physicsBody = SKPhysicsBody(circleOfRadius: 20)
        redSquare.physicsBody?.affectedByGravity = true
        redSquare.physicsBody?.dynamic = true
        redSquare.hidden = false
        redSquare.physicsBody?.categoryBitMask = PhysicsCategory.RedSquare
        redSquare.physicsBody?.contactTestBitMask = PhysicsCategory.touchlocation

        redSquare.color = SKColor.redColor()

        self.addChild(redSquare)




        let timerAction1 = SKAction.waitForDuration(0.5)
        let timerAction2 = SKAction.runBlock(spawning1)
        let timerSequence = SKAction.sequence([timerAction1, timerAction2])
        runAction(SKAction.repeatActionForever(timerSequence))

    }

    func didBeginContact(contact: SKPhysicsContact) {
        var firstBody : SKPhysicsBody = contact.bodyA
        var secondBody : SKPhysicsBody = contact.bodyB

        print("didbegincontact")
        if ((firstBody.categoryBitMask == PhysicsCategory.RedSquare) && (secondBody.categoryBitMask == PhysicsCategory.touchlocation)) || ((firstBody.categoryBitMask == PhysicsCategory.touchlocation) && (secondBody.categoryBitMask == PhysicsCategory.RedSquare)) {
            collisionwithredsquare(firstBody.node as! SKSpriteNode)
            print("Done")

        }
    }


    func collisionwithredsquare(redsquare: SKSpriteNode) {
        print("Hello")
    }


    func spawning1() {


    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
       /* Called when a touch begins */

        for touch in touches {
            let location = touch.locationInNode(self)

            touchpoint.position = location

        }
    }

    func score () {
        scorenumber++
        print(scorenumber)
    }

    override func update(currentTime: CFTimeInterval) {
        /* Called before each frame is rendered */
       if CGRectIntersectsRect(redSquare.frame, ground.frame) {
        redSquare.position = CGPoint(x: redSquare.position.x, y: redSquare.position.y + 10)
        }
    }
}

Thanks in advance, Niall

Upvotes: 0

Views: 81

Answers (1)

crashoverride777
crashoverride777

Reputation: 10674

You collision categories are wrong. It should be this because you are dealing with 32 bit integers.

  struct PhysicsCategory {
      static let RedSquare: UInt32 = 0x1 << 1
      static let touchlocation : UInt32 = 0x1 << 2
      static let BlueSquare : UInt32 = 0x1 << 3
  }

If you use your way you would have to write it like this

  struct PhysicsCategory {
      static let RedSquare: UInt32 = 1
      static let touchlocation : UInt32 = 2
      static let BlueSquare : UInt32 = 4
      static let somethingElse : UInt32 = 8
  }

which is more confusing because you cannot just increment the last number by 1.

Than change your collision code to this. This way you dont have to check for both bodies in the if statement.

    /// Did Begin Contact
func didBeginContact(contact: SKPhysicsContact) {
    var firstBody: SKPhysicsBody
    var secondBody: SKPhysicsBody

    if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
        firstBody = contact.bodyA
        secondBody = contact.bodyB
    } else {
        firstBody = contact.bodyB
        secondBody = contact.bodyA
    }

  if (firstBody.categoryBitMask == PhysicsCategory.RedSquare) && (secondBody.categoryBitMask == PhysicsCategory.touchlocation) {
        collisionwithredsquare(firstBody.node) // I aim pretty sure you dont need to cast as SKSpriteNod, because the body its already a SKNode.
        print("Done")

    }
  }

Also on the touchLocaiton sprite you forgot to give it a physics body.

  touchpoint.pysicsBody = SKPhysicsBody(..) // FORGOT THIS LINE
  touchpoint.physicsBody?.categoryBitMask = PhysicsCategory.touchlocation
    touchpoint.physicsBody?.contactTestBitMask = PhysicsCategory.RedSquare
    touchpoint.physicsBody?.affectedByGravity = false

This should work now if you are already getting the contact method to be called. Let me know how it goes.

Upvotes: 1

Related Questions