Alex Merlin
Alex Merlin

Reputation: 451

How to remove a node when hit more than once

I am making a space invader game in which many enemy ships come towards you and you have to shoot at them.

when the player touches the screen, the player ship shoots bullets at the enemy ships.

I got it so that whenever 1 bullet touches an enemy ship it is removed from the parent. But I cannot get it so that 2 bullets are needed to remove the enemy ship from the parent. For some reason the enemy's life resets itself whever another enemy ship is called to the scene. How can I make it so that each enemy ship has its own independent life and that it won't affect other enemy ship's life?

Here is the enemy class:

public class Villain: SKSpriteNode {

var life = 2

init(){

    let texture = SKTexture(imageNamed: "Villain")
    var life = 2
    print("number of lives: ", life)
    super.init(texture: texture, color: SKColor.clear, size: texture.size())
    self.name = "villain"
}

required public init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

Here is the GameScene class in which the Enemy class is called

func VillainRight(){
    let TooMuch = self.size.width
    let point = UInt32(TooMuch)

    let VillainR = Villain()

    VillainR.zPosition = 2
    VillainR.position = CGPoint(x: self.frame.minX,y: CGFloat(arc4random_uniform(point)))

    //This code makes the villain's Zposition point towards the SpaceShip
    let angle = atan2(SpaceShip.position.y - VillainR.position.y, SpaceShip.position.x - VillainR.position.x)
    VillainR.zRotation = angle - CGFloat(M_PI_2)

    let MoveToCenter = SKAction.move(to: CGPoint(x: self.frame.midX, y: self.frame.midY), duration: 15)

    //Physics World
    VillainR.physicsBody = SKPhysicsBody(rectangleOf: VillainR.size)
    VillainR.physicsBody?.categoryBitMask = NumberingPhysics.RightV
    VillainR.physicsBody?.contactTestBitMask = NumberingPhysics.Laser | NumberingPhysics.SpaceShip
    VillainR.physicsBody?.affectedByGravity = false
    VillainR.physicsBody?.isDynamic = true

    VillainR.run(MoveToCenter)
    addChild(VillainR)
}

and here is part of the didBeginContact method:

 //LASERS HIT ENEMY CHECK

    if BodyOne.categoryBitMask == NumberingPhysics.Laser && BodyTwo.categoryBitMask == NumberingPhysics.LeftV{
        run(VillainGone)
        ToNextLevel -= 1

        if BodyTwo.node != nil{
            MakeExplosions(BodyTwo.node!.position)
        }

        BodyTwo.node?.removeFromParent()
        BodyOne.node?.removeFromParent()
    }

    if BodyOne.categoryBitMask == NumberingPhysics.Laser && BodyTwo.categoryBitMask == NumberingPhysics.RightV{

        ToNextLevel -= 1

        if BodyTwo.node != nil{
            MakeExplosions(BodyTwo.node!.position)
        }

        run(VillainGone)
        BodyOne.node?.removeFromParent()
        BodyTwo.node?.removeFromParent()
    }
}

RECAP:

All I want to do is have the enemy ship be removedfromParent once 2 bullets touch it. And the enemy's life be independent from each other (if an enemy ship has 1 life left then it won't reset back to 2 if another enemy ship is called on to the scene).

Upvotes: 1

Views: 73

Answers (1)

Fluidity
Fluidity

Reputation: 3995

Here is a sample solution to your issue (this is a macOS project just replace mouseDown with touchesBegan if you want to convert).

Click the screen to watch the villains health deplete, and when reaches 0 the villain will die and remove from scene:

let category1 = UInt32(1)
let category2 = UInt32(2)


class Villain: SKSpriteNode {

  var lives = 2
  var hitThisFrame = false

  init(color: SKColor, size: CGSize) {
    super.init(texture: nil, color: color, size: size)
    let pb = SKPhysicsBody(rectangleOf: self.size)
    pb.categoryBitMask = category1
    pb.contactTestBitMask = category2
    self.physicsBody = pb
  }

  required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }
}

class Hero: SKSpriteNode {

  init(color: SKColor, size: CGSize) {
    super.init(texture: nil, color: color, size: size)
    let pb = SKPhysicsBody(rectangleOf: self.size)
    pb.categoryBitMask = category2
    pb.contactTestBitMask = category1
    self.physicsBody = pb
  }
  required init?(coder aDecoder: NSCoder) { fatalError() }
}


class GameScene: SKScene, SKPhysicsContactDelegate {

  let villain = Villain(color: .blue,  size: CGSize(width: 50, height: 50))
  let hero    = Hero   (color: .green, size: CGSize(width: 50, height: 50))

  override func didMove(to view: SKView) {
    physicsWorld.contactDelegate = self
    physicsWorld.gravity = CGVector.zero

    hero.position.y -= 100
    addChild(villain)
    addChild(hero)
  }

  func didBegin(_ contact: SKPhysicsContact) {
    let contactedBodies = contact.bodyA.categoryBitMask + contact.bodyB.categoryBitMask

    if contactedBodies == category1 + category2 {

      // Find which one of our contacted nodes is a villain:
      var vil: Villain
      if let foundVil = contact.bodyA.node as? Villain {
        vil = foundVil
      } else if let foundVil = contact.bodyB.node as? Villain {
        vil = foundVil
      } else {
        fatalError("one of the two nodes must be a villain!!")
      }


      if vil.hitThisFrame {
        // Ignore a second contact if already hit this frame:
        return
      } else {
        // Damage villain:
        vil.lives -= 1
        print(" vil lives: \(vil.lives)")
        vil.hitThisFrame = true
        if vil.lives == 0 {
          // Kill villain:
          print("villain is dead!!!")
          vil.physicsBody = nil
          vil.removeFromParent()
        }
      }
    }
  }

  override func didSimulatePhysics() {
    // Reset hero position (so as to not trigger another didBegin()
    hero.position = CGPoint(x: 0, y: -100)
    // Allow villain to be hit again next frame:
    villain.hitThisFrame = false
  }
  override func mouseDown(with event: NSEvent) {
    // Trigger didBegin():
    hero.position = villain.position
  }
}

Upvotes: 1

Related Questions