Reputation: 451
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
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