Sam Trent
Sam Trent

Reputation: 395

How to detect a collision between two objects in an Array (Sprite Kit)

I have an array of Bullets and Enemies objects. I want the game to check each element in the arrays to see whether there was a collision between the two or not. If there was any collision, then damage that enemy and delete the bullet. Right now every time a bullet hits an enemy it decreases the health of ALL the enemies in the array, thus killing them all at once. How can I make it so that it only decreases the health of the enemy which I'm shooting at?

 //This function handles our collision detection
    func didBegin(_ contact: SKPhysicsContact) {
        //print("COLLISIONS!")
        // If contact is with another object
        if contact.bodyA.categoryBitMask == pickupCategory && contact.bodyB.categoryBitMask == playerCategory
        {
            displayText(text: "Picked up Pistol")
            player.setHasPistol(gotPistol: true)
            pistol.removeFromParent()
        }

        //Bullet hits an object
        if contact.bodyA.categoryBitMask == objectCategory && contact.bodyB.categoryBitMask == bulletCategory
        {
            bulletCleanup(killNow: true)
            //print("BULLET HAS HIT THE PIPE!")
        }

        //Do collisions between bullets and enemies...
        for bullet in bulletList
        {
            for enemy in enemyList
            {
                //if the enemy was hit have them take damage.
                if contact.bodyA.categoryBitMask == enemyCategory && contact.bodyB.categoryBitMask == bulletCategory
                {
                    //deletes the bullet after hitting an object
                    bulletCleanup(killNow: true)

                    //apply damage
                    enemy.setHitPoints(setPoints: enemy.getHitPoints() - pistol.getDamage())

                    // print("BULLET HAS HIT THE enemy!!!!")
                }
            }
        }
    }

Upvotes: 1

Views: 684

Answers (1)

Steve Ives
Steve Ives

Reputation: 8134

didBegin(contact:) is called for a single collision between one specific object and another specific object. (actually between physics bodies...)

Your problem is occurring because you are iterating over every bullet and every enemy for a single collision and at each iteration you are testing if the collision was between a bullet and an enemy, which it was, so you are applying the damage to every enemy.

All you need to do is to extract the specific enemy from the SKPhysicsContact object and apply damage to that particular enemy.

Also, I suspect you are missing some contacts because for your contact tests, you are not checking if the bodyA and bodyB physics bodies are reversed i.e.

if contact.bodyA.categoryBitMask == pickupCategory && contact.bodyB.categoryBitMask == playerCategory

bodyA might be player and bodyB might be pickup, so you need to test for this also.

Here is an alternative didBegincontact() you might find helpful (It's Swift2, but that shouldn't be a big problem):

func didBeginContact(contact: SKPhysicsContact) {
    let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask

switch contactMask {

   case pickupCategory  | playerCategory
        displayText(text: "Picked up Pistol")
        player.setHasPistol(gotPistol: true)

       let pistol = (contact.bodyA.categoryBitMask == pickupCategory) ? contact.bodyA.node! : contact.bodyB.node!

        pistol.removeFromParent()

   case objectCategory | bulletCategory
        bulletCleanup(killNow: true)
        //print("BULLET HAS HIT THE PIPE!")

   case enemyCategory| bulletCategory

        //deletes the bullet after hitting an object
        bulletCleanup(killNow: true)

        //apply damage
       let enemy = (contact.bodyA.categoryBitMask == enemyCategory) ? contact.bodyA.node! : contact.bodyB.node!
        enemy.setHitPoints(setPoints: enemy.getHitPoints() - pistol.getDamage())

   default :
       //Some other contact has occurred
       print("Some other contact")
   }
}

I'm not sure how your bulletCleanup() function works - you don't appear to be sending it a specific bullet object so I don't know how it knows which bullet to process. The specific bullet involved in the contact can be obtained in didBegincContact: as follows:

       let bullet = (contact.bodyA.categoryBitMask == bulletCategory) ? contact.bodyA.node! : contact.bodyB.node!

which is a short form of saying "is nodeA's categoryBitMask a bulletCategory? If it is, then set bullet equal to nodeA, otherwise set bullet to nodeB.

Note that if your categories are more complicated (i.e. objects can belong to multiple categories), this won't work as the simple AND tests (enemyCategory| bulletCategory) won't match.

Upvotes: 2

Related Questions