UnityのAnimatorのレイヤーのSyncを使ってアニメーションを全て変更する

Unityのゲームで、キャラクターが元気な状態なのか、疲れている状態なのかでAnimatorの状態や遷移条件はそのままに、アニメーションクリップだけを替えたい事があります。

スクリプトを使えば、Animatorの歩いている状態(Walk)に設定されているアニメーションクリップを別のものに切り替える、ということでも実現出来そうです。

ですが、そんな時はAnimatorでベースとなるレイヤーと、シンクロした新しいレイヤーを作成した方が簡単です。

新しいレイヤーのBlendingをOverrideにし、ウエイトが0の場合は、ベースとなるレイヤー(通常状態)の状態と遷移を使い、1の場合は新しいレイヤー(疲れた状態)の状態と遷移を使う事が出来ます。

つまり、スクリプトから新しいレイヤーのウエイトを操作し、Animatorの状態と遷移はそのままにアニメーションを変更する事が出来ます。

スポンサーリンク

キャラクターに設定したAnimatorに新しいレイヤーを作成する

まずは、キャラクターに設定しているAnimatorControllerに元気な時のレイヤーを作成してみましょう。

キャラクターの通常状態のレイヤー

↑がキャラクターが元気な時の状態と遷移を作成したものです。

アニメーションパラメータにFloat型のSpeedを作成し、Idle→WalkはSpeedがGreaterで0.1、Walk→IdleはSpeedがLessで0.1という条件で遷移するように作成します。

IdleにはスタンダードアセットのEthanのIdle、WalkにはスタンダードアセットのEthanのWalkを設定し、普通に立っている、歩いているという状態になります。

次にキャラクターが疲れた状態のレイヤーを作成します。

疲れた状態時用のレイヤーを作成する

↑の左上のLayersを押し、その右下の+を押します。

名前をTired Layerとしたら、右の歯車をクリックし、Syncにチェックを入れます。

すると、Source Layerに指定したレイヤーの状態と遷移がそのまま現れますが、アニメーションクリップが設定されていません。

Idle、Walkにキャラクターが疲れた時用のアニメーションクリップを設定します。

Tired LayerのBlendingをOverrideとしているので、上のWeightが1になればTired Layerの状態と遷移、Weightが0になればBase Layerの状態と遷移が使われるようになります。

つまり、このWeightをスクリプトから操作すれば、キャラクターのアニメーションだけを切り替える事が出来ます。

キャラクター操作スクリプトの作成

キャラクター操作スクリプトを作成し、Tired Layerのウエイトを操作していきます。

基本のキャラクターの移動やアニメーションの遷移条件の変更等は、

Unityのアニメーションを切り替える為のアニメーターの設定とアニメーションの遷移をさせるスクリプトの作成を行います

を参考にしてください。

キャラクター操作スクリプトの概要

今回のキャラクター操作スクリプトの処理を考えていきます。

キャラクターを動かしている状態(移動キーを押している)が一定時間続いたら、キャラクターを疲れている状態にします。

こまめに移動キーを離していれば、疲れは溜まらないとします。

キャラクターが疲れた状態になっている時に、その場で一定時間じっとしていれば元気な状態に戻るようにします。

疲れた状態で少しでも移動キーを押すと、回復までの経過時間がリセットされ、また最初から時間の計測をする事にします。

キャラクターが元気な状態か、疲れた状態かはTired Layerを取得し、レイヤーのウエイトをスクリプトから操作する事で切り替えます。

状態を変化させた時に、いきなりウエイトをパッと切り替えてしまうと、アニメーションもいきなり変化しておかしくなるので、ウエイトは徐々に変化させていきます。

疲れた状態になる時間、回復までの時間等はインスペクタで設定出来るようにします。

スクリプトの実装

作成するスクリプトの処理がわかったので、スクリプトを作成していきます。

フィールド宣言とStartメソッド

まずはフィールド宣言とStartメソッド内の初期化処理です。

キャラクターの状態を列挙型で作成しておきます。

キャラクターは元気な時と疲れた時で歩くスピードを変化させる為、インスペクタでそれぞれのスピードを設定出来るようにします。

疲れた時用のレイヤーTired Layerを取得する為、tiredLayerというint型のフィールドを宣言します。

Tired Layerのウエイトを操作する時に、レイヤー番号を使用する必要がある為にこのフィールドを使います。

tiredLayerはStartメソッド内で

animator.GetLayerIndex(“Tired Layer”)

と、レイヤー名でレイヤーのインデックス番号を取得し、代入しています。

smoothFlagは徐々にウエイトを操作する時に、今ウエイトを操作しているか?という状態フラグです。

キャラクターの状態を変化させた時にsmoothFlagをオンにし、ウエイトが0か1になったら(どちらの状態からどちらの状態へ変化したかで分かれる)SmoothFlagをオフにします。

ちなみに、フィールド宣言で使用している[SerializeField]はそのフィールドを直列化(シリアライズ化)することの宣言です。

クラス全体を直列化しデータとして保存する時には、publicなフィールドしか直列化出来ませんが、この[SerializeField]を付けておくとprivateなアクセス修飾子が付いていても直列化する事が出来ます。

また、privateでもインスペクタで値を設定する事が出来るようになります。

クラス全体の直列化に関しては、

Unityのゲームで進行具合やキャラクターのステータスをデータとして保存しておき、それらのデータを読みだして続きから再開するというのは必須の機能になっています。 その為に今回はゲームデータのセーブとロードが出来るようにしてみたいと思います。

を参照してください。

その他、説明していないフィールドはコメントを見て頂ければわかると思います。

Startメソッド内で

SetState(State.Normal, first : true);

という見慣れない?記述がありますが、これはSetStateというメソッドの第2引数にはtrueというbool値を渡すという事です。

first :

という見慣れない表記があるのは、いったい何のbool値を渡しているのか?をわかりやすくする為のC#?の記述の仕方です。

現時点でSetStateを作成していないので、このfirstが何なのかもわかりづらいですが・・・・(^_^;)

firstはSetStateを呼び出すのが最初かどうか?のbool値です。

first自体には意味がないので、単純に

SetState(State.Normal, true);

でいいんですが、何のbool値を渡しているかを解りやすくする為にfirstという文字を記述していただけです。

キャラクターの状態を変化させるメソッドがSetStateなんですが、処理の関係上、最初の呼び出しの時はTired Layerのウエイトを操作したくない為にこのフラグを使って、第2引数にtrueが渡ってきた時はウエイトを操作しないようにしています。

SetStateメソッド

Updateメソッドを見る前に、キャラクターの状態を変化させるSetStateメソッドを見ていきます。

SetStateメソッドの第2引数の仮引数でfirstが宣言されていますが、firstにfalseを代入しています。

これはSetStateを呼び出した時に第2引数が指定されていなければ、firstにfalseを設定するという意味です。

ここら辺は

C#のクラスの作成やフィールド、メソッド、コンストラクタ、プロパティについて記述しました。

で解説しているので参照してみてください。

SetStateメソッドでは、キャラクターの状態フィールドstateを受け取った引数に変更し、firstがfalseだったらsmoothFlagをオンにし、ウエイト操作を行います。

元気な状態に変更した時は、nowSpeed(現在の歩くスピード)にwalkSpeedを設定し、idleTime(じっとして動かない時間)を0にします。

疲れた状態に変更した時はnowSpeedにtiredWalkSpeedを代入しています。

SetStateで行っている事はキャラクターの状態の変化と、その際に必要になるフィールドの変更ですね。

Updateメソッド

Updateメソッドではキャラクターの移動、アニメーションの切り替え、Tired Layerのウエイトの操作といった事を行います。

  • 移動キーを押している時
  • 現在、元気な状態の時は疲れた状態へと遷移する為の時間(continuedWalkTime)を増やしていきます。

    疲れている状態の時は、回復までの経過時間(idleTime)を最初からやり直す為0を代入しています。

  • 移動キーを押していない時
  • 疲れた状態へと遷移する為の時間(continuedWalkTime)を0にリセットします。

    現在、疲れた状態の時は回復までの経過時間(idleTime)を足していきます。

  • 元気な状態、疲れた状態で判定
  • 元気な状態、疲れた状態でcontinuedWalkTime、idleTimeと比較し、キャラクターの状態を変更します。

  • 徐々にウエイトを変化させる
  • smoothFlagがオンの時は、元気な状態か疲れた状態かでウエイトを徐々に足したり引いたりして操作します。

    ウエイトが、それぞれ指定する値(0か1)を越えた時にsmoothFlagをオフにし、ウエイトの操作を終了します。

    ウエイトの操作はMathf.MoveTowardsでも出来そうですね。

    最後に

    animator.SetLayerWeight (tiredLayer, weight);

    でTired Layerのウエイトを変化させたweightに設定します。

    これでスクリプトの作成は終了です。

    キャラクターを操作しアニメーションが変化するか確認

    機能が完成したので、キャラクターを動かしてレイヤーのウエイトが変化、アニメーションの変化を確認してみましょう。

    ↑のようになりました。

    アニメーションの切り替えを、ウエイトを操作するだけで行う事が出来るので、疲れた状態のレイヤー、ダメージを負った時のレイヤーと切り替える事が出来ますね。

    これはかなり使えるかも!?

    と自画自賛してみたり・・・・(;一_一)

    スポンサーリンク

    記事をシェアして頂ける方はこちら

    フォローして頂くとやる気が出ます