SpriteKit Game Development Challenge 2: another solution to the zombie problem
This challenge aims to set botnets to invincible when they encounter an enemy. The specific requirements are as follows:
1 You shoshould create a variable property to track whether or not the zombie is invincible.
2 If the zombie is invincible, you shouldn't bother enumerating the scene's cat ladies.
3 If the zombie collides with a cat lady, don't remove the cat lady from the scene. instead, set the zombie as invincible. next, run a sequence of actions that first makes the zombie blink 10 times over three seconds, then runs the block of code described below.
4 Theblockofcodeshouldsethiddentofalseonthezombie, makingsurehe's visible at the end no matter what, and set the zombie as no longer invincible.
The implementation in the book is as follows:
func zombieHitEnemy(enemy: SKSpriteNode) { enemy.removeFromParent() runAction(enemyCollisionSound) invincible = true let blinkTimes = 10.0 let duration = 3.0 let blinkAction = SKAction.customActionWithDuration(duration) { node, elapsedTime in let slice = duration / blinkTimes let remainder = Double(elapsedTime) % slice node.hidden = remainder > slice / 2 } let setHidden = SKAction.runBlock() { self.zombie.hidden = false self.invincible = false } zombie.runAction(SKAction.sequence([blinkAction, setHidden])) }func checkCollisions(){ if invincible { return } var hitEnemies: [SKSpriteNode] = [] enumerateChildNodesWithName("enemy") { node, _ in let enemy = node as! SKSpriteNode if CGRectIntersectsRect( CGRectInset(node.frame, 20, 20), self.zombie.frame) { hitEnemies.append(enemy) } } for enemy in hitEnemies { zombieHitEnemy(enemy) }}
I think there are several points that can be improved:
BlinkAction needs to be created every time, which is a waste of resources. You can use the shared Action bot to become invincible. If the enemy appears fast enough, it will still delete other enemies.
I set blinkAction to the computing attribute of lazy, and then directly process the collision with the enemy in the subnode enumeration of the scenario, and then directly jump out of the traversal, this ensures that only the enemies of the first collision will be deleted:
lazy var blinkAction:SKAction = { let blinkTimes = 10.0 let duration = 3.0 let blinkAction = SKAction.customActionWithDuration(duration){node,elapsedTime in let slice = duration/blinkTimes let remainder = Double(elapsedTime) % slice node.hidden = remainder > slice / 2 } return blinkAction }()func checkCollisions(){ if zombieInvincible{ return } var hitEnemies:[SKSpriteNode] = [] enumerateChildNodesWithName("enemy"){node,stop in let enemy = node as! SKSpriteNode if CGRectIntersectsRect(CGRectInset(enemy.frame, 20, 20), self.zombie.frame){ hitEnemies.append(enemy) self.zombieInvincible = true let seq = SKAction.sequence([self.blinkAction,SKAction.runBlock(){ self.zombie.hidden = false self.zombieInvincible = false }]) self.zombie.runAction(seq) stop.memory = true } } for enemy in hitEnemies{ zombieHitEnemy(enemy) } }