前項でキャラクターの動きがタワーディフェンスに近づいてきました。次は敵が何回も攻撃しないと倒せないようにします。
敵に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.
Smart & Social 記事ランキング