ゲームのState管理を簡単にするiOS 9 GameplayKitのクラスとは:iOS SDKとSwiftで始めるゲーム作成入門(5)(4/4 ページ)
iPhoneゲームをSwift言語で作成してみたいという初心者向けにiOSのゲームフレームワークを使った作り方を一から解説する入門連載。今回は、GoFデザインパターンの1つである「Stateパターン」やiOS 9から登場した「GKStateMachine」クラスを取り入れることで、今後の開発に役立つ知見を共有します。
iOS 9のGKStateMachineを使ってステータス管理を楽にする
ここからはiOS 9から登場したGameplayKitの「GKStateMachine」クラスを利用してState管理を改善します。
GKStateMachineとはStateの管理をしてくれるクラスで、Stateの保持やState変更時のコールバックメソッドを呼び出してくれます。
Char.swiftをGKStateMachineを使った形に修正します。
class Char: SKSpriteNode {
// stateMachineプロパティーがstateを保持する
lazy var stateMachine: GKStateMachine = {
let stateMachine = GKStateMachine(states: [
AttackState(char: self),
StayState(char: self)
])
stateMachine.enterState(AttackState)
return stateMachine
}()
// GKStateMachineが保持できるようにCharStateはGKStateのサブクラスにする
class CharState: GKState {
weak var char: Char?
var power: Int {
return char?.power ?? 0
}
init(char: Char?) {
self.char = char
}
func enableToAttack() -> Bool {
return false
}
}
class AttackState: CharState {
override func enableToAttack() -> Bool {
return true
}
}
class AngryState: CharState {
var enteredDate = NSDate()
override var power: Int {
return char?.power ?? 0
}
override func enableToAttack() -> Bool {
return true
}
override func didEnterWithPreviousState(previousState: GKState?) {
enteredDate = NSDate()
}
override func updateWithDeltaTime(seconds: NSTimeInterval) {
if NSDate().timeIntervalSinceDate(enteredDate) > 10 {
// stateの変更はenterStateメソッドを利用する
char?.stateMachine.enterState(AttackState)
}
}
}
class StayState: CharState {
var enteredDate = NSDate()
override func didEnterWithPreviousState(previousState: GKState?) {
enteredDate = NSDate()
}
override func updateWithDeltaTime(seconds: NSTimeInterval) {
if NSDate().timeIntervalSinceDate(enteredDate) > 0.2 {
char?.stateMachine.enterState(AttackState)
}
}
override func enableToAttack() -> Bool {
return false
}
}
var power = 1
}
併せてGameScene.swiftのupdateメソッドを書き換えます。
class GameScene: SKScene, SKPhysicsContactDelegate {
// 略...
override func update(currentTime: NSTimeInterval) {
char.stateMachine.updateWithDeltaTime(currentTime)
if let charState = char.stateMachine.currentState as? Char.CharState where charState.enableToAttack() {
enemyList.enemiesCloseToPoint(char.frame.origin, distance: 50).forEach {
$0.life -= charState.power
char.stateMachine.enterState(Char.StayState.self)
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)
}
}
}
}
}
// 略...
}
大体既存コードと同じなのですが、違いとしてAngryStateに「didEnterWithPreviousState」メソッドが追加されました。これはStateが他のものからAngryStateになったときに呼ばれるコールバックメソッドです。逆にAngryStateから別のStateになるときは「willExitWithNextState」メソッドが呼び出されます。
他にもGKStateMachineには別Stateへ変更可能かをチェックする「isValidNextState」など便利な機能が付いています。
次回は、プレイヤーが自由に自機を配置したりレベルアップしたり
今回はStateパターンとStateMachineを利用することで保守性の高い実装をしました。本連載は新規実装になるのでメリットが伝わりにくいのですが、実際にゲームを開発して保守をすることになれば、これらの機能によるメリットは大きいかと思います。
次回は自機の動きをさらに改善して、プレイヤーが自由に自機を配置したりレベルアップしたりすることができるようにしていきます。
筆者紹介
杉本裕樹
田町のベンチャーで働くエンジニア。
仕事ではiPhoneアプリの開発やRailsを使ったWebサービス開発を行っている。最近のマイブームはUnityを使った3Dゲーム開発。
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へ移行するメリットや手順、注意点など勘所をまとめて紹介します。