1
votes

I've created an asteroids type game in swift where I have multiple types of enemies. I currently have one enemy which is destroyed with one hit. I am trying to create a second enemy that is destroyed with two hits.

I have assigned a variable "var enemyTwoHealth = 0" at the class level, then inside my function where I create the enemy, physicsbody, pathing, etc for it I have added "self.enemyTwoHealth = 2". Inside of my "didBegin(_ contact: SKPhysicsContact)" when the missle collides with the enemy I decrement "enemyTwoHealth -= 1" and check for "if enemyTwoHealth <= 0 { body2.node?.removeFromParent()}".

The issue that I have is that when a second enemy two spawns on the screen before killing the first it resets all of their health to 2 again. (E.g. EnemyType2 spawns, it has 2 health, I hit it once, now it has one health; a second EnemyType2 spawns, both now have 2 health.)

How can I assign the health variable to each individual enemy?

(There is a lot of code, so I tried to just include the relevant code)

class GameScene: SKScene, SKPhysicsContactDelegate {

     var enemyTwoHealth = 0

     func didBegin(_ contact: SKPhysicsContact) {

          if body1.categoryBitMask == PhysicsCategories.Missle && 
          body2.categoryBitMask == PhysicsCategories.EnemyTwo {

               if enemyTwoLives <= 0 {
                    body2.node?.removeFromParent()
                    addScore()
               }
               else {
                    enemyTwoHealth -= 1
               }

               body1.node?.removeFromParent()
          }

      }

     func spawnEnemyTwo() {
          self.enemyTwoLives = 2
     }

}
1
Your "rocks" should be a subclass of SKSpriteNode - Then you can add a property for the "health" to each instance of the rock and track it that way.Paulw11
Give each node copy the userData property.El Tomato

1 Answers

2
votes

You have at least four options, 2 of which the comments have suggested.

Since this is an asteroids game, I would not make "health" at all What I would do in your case is have a child heirarchy of SKSpriteNodes.

Your heirarchy should look like this:

Biggest asteroid - zPosition = 5  
|  
-- Bigger asteroid - zPosition = 4  
|  |  
|  -- Big asteroid - zPosition = 3  
|  |  |  
|  |  -- Small asteroid - zPosition = 2  
|  |  |  |  
|  |  |  -- Smaller asteroid - zPosition = 1  
|  |  |  |  |  
|  |  |  |  -- Smallest asteroid - zPosition = 0  
|  |  |  |  |  
|  |  |  |  -- Smallest asteroid - zPosition = 0  
|  |  |  |  
|  |  |  -- Smaller asteroid - zPosition = 1  
|  |  |  |  |  
|  |  |  |  -- Smallest asteroid - zPosition = 0  
|  |  |  |  |  
|  |  |  |  -- Smallest asteroid - zPosition = 0  
|  |  |  
|  |  -- Small asteroid - zPosition = 2  
|  |  |  |  
|  |  |  -- Smaller asteroid - zPosition = 1  
|  |  |  |  |  
|  |  |  |  -- Smallest asteroid - zPosition = 0  
|  |  |  |  |  
|  |  |  |  -- Smallest asteroid - zPosition = 0  
|  |  |  |  
|  |  |  -- Smaller asteroid - zPosition = 1  
|  |  |  |  |  
|  |  |  |  -- Smallest asteroid - zPosition = 0  
|  |  |  |  |  
|  |  |  |  -- Smallest asteroid - zPosition = 0  
|  |  
|  -- Big asteroid - zPosition = 3  
|  |  |  
|  |  -- Small asteroid - zPosition = 2  
|  |  |  |  
|  |  |  -- Smaller asteroid - zPosition = 1  
|  |  |  |  |  
|  |  |  |  -- Smallest asteroid - zPosition = 0  
|  |  |  |  |  
|  |  |  |  -- Smallest asteroid - zPosition = 0  
|  |  |  |  
|  |  |  -- Smaller asteroid - zPosition = 1  
|  |  |  |  |  
|  |  |  |  -- Smallest asteroid - zPosition = 0  
|  |  |  |  |  
|  |  |  |  -- Smallest asteroid - zPosition = 0  
|  |  |  
|  |  -- Small asteroid - zPosition = 2  
|  |  |  |  
|  |  |  -- Smaller asteroid - zPosition = 1  
|  |  |  |  |  
|  |  |  |  -- Smallest asteroid - zPosition = 0  
|  |  |  |  |  
|  |  |  |  -- Smallest asteroid - zPosition = 0  
|  |  |  |  
|  |  |  -- Smaller asteroid - zPosition = 1  
|  |  |  |  |  
|  |  |  |  -- Smallest asteroid - zPosition = 0  
|  |  |  |  |  
|  |  |  |  -- Smallest asteroid - zPosition = 0  
|  |  
|  -- Big asteroid - zPosition = 3  
|  |  |  
|  |  -- Small asteroid - zPosition = 2  
|  |  |  |  
|  |  |  -- Smaller asteroid - zPosition = 1  
|  |  |  |  |  
|  |  |  |  -- Smallest asteroid - zPosition = 0  
|  |  |  |  |  
|  |  |  |  -- Smallest asteroid - zPosition = 0  
|  |  |  |  
|  |  |  -- Smaller asteroid - zPosition = 1  
|  |  |  |  |  
|  |  |  |  -- Smallest asteroid - zPosition = 0  
|  |  |  |  |  
|  |  |  |  -- Smallest asteroid - zPosition = 0  
|  |  |  
|  |  -- Small asteroid - zPosition = 2  
|  |  |  |  
|  |  |  -- Smaller asteroid - zPosition = 1  
|  |  |  |  |  
|  |  |  |  -- Smallest asteroid - zPosition = 0  
|  |  |  |  |  
|  |  |  |  -- Smallest asteroid - zPosition = 0  
|  |  |  |  
|  |  |  -- Smaller asteroid - zPosition = 1  
|  |  |  |  |  
|  |  |  |  -- Smallest asteroid - zPosition = 0  
|  |  |  |  |  
|  |  |  |  -- Smallest asteroid - zPosition = 0  

All of these asteroids will be at position (0,0) with the exception of the node in the highest zPosition.

Then, as your game plays, when your largest asteroid gets shot, you have a method that takes its immediate children (as in not grandchildren) and take them off of the asteroid and onto the scene. You then apply your code that causes them to project in different directions based on how the bullet came in.

Each time an asteroid is shot, you move the children to the scene and remove the parent.

Eventually you will get down to the tiniest asteroid that has no children, thus destroying all of the asteroid.

This method will be a little expensive in RAM, but you do not have to worry about losing CPU cycles constantly creating new objects.

Another thing you could do it sub class SKSpriteNode to give each class.

class Rocks : SKSpriteNode{
    var health = 0
    convenience init(health:Int){
        self.init(imageNamed:"rock")
        self.health = health
    }
}

Yet another thing you could do is add the health to the userData:

let userData = rock.userData ?? [:]()
userData["health"] = 2
rock.userData = userData

....

 if let health = rock.userData["health"]{
     health -= 1
     rock.userData["health"] = 1
 }

Finally, you could use GamePlayKit and add a health component:

 class HealthComponent : GKComponent{
     var health = 2
 }

 ....
 var healthComponent = new HealthComponent()
 rock.entity.addComponent(healthComponent)

 ....
 if let healthComponent = rock.entity.component(ofType:HealthComponent){
     healthComponent.health -= 1
 }