前項でキャラクターの動きがタワーディフェンスに近づいてきました。次は敵が何回も攻撃しないと倒せないようにします。
敵にlifeプロパティーを持たせるためにEnemyクラスを作成します。「File」→「New」→「File」からEnemyクラスを作成してください。親クラスにはSKSpriteNodeを指定します。
Enemyクラスを作成したら下のようにlifeプロパティーを付けてください。lifeはひとまず3に設定します。
import UIKit import SpriteKit class Enemy: SKSpriteNode { var life = 3 }
次にEnemyList.swiftでSKSpriteNodeを指定している部分をEnemyに置き換えます。
class EnemyList { private var enemies = [Enemy]() func enemiesCloseToPoint(point: CGPoint, distance: Double) -> [Enemy] { // 略... } func appendEnemy(enemy: Enemy) { enemies.append(enemy) } // 略... }
同時にGameScene.swiftの敵の初期化処理も書き換えます。今まで「SKSpriteNode(imageNamed: "Enemy")」としていたところを「Enemy(imageNamed: "Enemy")」に置き換えます。
class GameScene: SKScene, SKPhysicsContactDelegate { // 略... func createEnemy() { // 略... let enemy = Enemy(imageNamed: "Enemy") // 略... } // 略... }
最後にGameScene.swiftのupdateメソッドも修正します。今は自機が敵を攻撃した瞬間に敵が消滅しているので、それを敵ライフが0になったら敵が消えるように変えます。
class GameScene: SKScene, SKPhysicsContactDelegate { // 略... override func update(currentTime: NSTimeInterval) { enemyList.enemiesCloseToPoint(char.frame.origin, distance: 50).forEach { $0.life -= 1 if $0.life <= 0 { $0.physicsBody?.node?.removeFromParent() $0.physicsBody?.node?.removeAllActions() if enemyList.isAllEnemyRemoved() { state = .GameClear let myLabel = SKLabelNode(fontNamed: "HiraginoSans-W6") myLabel.text = "ゲームクリア" myLabel.fontSize = 45 myLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame) - 20) addChild(myLabel) } } } } // 略... }
前項の修正で敵のlifeを設定してきました。敵は3回まで攻撃に耐えれるようになったのですが、今は自機がupdateメソッドが呼ばれるたびに攻撃するので、一瞬で敵が倒されてしまいます。そこで自機が一定の間隔を空けて攻撃するよう修正してゲーム性を高めようと思います。
具体的な方法として、自機に攻撃可能状態・待機状態の2種類の状態を作ります。そして1度攻撃したら待機状態になり、一定期間が過ぎたら攻撃可能状態に戻るようにします。
自機に現在の状態を持たせるために、自機を表すCharクラスを作成します。Enemyを作ったときと同様にChar.swiftを作成して下のように置き換えます。
import UIKit import SpriteKit class Char: SKSpriteNode { enum State { case Attack case Wait } var state: State = .Attack }
GameScene.swiftの中のcharの初期化処理も少し修正します。
class GameScene: SKScene, SKPhysicsContactDelegate { // 略... // let char = SKSpriteNode(imageNamed: "Char") let char = Char(imageNamed: "Char") // 略... }
次に攻撃可能状態と待機状態を切り替える処理を実装します。GameScene.swiftのupdateを以下のように書き換えてください。
class GameScene: SKScene, SKPhysicsContactDelegate { // 略... override func update(currentTime: NSTimeInterval) { // stateが.Attackのときだけ攻撃する if char.state == .Attack { enemyList.enemiesCloseToPoint(char.frame.origin, distance: 50).forEach { $0.life -= 1 if $0.life <= 0 { $0.physicsBody?.node?.removeFromParent() $0.physicsBody?.node?.removeAllActions() if enemyList.isAllEnemyRemoved() { state = .GameClear let myLabel = SKLabelNode(fontNamed: "HiraginoSans-W6") myLabel.text = "ゲームクリア" myLabel.fontSize = 45 myLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame) - 20) addChild(myLabel) } } // 敵に攻撃したらstateを.Waitにする char.state = .Wait // 0.2秒経過したらstateを.Attackに戻す performSelector("changeCharStateToAttack", withObject: nil, afterDelay: 0.2) } } } func changeCharStateToAttack() { char.state = .Attack } // 略... }
以上で一定間隔ごとに攻撃する処理の実装が終わりました。次ページではStateパターンを使って今実装したコードに拡張性を持たせていきます。
Copyright © ITmedia, Inc. All Rights Reserved.