検索
連載

ゲームのState管理を簡単にするiOS 9 GameplayKitのクラスとはiOS SDKとSwiftで始めるゲーム作成入門(5)(4/4 ページ)

iPhoneゲームをSwift言語で作成してみたいという初心者向けにiOSのゲームフレームワークを使った作り方を一から解説する入門連載。今回は、GoFデザインパターンの1つである「Stateパターン」やiOS 9から登場した「GKStateMachine」クラスを取り入れることで、今後の開発に役立つ知見を共有します。

PC用表示 関連情報
Share
Tweet
LINE
Hatena
前のページへ |       

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.

前のページへ |       
ページトップに戻る