本文へスキップ

ステートマシン

はじめに

ステート・マシンは、状態管理を単純化するために設計されている。

ステートマシンは3つの主要コンポーネントから構成される:

  • 州グループ
  • トリガー

ステートマシンは常に正確に1つの状態にあり、(トリガーによって定義された)特定の条件が満たされたときに状態間を遷移する。 ステート・グループは、複数のステート間で共有されるロジックを束ねる便利な方法だが、グループそのものはステートではない。

ecs.registerComponent({
name: 'Jump On Touch',
stateMachine: ({world, entity, defineState}) => {
const idle = defineState('idle').initial().onEnter(() => {
console.log('アイドル状態に入る')
}).onEvent(ecs.input.SCREEN_TOUCH_START, 'jumping')

const jumping = defineState('jumping').onEnter(() => { console.log('ジャンプ状態に入る') ecs.physics.applyImpulse(world eid 0 5 0) }.onEnter(() => {
console.log('Entering jumping state')
ecs.physics.applyImpulse(world, entity.eid, 0, 5, 0)
}).onTick(() => {
console.log('In jumping state')
}).wait(2000, 'idle')
},
}).

ステートマシンの定義

コンポーネント内にステートマシンを作成する場合、関数は次のように呼び出される:

プロパティ

プロパティタイプ説明
世界世界世界への言及。
イードイード現在のコンポーネントのエンティティID。
エンティティエンティティ現在のコンポーネントのエンティティインスタンス
定義状態functionステートマシンの状態を定義する関数
defineStateGroupfunctionステートマシンのグループを定義する関数
スキーマ属性ワールド属性ワールドスコープにおける現在のコンポーネントのスキーマへの参照。
データ属性ワールド属性ワールドスコープにおける現在のコンポーネントのデータへの参照。

次のコードは、空のステートマシンを定義する方法の例である:

ecs.registerComponent({
...
stateMachine: ({world, entity, defineState}) => {
// ここで状態を定義する
},
})

ステートとは、ステートマシンの基本的な原子単位である。 ステートマシンの可能な状態を定義した後、トリガを定義することで状態間を移動できる。

州の定義

次のコードは、コンポーネント内のステートマシン内で新しいステートを定義する方法の例です。

ecs.registerComponent({
...
stateMachine: ({world, entity, defineState}) => {
const foo = defineState('foo')
...
}
})
チップ

State関数は "フルエント "であり、Stateの同じインスタンスを返すので、1つのステートメントで複数の関数呼び出しを連鎖させることができる。

.initial()

ステートマシンの作成時に、この状態を最初のアクティブ状態としてマークする。

defineState('myCustomState').initial()

.onEnter()

この状態になったときに実行するコールバックを設定する。

defineState('myCustomState').onEnter(() => {
// 何かをする
})

.onTick()

この状態がアクティブな間、毎フレーム実行するコールバックを設定する。

defineState('myCustomState').onTick(() => {
// 何かをする
})

.onExit()

この状態を終了するときに実行するコールバックを設定します。

defineState('myCustomState').onExit(() => {
// 何かをする
})

.onEvent()

特定のイベントを受信すると、新しい状態に遷移する。

パラメータタイプ説明
イベント (必須)ストリングリッスンするイベント名
nextState (必須)文字列または州イベント発生時に遷移する状態
オプション(オプション)オブジェクト追加オプション

オプション

パラメータタイプ説明
ターゲットイードイベントを受信すると予想されるエンティティ(デフォルトは現在のエンティティ)
どこ(event) => booleanトランジションする前にチェックするオプションの条件。
defineState('myCustomState').onEvent(
ecs.input.SCREEN_TOUCH_START,
'other',
{
target: world.events.globalId,
where:(event) => event.data.position.y > 0.5
}.
)

.wait()

一定時間後に新しい状態に移行する。

パラメータタイプ説明
タイムアウト番号遷移するまでの時間(ミリ秒単位
次の状態文字列または州次に遷移する状態
defineState('myCustomState').wait(1000, 'myOtherCustomState')

.onTrigger()

TriggerHandle(ecs.defineTrigger()で定義)がトリガーされた時に新しい状態に遷移する。

パラメータタイプ説明
ハンドルトリガーハンドル手動で作動させたときにトランジションを起こすハンドル
次の状態文字列または州次に遷移する状態
const toOther = ecs.defineTrigger()
defineState('example').onTrigger(toOther, 'other')
...
toOther.trigger()

.listen()

ステートに入ると自動的に追加され、ステートが終了すると削除されるイベントリスナーを登録します。

パラメータタイプ説明
ターゲットeidまたは() => eidイベントを受信すると予想されるエンティティ
名称ストリング注目のイベント
リスナー(イベント) => voidイベントがディスパッチされたときに呼び出される関数
const handleCollision = (event) => { 
console.log('Collided with', event.data.other)
}
defineState('example').listen(eid, ecs.physics.COLLISION_START_EVENT, handleCollision)

州グループ

ステートグループは、ステートのリストに適用される動作とトリガーを定義する方法です。 国家グループは国家そのものではないので、直接移行することはできない。 その代わり、グループ内のいずれかのステートがアクティブになると、グループのビヘイビアとトリガーもアクティブになる。

ステート・グループの定義

パラメータタイプ説明
サブステート(オプション)文字列または状態の配列このグループを構成する州のリスト。このパラメータを除外すると、すべての州をリストアップすることになる。
const fizz = defineState('fizz')
const buzz = defineState('buzz')

const fizzBuzz = defineStateGroup([fizz, 'buzz'])
チップ

ステート・グループ関数は "フルエント "であり、ステート・グループの同じインスタンスを返すので、1つのステートメントで複数の関数呼び出しを連鎖させることができる。

.onEnter()

このグループに入るときに実行するコールバックを設定します。

defineStateGroup(['a', 'b']).onEnter(() => {
// 何かをする
})

.onTick()

このグループがアクティブな間、毎フレーム実行するコールバックを設定する。

defineStateGroup(['a', 'b']).onTick(() => {
// 何かをする
})

.onExit()

このグループから抜けるときに実行するコールバックを設定します。

defineStateGroup(['a', 'b']).onTick(() => {
// 何かをする
})

.onEvent()

特定のイベントを受信すると、新しい状態に遷移する。

パラメータタイプ説明
イベント (必須)ストリングリッスンするイベント名
nextState (必須)文字列または州イベント発生時に遷移する状態
オプション(オプション)オブジェクト追加オプション

オプション

パラメータタイプ説明
ターゲットイードイベントを受信すると予想されるエンティティ(デフォルトは現在のエンティティ)
どこ(event) => booleanトランジションする前にチェックするオプションの条件。
defineStateGroup(['a', 'b']).onEvent(
ecs.input.SCREEN_TOUCH_START,
'other',
{
target: world.events.globalId,
where:(event) => event.data.position.y > 0.5
}.
)

.wait()

一定時間後に新しい状態に移行する。

パラメータタイプ説明
タイムアウト番号遷移するまでの時間(ミリ秒単位
次の状態文字列または州次に遷移する状態
defineStateGroup(['a', 'b']).wait(1000, 'c')

.onTrigger()

TriggerHandle(ecs.defineTrigger()で定義)がトリガーされたときに新しい状態に遷移する。

パラメータタイプ説明
ハンドルトリガーハンドル手動で作動させたときにトランジションを起こすハンドル
次の状態文字列または州次に遷移する状態
const toC = ecs.defineTrigger()
defineStateGroup(['a', 'b']).onTrigger(toC, 'c')
...
toC.trigger()

.listen()

状態グループに入ると自動的に追加され、終了すると削除されるイベントリスナーを登録します。

パラメータータイプ概要
targeteidまたは() => eidイベントを受信すると予想されるエンティティ
名称ストリング注目のイベント
リスナー(イベント) => voidイベントがディスパッチされたときに呼び出される関数
const handleCollision = (event) => { 
console.log('collided with', event.data.other)
}
defineStateGroup(['a', 'b']).listen(eid, ecs.physics.COLLISION_START_EVENT, handleCollision)

カスタムトリガー

カスタムトリガーを定義することができ、このトリガーはいつでも発動してトランジションを起こすことができる。

const go = ecs.defineTrigger()
const stopped = defineState('stopped').onTick(() => {
if (world.input.getAction('start-going')){
go.trigger()
}.
}).onTrigger(go, 'going')
const going = defineState('going')