iOS9から導入されたGKStateMachineによってStateパターンに則ったコードが書きやすくなりそう。
最低限実装に必要な部分をメモ。
各状態クラスはGKStateを継承して作成する。
いくつかのメソッドをオーバーライドして次のようなことを行う
- 各状態における動作
- どの状態に遷移可能かを判定
- 状態遷移直後の処理
- 状態遷移直前の処理
StateNormal
import UIKit
import GameplayKit
class StateNormal: GKState {
var normalTime:Double = 0
override func isValidNextState(stateClass: AnyClass) -> Bool {
return true
}
override func updateWithDeltaTime(seconds: NSTimeInterval) {
noarmalTime += seconds
print(normalTime)
if(normalTimeTime>1.0){
stateMachine!.enterState(StateNormal)
}
}
override func didEnterWithPreviousState(previousState: GKState?) {
print("change to normal")
normalTime=0.0
}
}
StateDown
import UIKit
import GameplayKit
class StateDown: GKState {
var downTime:Double = 0
override func isValidNextState(stateClass: AnyClass) -> Bool {
return true
}
override func updateWithDeltaTime(seconds: NSTimeInterval) {
downTime += seconds
print(downTime)
if(downTime>1.0){
stateMachine!.enterState(StateNormal)
}
}
override func didEnterWithPreviousState(previousState: GKState?) {
print("change to down")
downTime=0.0
}
}
上記の2つの状態クラスを使用する状態機械を定義して使用している。
やっているのは主に下記の2つ
- 状態機械を事前に定義した状態を使用して初期化している
- 初期状態の決定
- 状態機械の処理実行
ViewController
class ViewController: UIViewController {
// 状態機械を初期化
var sm:GKStateMachine = GKStateMachine(states: [StateNormal(),StateDown()])
// ボタン押下時の処理
@IBAction func changeState(sender: AnyObject) {
sm.updateWithDeltaTime(0.3)
}
override func viewDidLoad() {
super.viewDidLoad()
// 状態機械の初期状態決定
sm.enterState(StateNormal)
}
}
実行結果
change to normal
0.3
0.6
0.9
1.2
change to down
0.3
0.6
0.9
1.2
change to normal
0.3
0.6
0.9
1.2
change to down
0.3
0.6
StateMachineのupdateWithDeltaTimeメソッドを呼ぶとその時の状態クラスのupdateWithDeltaTimeメソッドが呼ばれるところがポイント。
本来ならば、StateMachineのupdateメソッドはspritekit経由で呼んでやるものなのだろうけど、今回は簡略化のためにその辺りを飛ばしているので注意されたし。