#前回までの記事
【GameplayKit】iOSゲームアプリにおけるStateパターン実践 Part_2では、給水機が取りうる全ての状態に共通する機能が実装されたDispenserState
クラスを定義しました。
#この記事について
本記事では、ステートとステートマシンの実装を行います。
給水機が変化しうるそれぞれの状態(ステート)を表現するクラスを定義します。
給水機は以下の状態に変化します。
- 満タン(FullState)
- 水あり(PartiallyFullState)
- カラ (EmptyState)
- 補給中(RefillingState)
- 給水中(ServeState)
定義されたステートは、ステートマシンによって管理・操作します。
ステートマシンを使うことで、給水機そのものを操作するよりも効率的に給水機を扱うことができます。
#手順
-
FullState
クラスを定義 - ステートマシンを定義
##満タン状態を表現するクラスを定義する
メニューバーから「File > New > File... > iOS > Swift File」を選択します。
ファイル名はFullState.swift
にしておきます。
SpriteKit
とGameplayKit
フレームワークをインポートして、DispenserState
クラスを継承したFullState
クラスを定義します。
import SpriteKit
import GameplayKit
class FullState: DispenserState {
}
親クラスに定義されているイニシャライザを利用して、必須イニシャライザを定義します。
また、didEnter(from:)
メソッドとwillExit(to:)
メソッドをオーバーライドします。
class FullState: DispenserState {
init(game: GameScene) {
super.init(game: game, associatedNodeName: "FullState")
}
override func didEnter(from previousState: GKState?) {
super.didEnter(from: previousState)
let green = SKColor.green
changeIndicatorLightToColor(green)
}
override func willExit(to nextState: GKState) {
super.willExit(to: nextState)
let black = SKColor.black
changeIndicatorLightToColor(black)
}
}
didEnter(from:)
メソッドとwillExit(to:)
メソッドでは、給水機の表示ランプの色を「満タンになったらグリーン・満タンではなくなったらブラック」に変化させています。
##ステートマシンを定義する
ステートマシンは各種状態への遷移を管理する役割を持ち、GKStateMachine
クラスによって表現されます。
ゲームシーンに、GKStateMachine
クラスのオブジェクトを定義します。
まず、GameScene.swift
ファイルにGameplayKit
フレームワークをインポートしておきます。
メンバワイズプロパティにstateMachine
プロパティを暗黙アンラップなオプショナルで定義します。
stateMachine
プロパティは、didMove(to:)
メソッドで初期化します。引数には、GKState
型オブジェクトの配列を渡します。
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var stateMachine: GKStateMachine!
override func didMove(to view: SKView) {
let fullState = FullState(game: self)
stateMachine = GKStateMachine(states: [fullState])
stateMachine.enter(FullState.self)
}
override func didChangeSize(_ oldSize: CGSize) {
let dispenser = childNode(withName: "dispenser")
dispenser?.position.x = size.width / 2
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
let locationInView = touches.first?.location(in: view)
let locationInScene = convertPoint(fromView: locationInView!)
let refillButton = childNode(withName: "//refillButton")
let location = locationInScene
if atPoint(location) == refillButton {
print("attempt to refill.")
} else {
print("attempt to dispense")
}
}
}
didMove(to:)
メソッドで、給水機の初期状態がFullState
になるように記述しています。
###ビルド
シミュレータでビルドしてみます。
給水機の表示ランプindicator
がグリーンになっていれば、状態がFullState
になっていることになります。また、状態遷移パネルにある「Full」がハイライトされていることも確認しておきましょう。
#次回
ステートマシンを実現するGKStateMachine
クラスを使って、状態GKState
オブジェクトを管理することができました。
ステートマシンでは、GKState
型のインスタンスを操作せずにクラスそのものを扱っていることに注目できます。
次回【GameplayKit】iOSゲームアプリにおけるStateパターン実践 Part_4では、他の状態オブジェクトを定義して、状態から状態への繊維を実装します。