Search code examples
swiftsprite-kitcollision-detectionskphysicsbodysknode

How can I require two collisions on one of my nodes before removing it from screen?


I have a collision based game with missiles and bombs. Everything works perfect right now with 1 collision and it removes the node from screen.

Although I want to be able to make bomb1 of my "bombs" harder to destroy so I would like to require it being hit twice. How can I do this?

Here are the bombs

func enemies() {

    let bomb1 = SKSpriteNode(imageNamed: "Bomb1")
    let bomb2 = SKSpriteNode(imageNamed: "bomb2")
    let bomb3 = SKSpriteNode(imageNamed: "Bomb3")
    let enemy = [bomb1, bomb2, bomb3]

    // Enemy Physics
    for bomb in enemy {
        bomb1.size = CGSize(width: 55, height: 55)
        bomb2.size = CGSize(width: 55, height: 70)
        bomb3.size = CGSize(width: 30, height: 30)
        bomb.physicsBody = SKPhysicsBody(circleOfRadius: bomb.size.width / 4)
        bomb.physicsBody?.categoryBitMask = PhysicsCategory.enemy
        bomb.physicsBody?.collisionBitMask = PhysicsCategory.missile | PhysicsCategory.airDefense
        bomb.physicsBody?.contactTestBitMask = PhysicsCategory.missile | PhysicsCategory.airDefense
        bomb.physicsBody?.affectedByGravity = false 
        bomb.physicsBody?.dynamic = true
        bomb1.name = "enemy1"
        bomb2.name = "enemy2"
        bomb3.name = "enemy3"

    }

Here is the function thats called when the bomb hits the missile.

 func collisionWithMissile(enemy : SKSpriteNode, missile : SKSpriteNode) {
    enemy.physicsBody?.dynamic = true
    enemy.physicsBody?.affectedByGravity = true
    missile.physicsBody?.affectedByGravity = true

    enemy.physicsBody?.mass = 10.0
    missile.physicsBody?.mass = 5.0

    enemy.removeAllActions()
    missile.removeAllActions()

    enemy.removeFromParent()
    missile.removeFromParent()

    enemy.physicsBody?.contactTestBitMask = 0
    enemy.physicsBody?.collisionBitMask = 0
    enemy.name = nil

    score++
    scoreLbl.text = "\(score)"

}

This may help with the error Im getting

func didBeginContact(contact: SKPhysicsContact) {
    if contact.bodyA.node != nil && contact.bodyB.node != nil {
        let firstBody = contact.bodyA.node as! Bomb
        let secondBody = contact.bodyB.node as! SKSpriteNode

        // Bomb1 **********
        if ((firstBody.name == "enemy1") && (secondBody.name == "missile")) {

            collisionWithMissile(firstBody, missile: secondBody)
            atomicExplosion(contact.bodyA.node!.position)
            missileExplosion(contact.bodyB.node!.position)

        }

Solution

  • You can subclass SKSpriteNode for your bombs and add a collision counter to this class. Inside your collisionWithMissile func you check the value of this counter and remove the bomb if a given value is reached otherwise you increase the counter.

    Your subclass can look like this

    class Bomb: SKSpriteNode {
      var hitCount: Int
    
      init(imageNamed: String, hitCount: Int) {
        self.hitCount = hitCount
        let texture = SKTexture(imageNamed: imageNamed)
        super.init(texture: texture, color: UIColor.clearColor(), size: texture.size())
      }
    
      required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
      }
    }
    

    The init method has hitCount as a parameter, so you can create easily Bombs with different strength. Your collisionWithMissile method could be like this. Just fill the if-else parts with your needed code.

    func collisionWithMissile(enemy : Bomb, missile : SKSpriteNode) {
      if enemy.hitCount <= 0 {
          enemy.removeFromParent()
      } else {
          enemy.hitCount -= 1
      }
    }