ゲームのState管理を簡単にするiOS 9 GameplayKitのクラスとは:iOS SDKとSwiftで始めるゲーム作成入門(5)(2/4 ページ)
iPhoneゲームをSwift言語で作成してみたいという初心者向けにiOSのゲームフレームワークを使った作り方を一から解説する入門連載。今回は、GoFデザインパターンの1つである「Stateパターン」やiOS 9から登場した「GKStateMachine」クラスを取り入れることで、今後の開発に役立つ知見を共有します。
敵は1回の攻撃で倒せないようにする
前項でキャラクターの動きがタワーディフェンスに近づいてきました。次は敵が何回も攻撃しないと倒せないようにします。
敵に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.
関連記事
- 開発者向けiOS 9、WatchOS 2、Swift 2、Xcode 7の新機能と新しいApple Developer Programの参考情報まとめ
iOS 9、WatchOS 2、Swift 2、Xcode 7の新機能や、Apple Developer Programについて、その概要とアップルが公開している参考情報をまとめて紹介します。 - Apple WatchやiPhoneのアプリを作ろう! Playgroundで学ぶSwiftの基礎―変数、定数、型、演算
本連載では、これからプログラミングやiPhoneアプリ開発を始めてみたい方を対象に、開発に必要な知識を基礎から解説していきます。今回は、Swiftの変数、定数、型、演算などについてサンプルプログラムを交えて解説します。 - iOSアプリ開発でObjective-CからSwiftに移行するための手順、注意点まとめ〜言語仕様の違いは? 連携時の呼び出し方は?
開発生産性や品質を向上させたいiOSアプリ開発者のためにObjective-CからSwiftへ移行するメリットや手順、注意点など勘所をまとめて紹介します。