Unityに関連する記事です

 ポップアップ内で選択しているキャラをタイルマップに配置する処理を実装します。

 この手順が完成することで、下記の動画のように、ポップアップ内で選択したキャラが配置される機能を実装します。
ただし、配置したキャラがアニメーションせずに、1枚の画像の状態である場合で問題がない場合には、この手順は不要です。

<実装動画>
動画ファイルへのリンク


 以下の内容で実装を進めていきます。

手順23 ー配置したキャラのアニメを自動設定する処理の実装ー
41.CharaController スクリプトを修正し、配置したキャラに合わせたアニメーションを再生する機能を実装する



 新しい学習内容は、以下の通りです。

 ・AnimationClip の動的な差し替え処理



1.設計


 画面に配置したキャラは CharaData に Sprite 画像の設定があるため、その情報を参照して、画像が変わるようになっています。

 この手順ではさらに一歩踏み込んで、各キャラごとに作成したアニメーションの情報(AnimationClip)を CharaData として設定できるようにし、
ゲームオブジェクトの振る舞いを変えるようにします。

 そうすることにより、画面に配置したキャラは、1枚の画像ではなく、アニメーションする情報もキャラごとに参照して設定できるようにします。


2.キャラごとのアニメーションを作成する


 手順9内にある【14.2移動アニメの作成を行う】を参考にしながら、
各キャラのスプライトアニメーションを作成します。

 正面を向いているスプライト画像を利用してアニメーションを作成してください。名前は Chara_1 のように、終わりの数字の部分を連番にして
CharaDataSO スクリプタブル・オブジェクト内の各キャラの通し番号の情報(CharaNo 変数)と同じ番号にしておくことで管理がしやすくなります。

 スプライトアニメーションを作成すると AnimationClip の他に AnimatorController が作成されます。
これらは不要ですので、AnimationClip だけ残して、AnimatorController は削除してください。

 フォルダなども自分で作成して、ファイルの整理整頓を心がけてください。


参考 キャラ分の AnimationClip。AnimatorController は最初にあるもの以外は削除



 続いて、この各 AnimationClip を CharaDataSO スクリプタブル・オブジェクトに登録できるようにするため、CharaData クラスに情報を追記します。


3.CharaData スクリプトを修正し、アニメーションの情報を登録できるようにする


 スクリプタブル・オブジェクトのデータは、この CharaData クラスを元に作成されています。
そのため、スクリプタブル・オブジェクトに新しい変数の情報を追加したい場合には、その元である CharaData スクリプトを修正して、新しい変数を追加する必要があります。


CharaData.cs

<= クリックすると開きます


 スクリプトを修正したらセーブを行います


4.CharaDataSO スクリプタブル・オブジェクトに各キャラごとの AnimationClip を登録する


 CharaData クラスに新しい変数を追加しましたので、セーブを行うと、スクリプタブル・オブジェクトの方にも自動的に新しい情報として CharaAnim 変数が追加されます。
新しい変数が追加されるだけで以前のデータは残っています。

 charaAnime 変数には【2.キャラごとのアニメーションを作成する】で作成したスプライトアニメーション(AnimationClip 型)を登録できます。
ドラッグアンドドロップして、各キャラごとの AnimationClip を登録してください。


CharaDataSO スクリプタブル・オブジェクト インスペクター画像



 以上で設定は完了です。最後に CharaController を修正し、この CharaAnim 変数を利用して、配置されたキャラに合わせてアニメーションを差し替える処理を実装します。


5.CharaController スクリプトを修正する


 アニメーションの設定用の変数の宣言と SetUpChara メソッド内でアニメーションの設定用の SetUpAnimation メソッドの呼び出しを記述します。
なお、SetUpAnimation メソッド内の処理は、テラシュールブログ様のサイトの記事を参考にさせていただいております。ありがとうございます。
テラシュールブログ 様
【Unity】MecanimのAnimationClipを動的に差し替える
http://tsubakit1.hateblo.jp/entry/2016/11/18/23413...



 処理の内容としては、AnimationClip の差し替えを行うことになります。
Animator ビューのステートを選択すると Motion 部分に AnimationClip の情報が表示されます。ここをゲーム内で動的に変更を行います。

 新しく作成する overrideClipName 変数に登録する文字列が、差し替える AnimationClip と同名の文字列である必要があります。
そのためこの変数の値は、自分のプロジェクトの内容に合わせて変更する必要があります

 Chara ゲームオブジェクトの Animator ビューを確認し、Chara ステートを選択します。このときインスペクターの Motion 部分に AnimationClip の名前が表示されますので、
その名称をこの変数に代入するようにしてください。そうしないと、キャラのアニメーションを動的に差し替える処理が上手く実行されません。


Animator ビュー インスペクター画像



 
CharaController.cs


 スクリプトを修正したらセーブを行います。


6.<AnimationClip の動的な差し替え処理>


 今回追加した SetUpAnimation メソッド内でやっていることですが、これは、下記のマニュアルを見ていただくと可視化できます。
インスペクターで設定できることを、ゲーム内でランタイムに制御するため、スクリプトを利用して同じことをしているイメージです。
 

Unity 公式マニュアル
Animator Override Controller


 それでは処理の内容を1行ずつ読み解いていきます。



overrideController = new AnimatorOverrideController();

overrideController.runtimeAnimatorController = anim.runtimeAnimatorController;

 新しく AnimatorOverrideController のインスタンスを作成し、その runtimeAnimatorController 変数に、現在の AnimatorController の runtimeAnimatorController 変数を代入しています。
これは先ほどのマニュアルを見ていただくとわかるのですが、上書きする方にも現在と同じ情報を代入しておく必要があるためです。



anim.runtimeAnimatorController = overrideController;

 現在の AnimatorController の runtimeAnimatorController に対して新しく作成した AnimatorOverrideController を代入して更新します。
この時点で、一旦、まったく同じ内容の情報で更新が入ります。

 この処理を行っておくことで、AnimatorController が再生処理を行うとき、AnimatorOverrideController の設定を利用することができる状態になります。



AnimatorStateInfo[] layerInfo = new AnimatorStateInfo[anim.layerCount];

 AnimatorStateInfo 型の配列を用意し、anim.layerCount 変数だけ要素番号を取得しておきます。

 基本的に anim.layerCount の値は 1 です。内容としては BaseLayer(いつもステートを登録している場所) の情報になります。
確認するためには、11行目に Debug.Log("LayerCount : " + anim.layerCount ); を入れてみると分かります。

 何か内部的な情報を可視化して確認したいときには、Debug クラスの Log メソッドを活用してみてください。



for (int i = 0; i < anim.layerCount; i++)
{
    //GetCurrentAnimatorStateInfoでAnimatorの現在の状態からデータを取得する。例えば、速度、長さ、名前、その他の変数など
    layerInfo[i] = anim.GetCurrentAnimatorStateInfo(i);  
}

 GetCurrentAnimatorStateInfo メソッドを実行することで Animator の現在の状態を取得できます。
それを用意しておいた空の状態の layerInfo 配列に代入して保持しておきます。

 BaseLayer しかない場合、layerCount 変数は 1 なので、このループは1回だけ処理を行います。

 for 文は、実数値に置き換えて考えると理解が深まります。

 今回の処理は、下記のような処理ですので

layerInfo[i] = anim.GetCurrentAnimatorStateInfo(i);

 この i 変数部分を実数値にして置き換えて考えてみてください。

layerInfo[0] = anim.GetCurrentAnimatorStateInfo(0);

 よって、実際にはこのような、layerInfo[0] の要素とし代入処理が行われていることが分かります。



overrideController[overrideClipName] = this.charaData.charaAnim;

 overrideController 変数は Animator クラスが用意している Dictinary 型の変数です。
Key は string 型で定義されていますので、文字列の値を指定することで Value の値を更新できます。

 今回は string 型の overrideClipName 変数を定義してありますので、この値を Key として指定し、
this.charaData.charaAnim 変数の情報を Value として代入処理しています。

 この処理により、overrideController に設定しているアニメの情報を、今回利用するキャラ専用のアニメの情報に更新します。



anim.runtimeAnimatorController = overrideController;  

 先ほど overrideController の内容を更新し、現在利用しているキャラのデータのアニメ情報に更新して置き換えたので、
それを再度、runtimeAnimatorController に適用し、更新したアニメの情報を設定します。

 overrideController に情報を設定しただけでは反映されないため、設定後、この更新の処理を行うことで反映・適用されます。



anim.Update(0.0f);  

 この Update メソッドは Animator クラスに用意されているメソッドです。(通常の Update メソッドではない、ということですね)
アニメーションの更新設定を反映させる処理です。この処理を入れておくと設定した新しいアニメが即座に適用されます。


Unity スクリプト・リファレンス
Animator



for (int i = 0; i < anim.layerCount; i++)
{
    anim.Play(layerInfo[i].fullPathHash, i, layerInfo[i].normalizedTime);
}

 アニメーションの状態情報を使用して、アニメーターの各レイヤーで再生中のアニメーションを復元します。

 layerInfo[i].fullPathHash 変数は、再生中のアニメーションのフルパスのハッシュ値(int 型)を取得し、
i 変数はレイヤーのインデックス(0 の場合、BaseLayer)、layerInfo[i].normalizedTime 変数はアニメーションの再生時間を正規化した値(0-1)を表します。
これらの情報を使用して、各レイヤーで再生中のアニメーションを指定した時間位置から再開します

 フルパスとはステートの階層構造のことです。BaseLayer の中にステートが存在していますので、
基本的には、BaseLayer.Idle といった形で親子関係が構築されています。
この情報をハッシュ値である int 型に変換したものが fullPathHash 変数です。
ここで指定しているのは、現在、ゲーム画面で再生しているアニメのステートの情報を制御するようにしています。
今回の場合であれば、移動用のステートに対して命令しています。

 normalizedTime 変数はアニメの再生時間をアニメーションの長さで割り、0から1の範囲に正規化します。
例えば、再生時間のトータルが2秒のアニメであれば、それが再生されて現在1秒であるとき、正規化を行うと 0.5 という値になります。

 したがって、この部分を抜くと、アニメーションの再生位置や状態が保持されず、新しいアニメーションが最初から再生されることになります。



 ここまで説明の通り、下記の処理はなくても、アニメの変更手続き自体は終了しています。

anim.Update(0.0f);

for (int i = 0; i < anim.layerCount; i++)
{
    anim.Play(layerInfo[i].fullPathHash, i, layerInfo[i].normalizedTime);
}

 ただし、更新したアニメがすぐに適用されなかったり、途中だったアニメが最初から再生されてしまうと違和感を感じてしまうため、
こういったちょっとした部分が実はゲームの画面ではすごく不自然に映ります。

 そこで上記の処理を行い、ゲーム画面が自然に映るように処理を施しています。
気配りのようなものですが、こうした1つ1つの小さな処理が重要です。


7.ゲームを実行して動作を確認する


 キャラを配置してみてください。
CharaData に登録した AnimationClip にアニメーションが差し替われば制御成功です。

 もしも上手くいかない場合には、AnimationController の情報を Animator ビューで確認し、
Motion の部分の AnimationClip の名前と、スクリプト内の登録とが相違していないかをチェックしてください。


<実装動画>
動画ファイルへのリンク


 これでスクリプタブル・オブジェクトを活用して、配置するキャラの情報を設定することで、
1つのゲームオブジェクトを異なるゲームオブジェクトになるように情報を設定する処理が完成です。



 以上でこの手順は終了です。

 次は 手順24 −ゲームの進行管理の制御機能の実装  です。

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Menu



技術/知識(実装例)

2Dおはじきゲーム(発展編)

2D強制横スクロールアクション(発展編)

3Dダイビングアクション(発展編)

2Dタップシューティング(拡張編)

レースゲーム(抜粋)

2D放置ゲーム(発展編)

3Dレールガンシューティング(応用編)

3D脱出ゲーム(抜粋)

2Dリアルタイムストラテジー

2Dトップビューアドベンチャー(宴アセット使用)

3Dタップアクション(NavMeshAgent 使用)

2Dトップビューアクション(カエルの為に〜、ボコスカウォーズ風)

VideoPlayer イベント連動の実装例

VideoPlayer リスト内からムービー再生の実装例(発展)

AR 画像付きオブジェクト生成の実装例

AR リスト内から生成の実装例(発展)

private



このサイト内の作品はユニティちゃんライセンス条項の元に提供されています。

管理人/副管理人のみ編集できます