VR、ゲーム制作、プログラミング。Unity とか Oculus Rift とか。

2014年5月18日日曜日

[Unity]uState : スクリプトベースのステートマシン

uState は Unity 用のスクリプトベースなステートマシンです。

ダウンロード

uState v0.9.1

過去のバージョン
uState v0.9.0

概要

スクリプトの記述を前提としたステートマシンです。


  • 基本 1 ステート 1 ファイル。100% スクリプトだけでも記述可能
  • パラメータ、遷移条件、各状態での動作などは自由に記述可能
  • 継承による一部改変が容易
といった色気のなさを特徴としています。

使い方 - はじめに

以下、慣れないうちは Examples/00_Common/Scripts にある TemplateStateMachine.csTemplateState.cs をコピーして編集するのがおすすめです。

また、ある程度 C# スクリプトを書くことに慣れた方であれば、これらのファイルやパッケージ内のサンプルを眺めながら以下の説明を読んでいただいた方が理解が早いかもしれません。

使い方 - ステートマシンとステートの作成

ステートマシン作成
  1. 新しい C# スクリプトを作成し、uStateMachine を継承する
    public class MyStateMachine : uStateMachine
    
  2. 作成したスクリプトを適当なオブジェクトに追加する
ステート作成
  1. まず、後の利便性のため、ベースとなるスクリプトを作成しておく
    1. 新しい C# スクリプトを作成し、uStateGeneric<MyStateMachine> を継承する
      public abstract class MyStateBase : uStateGeneric<MyStateMachine>
  2. 実際に利用するステートを作成する
    1. 新しい C# スクリプトを作成し、MyStateBase を継承する
      public class MyState1 : MyStateBase
    2. MyStateMachine を追加したオブジェクトに子オブジェクトを作成し、MyState1 を追加する
    3. インスペクタなどから、MyState1 の State Name を適宜設定する
初期ステートの設定
  1. MyStateMachine の Default State Name を、さきほど設定した MyState1 の State Name にする
これで、状態が 1 つだけで何もしないステートマシンができました。

使い方 - 動作の記述

各ステートでの動作は、以下のメソッドに記述します。
  • OnStateUpdate : 状態遷移判定の前
  • OnStateEnter : ステートに遷移した直後
  • OnStateExit : ステートから遷移する直前
  • OnStateStay : そのステートである間、Update ごとに呼び出される

使い方 - ステートマシンのパラメータ

ステートマシン全体のパラメータは、ステートマシンのスクリプトに public 変数などで通常の MonoBehaviour と同様に記述します。

各ステートではステートマシンに stateMachine フィールドでアクセスできます。

使い方 - 状態遷移

指定時間で遷移する方法と、bool を返す関数の結果で遷移する方法があります。

時間で遷移する場合は、ステートの Exit By Time に時間と遷移先状態名を指定してください。

関数の結果で遷移する場合は、以下のような関数をステートに用意しておき、ステートの Transitions の配列サイズを変更、関数名と遷移先状態名を指定してください。関数は public である必要があり、true が返ったときに遷移します。引数は取れません。

public bool IsParam1Large ()
{
    return stateMachine.param1 > 10; // true for transition and false for not
}

遷移関数は配列の若い番号のものほど優先されます。

使い方 - ステートの初期化をスクリプトだけで行う

ステートの各パラメータはインスペクタからも設定できますが、スクリプトに書いてしまった方が管理が楽になる面もあります。

Monobehaviour の Reset 関数に記述する方法がおすすめです。

using System.Linq; // for Concat()

protected override void Reset ()
{
    base.Reset();

    stateName = "State1";
    exitByTime = new ExitByTime(1.0f, "State2");
    transitions = (new Transition[] {
        new Transition("IsToState3", "State3"),
        new Transition("IsToState4", "State4")
    }).Concat(transitions).ToArray();
}

使い方 - ステートマシンの初期化をスクリプトだけで行う

ステートの生成を含め、全ての初期化をスクリプトで書くことも可能です。

こちらも Monobehaviour の Reset 関数で、パラメータの初期化やステートの生成を行います。

ステートの生成については、利便性のために DestroyAllStates() と CreateStates() が用意されています。

protected override void Reset ()
{
    base.Reset();

    defaultStateName = "State1";

    DestroyAllStates();
    CreateStates(new System.Type[] {
        typeof(State2),
        typeof(State3)
    });
}

使い方 - その他

  • 自分自身と同じステートに遷移できます
    • OnStateExit(), OnStateEnter() が呼び出されます
  • 遷移条件を満たす限り、1 フレーム内で複数ステート先まで遷移可能です
    • ステートマシンの transitionLimit で遷移回数の上限を指定します(デフォルトは 10)
    • 0 にすると無制限になりますが、無限ループにならないよう注意してください
    • ただし、自分自身と同じステートへの遷移は 1 回で止まります

サンプル

パッケージ内のサンプルの説明です。
  • 00_Common : サンプルで共通に使うスクリプトや、スクリプトの雛形があります
  • 01_Signal : 時間で状態遷移する信号機のようなものです。日本以外だとダメそうですね
遷移関数 transitions を使うサンプルがまだありません。すみません。追って追加予定です。

今後の予定

主にスクリプト作成支援系のエディタ拡張などを行い、アセットストアに出すことを検討しています。

その場合でもコア部分(少なくとも v0.9.0 相当)のスクリプトは体験版も兼ねて公開を続けます。ただし、メジャーバージョンアップや仕様上の欠陥が見つかった場合は後方互換性が保障されませんのでご了承ください。


2014/05/20 : v0.9.1 リリース。1 フレーム内の遷移回数制限追加など

4 件のコメント:

  1. ぜひtransitionsをつかうサンプルもよろしくお願いします。

    返信削除
    返信
    1. 私がゲームジャムで使ったときのソースをこちらに置きました。
      https://github.com/udasan/unity-mozzarella-states
      そのまま実行できるものではありませんが、ご参考になればと思います。

      削除
  2. わかりやすいサンプルで参考になりました!
    あと、Unity5の環境で実行したところ
    The function must have exactly 3 parameters. というエラーが出ましたので一応報告です。
    Unityで使用されている関数と名前が一致してしまったため起きているエラーのようで、uStateのOnStateUpdate, OnStateEnter, OnStateExitの3つの関数名をリファクタリングすることで回避できました。

    返信削除
    返信
    1. ご報告ありがとうございます!
      遠くないうちにこちらでも修正したいと思います。
      しかし Unity5 の StateMachineBehaviour 便利そうですね。
      uState の存在意義が薄らぐレベルに見えます。
      標準でできるのは嬉しいですね。

      削除