Unityに関連する記事です

 前回に引き続き、キャラモデルの演出を追加します。
この手順ではキャラモデルの各アクションに対してのアニメーションの制御を実装します。


<実装動画 バレット生成(攻撃)時>
動画ファイルへのリンク


<実装動画 被ダメージ時>
動画ファイルへのリンク


<実装動画 ゲームオーバー時>
動画ファイルへのリンク


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


拡張4 −キャラモデルのアニメーションの追加−
 7.キャラモデルのアニメーションを設定する
 8.キャラモデルのアニメーションを管理するスクリプトを作成し、アニメーションが遷移する処理を呼び出したいスクリプト内に適宜な部分に追加する



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

 ・Any State を利用したステートの遷移処理の実装例
 ・Animator.ResetTrigger メソッド
 ・static 修飾子
 ・const キーワードと const キーワードを利用したクラスの作成例



7.キャラモデルのアニメーションを設定する

1.設計


 各アクションに対しての制御は Animator の機能を利用し、Animator のパラメータを利用して制御を行っています。

 アニメーションの遷移処理はスクリプトを通じて制御することができますが、そのためには事前に、Animator ビューにおいて、
アニメーションのステートを登録し、パラメータを作成して、各ステート間の遷移条件を設定しなければなりません

 ステート間の遷移については Any State を利用します。この機能を利用することで煩雑になりがちなステート間の遷移処理を簡潔にまとめることが可能です。


2.Animator ビューにてアニメーションの設定を行う


 Little_Cat_Girl ゲームオブジェクトの子オブジェクトである Little_Cat_GirlRig ゲームオブジェクトを確認してください。
Animator コンポーネントがアタッチされていると思います。

 Animator コンポーネントの Controller プロパティ欄にはデフォルト情報として、Little_Cat_GirlRig コントローラーがアサインされてますので、
こちらのコントローラーを編集して設定を行います。この情報が Animator ビューに表示されます。


Little_Cat_GirlRig ゲームオブジェクト インスペクター画像




 Animator ビュータブを押して Animatorビューを表示してください。
Animatorビュー タブがない場合には、Unity Editor の左上のメニューより、Window => Animation => Animator で表示することが出来ます。

 ヒエラルキーの Little_Cat_GirlRig ゲームオブジェクトを選択することで、Animatorビュー にコントローラーの情報が表示されます。
最初からすべての AnimationClip がステートとして登録されていますので、下記の画像のようにトランジションを設定してください。
この画像にないステートは今回は利用しませんので、削除してもいいですし、Animator ビューの端側にまとめておいても構いません。


Animator ビューの設定


 
 Entry のトランジションを Idle になるようにして、他のトランジションへの遷移を止めておきます
また、AnyState を活用しますので、AnyState を起点として各ステートへの遷移を作成してください

 AnyState では、現在のステートがどこであるかは問わず、新しい遷移の条件が実行された時点で AnyState から遷移が実行されます。
そのため、各ステート間を逐一トランジションでつなぐ必要が亡くなります。



 つづいてパラメータを作成します。Trigger 型の attack と hitbool 型の down の3つを用意してください。
各パラメータの右側にあるアイコンの形でパラメータの型を判断できます。(○は Trigger型、□は Bool 型です。)


パラメータ画像


 パラメータを作成したら、トランジションにパラメータを設定してスクリプトから制御を行えるようにします。



 各ステートに対して、トランジションと遷移条件を設定します。
各設定については、下記のインスペクター画像をまとめておきますので参考にしてください。


AnyState => attack



インスペクター画像



attack => Exit




AnyState => get_hit



インスペクター画像



get_hit => Exit




AnyState => die



インスペクター画像



die => Exit



 以上で設定は完了です。どのトランジションがどの条件で遷移するかを確認しておいてください。



 また、各ステートに登録されている AnimationClip の確認をおこなってください。
もしも Loop Time にチェックが入っている場合、アニメーションが自動的にループしてしまうため、
チェックは外しておくようにしてください。


 下記の場合、Die の AnimationClip を確認した場合のものです。


AnimationClip






 画像のように Loop Time にチェックが入っていたら、外しておきましょう。

 このように Unity の場合は、ソースコード以外にも、エディター側の設定、インポートしたファイルの設定と、見直すべき箇所がたくさんあります。
なるべく視野を広く持っておくことで、万が一の不具合に対処できるようになります。

 例えば、予期しないアニメーションのループが発生した場合、ソースコード内でアニメの実行命令を確認したとしましょう。
仮に実行目入れが1度しか出ていないことが判明できたとき、ソースコードの修正だけに捕らわれいてはエラーは特定できません。

 視野を広く持ち、エラーには様々な要因があることを知っておくことで、次は AnimationClip の設定に問題があるかも、というようにエラーの想定が可能になるためです。


8.キャラモデルのアニメーションを管理するスクリプトを作成し、アニメーションが遷移する処理を呼び出したいスクリプト内に適宜な部分に追加する

1.設計


 どのスクリプトにどのような処理を追加すればよいか、ロジックを含めて考えてみましょう。
処理のゴール地点とスタート地点、繋がりをどのように構築すればよいか、など、今までの処理の実装例を思い出してみてください。


2.CharaAnimationController スクリプトを作成する


 Animator コンポーネントを利用して、Animator ビューにて設定を行ったステート間の遷移を実装します。
ロジックとしては、ステート単位で実行用のメソッドを用意せずに、Animator の実行命令を記述したメソッドを用意しておいて、
引数で受け取った情報を利用して汎用的に遷移が行える設計にしています。

 例えば、attack のパラメータの情報を引数で受け取った場合には attack のアニメーションを再生し、
hit のパラメータの情報を引数で受け取った場合には、同じメソッドではありますが、今度は hit のアニメーションを再生するような設計になっています。

 今回のケースでは、パラメータの情報については、static 修飾子付きの string 変数で宣言して値としてパラメータの文字列を代入しておくことで、
外部のスクリプトで引数としてパラメータの値を指定する際に、その都度文字列を入力するのではなく、これらの変数を利用します。

 文字列を直接スクリプト内に入力するとエラーを生みやすいので、可能であれば出来るだけ、enum や、string 型の変数を利用して値を代入しておくことで問題を未然に回避出来ます。
特に文字列はコンパイル時のエラーにひっかからないため、見つけにくいという問題もあります。(変数は書き間違えるとエラーが出ますが、文字列は出ません。)

 なるべく問題が発生しにくい処理の設計や記述を心がけることで、処理全体も見やすくなりますし、記述の精度が上がります


CharaAnimationController.cs

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


 スクリプトを作成したらセーブします。


3.<Animator.ResetTrigger メソッド>


 引数に指定した Trigger 型のパラメータで実行されているステートの処理をリセットして停止するメソッドです。

  animPlayer.ResetTrigger(attackParameter);
  animPlayer.SetTrigger(playAnimationParameter);

 今回のケースでは、attackParameter 変数内で指定している文字列("attack")の情報で動いている Trigger 型のステートを停止します。
そのため、Trigger 型の attack のパラメータを利用して制御されている attack ステートの処理が停止されます。

 そののちに、SetTrigger メソッドで新しいアニメーションが実行されるようになっています。


参考サイト
Unity公式スクリプトリファレンス
Animator.ResetTrigger
https://docs.unity3d.com/ja/current/ScriptReferenc...



 さて、なぜ attackParameter の方だけ ResetTrigger メソッドを実行しているかですが、
これは直前に動いているアニメが同じ attackParameter であった場合、同じ攻撃のアニメが連続で動くため、
挙動が不自然になることがあり、それを防ぐためです。

 例えば、連続で攻撃しているのに、3回に1回しか攻撃アニメがしなくなる、という感じです。
 
 そこで、攻撃用のアニメをリセットしておくことで、連続で攻撃をおこなった場合であっても、毎回最初から攻撃のアニメをするようにしています。
3回攻撃タップしたら、ちゃんと3回分の攻撃アニメが再生されるようにしたいですよね。

 これによりプレイヤーの操作と、それに期待されるアニメの挙動とを連携させるための調整がしたい、という目的があり、
その意図を実現するためにリセット処理を入れています。そうすることでユーザーの期待通りの挙動になる、という訳です。

 なお、hitParameter の方は被弾時のアニメなので、連続して敵からの攻撃がこない想定で、リセット処理は入れていません。
 ですが、タイミングによっては、被弾時のアニメも連続で動いてしまう可能性もありますので、こちらも ResetTrigger メソッドを入れても問題ないと思います。


4.<static 修飾子>


 static 修飾子を利用することで、この変数はインスタンスが自動的に作成されるともに、1つしか存在しなくなります。
そのため、【クラス名.static 修飾子の変数名】という記述をするだけで、CharaAnimationController クラスを変数に代入しなくても利用できます。

 それからもう1つ、同名のクラスを複数インスタンスしたときに、static の情報は1つしか存在しなくなる点があります。
CharaAnimationController クラスを複数インスタンスしたとき、static でない変数は、それぞれのクラスにある変数ごとに、それぞれのクラス固有の値が保持されます。
 
 ですが、static になっていると、この変数は共通の情報として利用する値となります。
そのため、複数の CharaAnimationController が存在した場合であっても、それぞれに同じ情報が固定で入るため、
それであればわざわざ別々に管理しないで、1つに共通化して使ってしまおう、という使い方です。

 この手法は今回は利用していませんが、そういった方法にも応用できる、汎用性のある設計にしてある、という形です。

 なお、こういった場合ですが、色々なクラスで共通して使う情報は const キーワードを使っても表現できます。
こちらについては別機能になりますので、最後に記述しておきます。


5.Little_Cat_Girl ゲームオブジェクトに CharaAnimationController スクリプトをアタッチして設定を行う


 ヒエラルキーにある Little_Cat_Girl ゲームオブジェクトに、作成した CharaAnimationController スクリプトをドラッグアンドドロップしてアタッチしてください。
インスペクターを確認してアタッチが正常に行われているかをチェックした上で、animPlayer 変数に必要な情報をアサインします。

 スクリプトより操作を行いたい Animator コンポーネントをアサインすることになりますので、Little_Cat_GirlRig ゲームオブジェクトをドラッグアンドドロップしてアサインしてください。
自動的に、Animator コンポーネントの情報がアサインされます。これでこのコンポーネントを操作する準備が整いました。


Little_Cat_Girl ゲームオブジェクト インスペクター画像



 以上で設定は完了です。


6.PlayerController スクリプトを修正する


 アニメーションを実行するための変数の宣言と、実行命令を追記します。


PlayerController.cs

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


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



 ヒエラルキーにある PlayerSet ゲームオブジェクトのインスペクターを確認してください。
新しく宣言した変数が表示されていますので、対象となるゲームオブジェクトをドラッグアンドドロップしてアサインしてください。


PlayerSet ゲームオブジェクト インスペクター画像



 以上で設定は完了です。


7.DefenseBase スクリプトを修正する


 こちらにも PlayerController と同様に、CharaAnimationController 型の変数を用意し、
アニメーションの切り替え命令を出せるようにします。

 今回は SerializeField属性にて変数を用意していますが、SetUpDefenceBase メソッドの引数に
CharaAnimationController 型の情報を追加し、引数を利用して情報を受け取る形式で実装してもいいでしょう。


DefenseBase.cs

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


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

 CharaAnime 変数に、Player のゲームオブジェクトにアタッチされている CharaAnimationController スクリプトをアサインしてください。


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


 実装する内容を確認し、デバッグが必要な部分を理解した上で処理を実行してください。
何か所かデバッグを行う必要がありますので、それを自分で1つずつ確認していってみましょう。


<実装動画 バレット生成(攻撃)時>
動画ファイルへのリンク


<実装動画 被ダメージ時>
動画ファイルへのリンク


<実装動画 ゲームオーバー時>
動画ファイルへのリンク


9<const キーワードと const キーワードを利用したクラスの作成例>


 ゲーム内に利用する情報のうち、定数を決めて扱いたい場合には const キーワードを使って表現できます。

 例えば、アイテムの最大所持数、お金の最大値というように、ゲーム全体で共通の値を設定して管理したい場合、
こういったゲーム内の大切な値を別々のクラスに書いてしまうと、どのクラスで設定しているかわかりにくく、管理しにくくなります。

 その場合、よく利用するのが、const キーワードを使い、定数のデータのみを集めた ConstData という形式のクラスを作成して運用する方法です。



 まずはサンプルコードを提示します。

<ConstData.cs>
public static class ConstData
{
    public const int MAX_EXP = 10000;

    public const float MOVE_LIMIT = -3000.0f;           // 拠点の位置。MoveDataSO スクリプト内で宣言している moveLimit 変数と同じものをこちらで用意

    public const string ATTACK_PARAMETER  = "Attack";   // CharaAnimeController スクリプト内で宣言している各変数と同じものをこちらで用意
    public const string downParameter = "down";
    public const string hitParameter = "hit";

    // TODO 他にもあれば追記する

}

 こちらでは先ほど作成した CharaAnimeController 内にあった static 修飾子の情報を const キーワードに置き換えてあります。
これは、今回の static 修飾子の情報を固定値として利用していたため、それをそのまま定数に置き換えることができているためです。
すべての static 修飾子が const キーワードに置き換えられるわけではありませんので注意してください。



 まず、クラスには static 修飾子をつけておき、インスタンスが自動的に1つだけ作られるようにします。

public static class ConstData

 クラスの継承は不要のため、MonoBehaviour クラスを削除します。また、using の情報も不要なので削除して構いません。
そのためこのクラスは、常に1つしかないので、変数に代入しなくても利用できるクラスになります。



 各変数には所定の書式があります。

public const 

 ここまでが共通の書式です。public 修飾子と const キーワードをセットで最初に記述します。
このようにすることで、次に宣言する変数の値を定数化し、どのクラスからでも同じ値が取り出せるようにします。



 const キーワードに利用できる型には制限があります。
下記は C# マニュアルからの抜粋です。

const キーワードは、定数フィールドまたはローカル定数を宣言するために使用します。
定数フィールドとローカルは変数でないため、変更できません。

定数には、数字、ブール値、文字列、または null 参照が含まれます。 

 以上のことから、数字(int、long、float、double 型など)、ブール値(bool)、文字列(string) が型として利用可能です。


参考サイト
MicroSoft
const (C# リファレンス)



 最後に変数です。
 
 変数の宣言における変数名ですが、const キーワードで利用する変数は慣例として、
すべて大文字で書いて、単語が変わる部分ではアンダーバーを使うという命名規則があります。


public const int MAX_EXP = 10000;
public const string ATTACK_PARAMETER  = "Attack";

 通常の変数と違って、小文字は使いません。単語の区切りで大文字にできないので、代わりにアンダーバーを使います。
この書き方は、すべて大文字である時点で「あ、これは定数が入っている変数だな」と誰もが判断できるようにするための、共通の書式です。
C# 以外でも一般的に利用されています。

 そして、const キーワードは定数値を設定する役目を持っているので、宣言と同時に必ず = を使って値を代入し、初期化を行います
初期化をしないとエラーが出ます。そして、この値は定数値となるため、ゲーム内では一切変更が出来ません。

 readonly キーワードもある意味で定数値を扱えますが、こちらは初期化するタイミングがコンストラクタメソッドでも許可されている部分が違います。
(変数の宣言時に、必ず = で初期化しなくてもいいということになっています)



 このような定数を専用のクラスとして作っておくと、どのクラスからでも【static クラス名.変数名】でアクセスできます。

 例えば、先ほどの DefenceBase の処理であれば、引数部分を ConstData に変更することで

charaAnimationController.PlayAnimation(ConstData.ATTACK_PARAMETER);

 こんな風に書くことが出来ます。
ここには定数で設定されている情報が使われているな、と判断がしやすくなります。



 ConstData クラスは作成しておくと便利なので、今後作るゲームに採用していただいてもいいかもしれません。

 アニメーションの遷移の命令には引数の指定に文字列を使いますが、打ち間違えが怖いので、それを ConstData に登録して事前に用意しておく形です。
そうすれば、毎回 ConstData から情報をもらえるので、文字を打ち間違える心配が無くなります。



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

 次は  です。

コメントをかく


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

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

Menu



技術/知識(実装例)

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

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

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

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

レースゲーム(抜粋)

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

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

3D脱出ゲーム(抜粋)

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

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

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

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

VideoPlayer イベント連動の実装例

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

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

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

private



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

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