UnityEditorを使って2D格闘(2D Fighting game)作るときのモーション遷移図作成の半自動化に挑戦しよう<その3>

  • 0
    いいね
  • 0
    コメント

    前回まで

    201701230746a35.png
    スクリプトで線が引けることは分かった。
    前回: http://qiita.com/muzudho1/items/8455c0c7a26d5788b541

    ソース公開中 Open source

    201701211744gif33.gif
    https://github.com/muzudho/KifuwarabeFighter2

    モーションの紐付けを 半自動でやりたいんだった。

    「立ち待機」から「立ち弱パンチ~立ち強キック」まで 線を引く、ということをやるには、ステートに「これは立ち待機です」「これは弱パンチです」といった属性(荷札のようなもの)を付けておくという方法がある。
    201701231630a2b.png
    アニメーター・コントローラーのステートに 一対一対応で データを付けることができる。

    例えば、
    (1)ブロックするモーションには Attr.Block と付けておく
    (2)このモーションのときは レバーの横方向の倒しに反応しないときは Attr.BusyX と付けておく
    といった荷札をいくつか決めて置き、

    (3)複数の荷札は 縦棒「|」でつないでおく
    というルールにしておく。左側にQWERTYのキーの並びが有るキーボードなら 右上の方に | 記号があるだろう。

    201701231630a3b.png
    そして テスト用として Where メソッドを仮に用意した。ここで荷札を並べて実行すると、そのレコードを選び出す仕組みだ。

    201701231630a4b.png
    実行結果はこの通り。

    201701231630a5b.png
    上図には全部は映っていないが、Attr.BusyX と Attr.Block の両方を持つデータだけを取得する、ということができた。

    オープンソースなので、個別対応が嫌なので、どうやって この仕組みを作っているのか、C#スクリプト に興味のある方に向けて解説する。話しに付いてこれなくても置いていくので読み流してほしい。

    列挙型にしたのは無謀だったか。

    201701231630a6b.png
    プログラムの中で 月、火、水、木、金、土、日 のような、そのプログラムが存続中は 世の中で変わらないようなものを扱うときは、列挙型 というのは良い選択だ。
    例えば enum Week { Monday, Tuesday, Wednesday, Thuesday, Friday, Sataday, Sunday } といったように。

    だが ステート はどうだろうか? アニメーターを使って 頻繁に追加・削除される項目じゃないか。

    しかし "Base Layer.SMove" といった文字列を プログラムに埋め込みたくないのも実情だ。 const 型を大量に作るようでは enum型を使うのでも同じで 本質的に解決しない。

    一番いいのは アニメーターを編集したら 列挙型も更新されることなんだが、監視常駐プログラムを1個用意して .cs ファイルを動的更新させるようにすれば できないこともないのかもしれないが、日ごろ習慣にないことをすると あとで自分が 大混乱 するかもしれないので 踏み込めないところだ。 新しい習慣を説明するのも大変だ。 しばらく手作業で列挙型を編集することにする。とほほ。

    シーンごとに分けたC#スクリプト

    201701231630a7b.png
    C#スクリプトは シーンごとにフォルダー分けした。シーンを跨ぐものは CommonScript.cs にまとめた。

    その中で SceneTemplate という名前のフォルダーを特別扱いとして用意し、他のシーンでも使いまわせるように abstractクラスや interfaceクラスを用意した。

    abstractクラスや interfaceクラスを多用すると、ソースコードの量を減らす効果がある。 オブジェクト指向言語の恩恵を何も得ないコード に比べて、実行速度面でデメリットがあると思うが、ぐっとこらえて実行速度を極める方向は捨てた。

    hash_to_index

    C#には推奨される命名規則があると思うんだが、とりあえず それも捨てて我流で A_to_B という命名規則を使った。
    世の中、マッピングだ。(この先の丸い棒にはスプーンという名前を付けましょう、といったような対応付け)

    AはBなんだ。この hash は、あの index なんだ。というタダの1対1の対応。

    Unity では ステート名は全て数字にしていて、これをハッシュという。
    201701231630a8b.png
    だから プログラマーは OGiveup といったステート名ではなく、 -1420427518 といったハッシュを使ってプログラムを組まなければならないんだが そんなことは嫌なので、Unity のスクリプトに触れるときにぶつかる最初の壁で、みんな自分で "OGiveup" と書いたら "-1420427518" ということにしておいておくれよ、分かるな? というようなプログラムを組む。

    index というのは さっき説明した 列挙型を数字にしたもののことだ。列挙型の最初のメンバーを 0 とし、1、2、3 と連番にしている。

        /// <summary>
        /// シーンの Start( )メソッドで呼び出してください。
        /// </summary>
        public void InsertAllStates()
        {
            hash_to_index = new Dictionary<int, int>(); // <hash,AstateIndex>
    
            for (int iAstate = 0; iAstate < index_to_record.Count; iAstate++)
            {
                AstateRecordable astate = index_to_record[iAstate]; // [AstateIndex]
                hash_to_index.Add(Animator.StringToHash(astate.BreadCrumb + astate.Name), iAstate); // (~,AstateIndex)
            }
        }
    

    Animator.StringToHash("OGiveup") と書いてあれば、 -1420427518 が返ってくるわけだ。
    ここで私の場合、 -1420427518 は要らないから "SWait" に連番の 0 を当ててくれ、といった改造をしている。

    なんかあとで困りそうだが、今のところ困っていない。

    index_to_record

    AはBなんだ! index は、 record なんだ! A_to_B、index_to_record。
    これは 列挙型の数字(index)をキーとして、好きな形でデータを持とう、というものだ。

    201701231630a9b.png
    コンストラクタ部分が 手書きのデータベースのデータ記入部分となっている。
    また、ぶっきらぼうな シングルトンの形になっている。コーディングがめんどくさいのでセッターを外に出したままにしてしまった。

    201701231630a10b.png
    そして 条件検索は あっさりしたものだ。これが Where メソッドの中身だ。

    attr は本来 列挙型にしたいところなんだが、C#言語 では 列挙型にインターフェースを付けることができない。
    そこで int にキャストして、また列挙型に戻す、という冗長なことをやっている。

    .HasFlag には説明がいるかもしれない。

    列挙型.HasFlag( 列挙型 )

    201701231630a11.png
    インターネットのWebサイトで拾ったサンプルコードだ。
    Unity で使われているC#言語のバージョンが古いのか boolean型に .HasFlag( ~ ) メソッドが追加されていないようなので、それを後付けで追加するものだ。少し見慣れない構文をしているかもしれない。

    働きを 感覚的に説明すると、右のバケツを、左のバケツに 放り込めるなら真だ。
    確認してほしい。
    201701231630a12.png

    ただし、.HasFlag( ~ ) を使うためには下準備が要る。
    201701231630a13b.png
    この場合、2、4、8、16 という数字を割り当てている。
    enum型に [Flags] というアノテーションを頭に付け、中身は 1、2、4、8、といった2のN乗にする必要がある。オートでやってくれればいいのに、けっこう手間。

    Attrでも そうやっている。AstateIndexの方は棒「|」でつなげる使い方をしていないので フラグにはしていない。
    201701231630a14b.png
    この場合、0、1、2、4 という数字を割り当てている。

    これでひとまず、属性(荷札)を付けて データを絞り込む、という部分は 作れることが分かった。