【再編集】Unity開発メモまとめ「Animator」

※本記事は旧ブログの記事を再編集し、再度投稿したものです。
 一部内容に差異がある可能性がありますので、予めご了承ください。

【2016/05/29】
記事内容を一部修正・加筆しました。
Unity5.3.3 時点の内容になります。

スクリプト系メモ

Animatorのスクリプト制御に関するメモ集です。

Animator.Play()

引数で指定したアニメーションを再生します。
どのステートからでも強制的に遷移されます。
「攻撃をキャンセルして回避」などの割り込みを AnimatorController 側のパラメータで制御するのはなかなか大変です。
素直にスクリプト側でこれを使えば即時に遷移してくれます。

Animator.CrossFade()

こちらも引数で指定したアニメーションを再生しますが、遷移に掛かる時間を指定することができます。
AnimatorControllerのステートのインスペクターにある「transitionDuration」そのままだと思われます。

自分がCrossFade()の方が便利だと思うケースは、「アニメーションの途中から再生」させる場合です。

Input.GetButton("Jump") {
    animator.CrossFade("Jump", 0, 0, 0.8f);
}

CrossFade()の第4引数で「normalizedTime」を指定できます。
遷移先ステートの開始時間を0~1の間で指定できます。
上の例の場合、「Jump」というアニメーションの80%の部分から再生します。
「ジャンプ開始モーションは要らないけど、後半の落下モーションから再生したい」といった場合に便利です。

Animator.ResetTrigger()

指定したトリガーの状態をリセットします。
たまにリセットされない場合があるので、StateMachineBehaviourと合わせて使うと効果的です。
StateMachineBehaviour については後述します。

public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {
    animator.ResetTrigger("Jump");
}

HasExitTime

ステートのインスペクターに存在する項目です。
チェックを入れるとモーションが終わるまで他のステートに遷移しなくなります。
途中で他のステートに遷移させたくない場合はチェックを外しておきましょう。
Unity5 から Condition の項目から独立しているため注意します。

shot2ss20160529121715066

ただし Animator.Play() や Animator.CrossFade() 等で遷移させる場合、モーション途中でも遷移します。
AnimatorController とスクリプトの両方から制御している場合は注意が必要です。

EntryノードとExitノード

Unity5 の AnimatorController に追加されたノードです。
ステートマシンはEntryノードから遷移が始まり、Exitノードへ流れていきます。

遷移先にステートマシン自体を選択することで、そのステートマシンのEntryノードへ遷移させることができます。
サブステートマシン内のExitノードに到達した場合、遷移は1つ上のステートマシンのEntryに戻ります。

・・・という趣旨のものですが、正直かなりとっつきにくいです。
特に遷移先にサブステートマシンを指定した際に、ステートマシン内のEntryノードからどのステートへ流れるかが把握しにくいです。
(私的には)スクリプトで制御した方がスッキリしたりするので、無理に意識する必要もないかもしれません。
(サブステートマシン自体は類似するステートをまとめて管理できるので便利です)

一応公式のチュートリアルもありますが、英語な上メリットが伝わってこないので厳しいですorz
上手く使えば機能のカプセル化が実現できるようですが・・・。

https://www.youtube.com/watch?v=lpekqN4_4xg

StateMachineBehaviourを使った制御

StateMachineBehaviour は Unity の機能名ではなく、API のクラス名になります。
このクラスを継承したスクリプトは、Animator のステートに付けることができるようになります。
ステートに付与することで、特定のタイミングでコールバック関数が実行されます。

普通のスクリプトと同じようにパラメータも設定できます。
ただし特定のオブジェクトを指定するようなパラメータを持つことはできません。
(複数のキャラで使われる場合に使いまわせるようにするためらしいです)

ただ、コールバック関数実行時に引数として Animator が渡されるため、それで GmaeObject を参照すればいろいろできます。
Player クラスにゲッタやセッタを用意しておけば、間接的に値を操作することができ、SendMessage() で関数も実行できちゃいます。
例えば以下の例の場合、ステート終了時にプレイヤーのゲームオブジェクトの「damageReset」関数を呼び出します。

public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {
    animator.gameObject.SendMessage("damageReset", 0f);   
}

実装は StateMachineBehaviour の該当メソッドをオーバーライドして使います。
自動的に base が挿入されますが、消してしまっても問題ないと思われます。

汎用クラスの作成

ステートの遷移をコントロールする汎用クラスを作成します。
あくまで条件なので、「ジャンプ」「攻撃」に伴う処理(攻撃判定など)は各々のクラスで実装します。

以下のソースはボタン押下時にTriggerを操作したり、Animator.Play()を実行することで遷移させるものです。
InputManagerの名前とinputKeyを対応させる必要があります。

namespace StateController {
     public class SwitchTriggerByKey : StateMachineBehaviour {
 
          [SerializeField]
          private string inputKey;
 
          [SerializeField]
          private string parameterName;
 
          [SerializeField]
          private bool useAnimatorPlay;
 
          public override void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {
               if (Input.GetButtonDown(inputKey)) {
                    switchTrigger(animator);
               }
          }
 
          private void switchTrigger(Animator animator) {
               if (useAnimatorPlay) {
                    animator.Play(parameterName);
               }
                    animator.SetTrigger(parameterName);
               }
          }
     }
}

2段ジャンプの実装

自分のゲームではプレイヤーキャラクターの制御に「CharacterMotor」を使用しています。
基本的な移動やジャンプなどが簡単に実装できますが、「ジャンプ後は再着地までジャンプできない」といった部分まで厳密なので、
2段ジャンプなどの特殊な移動を行う際は工夫が必要です。

そこで StateMachineBehaviour を使ってみます。
「ジャンプ中に再度ボタン押下」で2段ジャンプ用ステートに遷移するようにします。
2段ジャンプのステートに以下のスクリプトを付与し、Enter 内でジャンプを行います。
ジャンプの移動処理は iTween.MoveBy() で行います。

 
public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {
     animator.gameObject.GetComponent<charactermotor>().movement.velocity.y = 0;
 
     iTween.MoveBy(animator.gameObject, iTween.Hash(
          "amount", new Vector3(0f, 25f, 0f),
          "time", 2f)
     );
 
     animator.ResetTrigger("Jump");
}

2段ジャンプ用のステートに遷移された瞬間に OnStateEnter が実行されます。
animator.gameObject がプレイヤーのゲームオブジェクトになるので、これに対して iTween を実行します。
amount と time の値はゲーム内容に合わせてお好みで。
2段ジャンプ時に CharacterMotor.movement.velocity.y の値を0にし、Y軸に余計な速度が掛からない状態で実行するようにします。

これに限らず「特定のモーション中に○○がしたい」といった際に便利です。
プレイヤーキャラの Update() で判定するよりも確実で、Player クラスのコードもスッキリします。

AnimatorOverrideController

1つの AnimatorController をベースに、別々のモーションを割り当てられる機能です。
「キャラクター間でコントローラは同じだけどモーションが違う」といった場合に便利です。
ベースとなる AnimatorController を選択し、それぞれのモーションを割り当てていきます。

shot2ss20160529134240605

キャラクター毎に固有のアクションをさせたい場合には不向きかもしれません。
逆にアクションが共通化されている場合は非常に便利です。

【再編集】Unity開発メモまとめ「CharacterMotor」

※本記事は旧ブログの記事を再編集し、再度投稿したものです。
 一部内容に差異がある可能性がありますので、予めご了承ください。

CharacterControllerのパラメータ

CharacterControllerのパラメータについてまとめたものです。
Unity公式にもリファレンスがあるので、合わせて確認すると分かりやすいと思われます。

・Slope Limit
どのくらいの傾斜まで登れるかを設定します。
数値がそのまま限界角度になるようです。

・Step Offset
「指定された値よりも地面に近い場合登る」と書いてあります。
要するに階段とかを登るためのものですね。
あまり大きくしすぎると絶壁すらもホイホイ登ってしまうため注意が必要です。

・Min Move Distance
この値未満の移動ができなくなる・・・らしいです。
自分が検証した感じだと動くか動かないかの二極だったので、デリケートな気がします。
公式にも「ほとんどの場合は0でいい」と書いてあるので、いじらなくてよさそうです。

・Skin Width
コライダーの位置はそのままに、地面との間を設定するもの(?)
公式曰く「動作させるための重要なパラメータ」らしいですが、自分のキャラではよく分かりませんでしたorz
「Radiusの10%程度にしておくといい」とあるので、0.05くらいにしておきます。

・Center
コントローラのカプセルコライダーの位置です。
キャラクターの旋回には影響しないそうです。

・Radius
カプセルコライダーの大きさ(半径)です。

・Height
カプセルコライダーの高さです。

CharacterMotorのパラメータ

すごくパラメータが多いです。
移動やジャンプの挙動に大きく影響するので大切な部分でもあります。

・Can Control
CharaCterMotorの有効/無効を切り替えます。
これだけを無効にすると、移動・ジャンプが行えなくなり、入力した方向への回転のみになります。

・Use Fixed Update
そのまま捉えると「FixedUpdate関数を使うかどうか」といった感じでしょうか。
前に検証してもよく分からなかったですorz

Movement

移動に関するパラメータです。
デフォルトではWSで前後、ADで左右に移動ができます。
ゲームパッドを接続している場合、左スティックで移動ができます。

・Max Forward Speed
前方への移動速度です。
PlatformInputControllerを使っている場合、入力方向へ旋回するので、実質全方向への移動速度になります。

・Max Sideways Speed
平行移動時の移動速度です。
PlatformInputControllerのAutoRotateをOFFにしている場合、これが平行移動速度として適用されます。

・Max Backwards Speed
後方への移動速度です。
PlatformInputControllerのAutoRotateをOFFにしている場合、(略

・Slope Speed Multiplier
坂などの斜面に対する速度の減少度合いを設定します。
縦軸が速度、横軸が高さ(?)だと思われます。
例えば線を一定にすると、(SlopeLimit以内の傾斜なら)どんな坂でも一定の速度で登れるようになります。

SlopeLimitと似ていますが、あちらは「滑る斜面の角度」に対し、こちらは「坂に対する減少速度」です。
使ってみると分かりますが、似て非なるもの・・・というよりほぼ別物です。

・Max Ground Acceleration
「Acceleration」は加速度とかそんな感じの意味です。
移動入力時の加速度を設定します。
もっと具体的にいうと、軸の入力値が0~1の間の時の速度・・・だと思います。
ゲームパッドでスティックを少しだけ倒すと分かりやすいです。

この値とPlatformInputControllerの「MaxRotationSpeed」の値を大きく設定すると、向きと逆方向に入力した際のキレがよくなります。
あまり高くしすぎると初速度が早すぎて操作しにくくなりそうなので程々で。

CharacterControllerはPhysicsMaterialの影響を受けませんが、この値を小さくすると「氷の上で滑る」ような感じにできます。
その場合は判定を作り、EnterとExitでこの値を変化させるのがいいと思います。

・Max Air Acceleration
Max Ground Accelerationの空中版です。
この値を大きくすると、空中でも機敏に動けるようになります。
逆に小さくすると空中制御がしにくくなり、ファミコンのアクションゲームのような癖のある挙動になります。

・Gravity
そのまま「重力」です。
ゲーム的に言うと落下速度ですが、どちらかというと重力加速度(?)な気がします。
これ単体で大きくしても歪な挙動になるので、下のMaxFallSpeedと合わせて調整しましょう。

ちなみにProjectSettings→PhysicsのGravityは適用されないようです。
まあ両方が作用したらいろいろと面倒になりそうなので、別々でいいと思います。

・Max Fall Speed
Fallは「落下」とかそういう意味ですね。
となれば「最大落下速度」とかそんな感じでしょうか。
Gravityと合わせて、ゲーム内容に合った値に調節しましょう。

Jumping

ジャンプに関するパラメータです。
デフォルトでは接地状態でスペースキーを押すことでジャンプが行えます。

・Enabled
ジャンプの有効/無効を切り替えます。

・Base Height
基準となるジャンプの高さです。
ジャンプ入力すると、最低限この高さまでは飛びます。
実際は重力とかもあるので数値通りの高さではないです。

・Extra Height
ジャンプ入力し続けることで飛べる高さです。
BaseHeight分の高さを飛んだ後もスィーっと飛び続けます。
BaseHeightを1、ExtraHeightを100にした状態でスペースキーを押し続けると分かりやすいです。

・Perp Amount
「Perp」は垂直という意味です。
坂の上でジャンプした時、どの程度斜めにジャンプするか設定します。
斜角に対し、0だと垂直(影響なし)、1だと直角、0.5はその間です。

・Steep Perp Amount
「Steep」は急勾配という意味です。
PerpAmountの急斜面版みたいな感じでしょうか。
デフォルトだと0.5なので、壁に密着してジャンプすると変な方向に飛んだりしますが、これを0にすればなくなります。

Moving Platform

地面が動いている場合の挙動を制御します。

・Enabled
MovingPlatformの有効/無効を切り替えます。
これを無効にすると、動く床の上でも位置が移動しません。
スーファミのアクションゲームでよくありそうな感じですね。

・Movement Transfer
「None」
ジャンプ時の床の影響を受けません。
横に動くリフトからジャンプしても垂直に飛びます。

「InitTransfer」
ジャンプ時に床の速度を参照し、停止するまで速度が掛かります。
「動く床だから考慮するけど、そんなに飛ばしたくない」時にお世話になりそうです。

「PermaTransfer」
ジャンプ時に床の速度を参照し、着地するまで速度が掛かります。
デフォルトはこれで、慣性的にもこれが一番自然な形でしょうか。

「PermaLocked」
ジャンプした床の動きに合わせて移動します。
往復するリフトの上でジャンプした場合、リフトからはみ出ずに連動して動きます。

Sliding

スライダーの有効/無効を・・・と言いたいところですが、ONとOFFで何も変わりませんでした。
他は効くのにこれだけ効かないというのも考えにくいところですが・・・。
もしかしたらスクリプトからの制御を無効にする・・・のかもしれません。

・Sliding Speead
斜面から自動的に滑り落ちる際の速度です。

・Sideways Control
斜面に対して垂直方向に移動する際の速度です。
変に難しい表現をしている気がしますが、つまり「滑っている際の左右への移動速度」ですね。

・Speed Control
斜面から下り方向へ移動入力した際に滑る速度です。
この値が低いと下り方向へ入力しても速度がほとんど変わりません。
所謂スライダー系のステージで、プレイヤーの入力で調節できるようにする場合に使えそうです。

PlatformInputControllerのパラメータ

プレイヤーの回転を担うスクリプトで、三人称視点の場合に使用します。
パラメータが少ないので、モーターほどきつくはないかと思います。
ちなみに一人称視点(所謂FPS)の場合は「FPSInputController」を使いますが、本記事では扱いません。

・Auto Rotate
回転の有効・無効を切り替えます。
無効にするとMovementのMaxSidewaysSpeedとMaxBackwardsSpeedが有効になります。

・Max Rotation Speed
プレイヤーのY軸の回転速度を設定します。
ロボットアクションによくある「旋回速度」とほぼ同じだと思います。

ブログ移転しました!

というわけで、本日よりFC2ブログから独自サーバーに移転しました!
VPS上にWordPressをインストールし、旧ブログと独立した形になっています。
今後はこちらのサーバーで運営していきますので、よろしくお願いします!

ブログタイトルは「ゴマちゃんフロンティアV2」に変更しました。
V2は「Version2」のつもりで、単純に「2代目」のブログのためです。

新ブログになって変わったこと

FC2ブログサービスから独自サーバーに移ったことで、今までよりいろいろカスタマイズできるようになりました!

独自ドメイン

ドメインとして「gomafrontier.com」を取得しました!
前の量産型っぽいドメインから独立した感じになりました。

レスポンシブデザイン

ブログ移転の際にテンプレートをリニューアルし、レスポンシブデザイン対応になりました!
今までは「スマフォでアクセスされたらPC版にリダイレクト」というトンデモブログでしたが、今後はスマフォからでも問題なく見れます!
流石にモバイルには対応していませんが、PCとスマフォで十分だと思われます。

Googleアドセンス

Googleのインデックスが新ブログに向いてきたら、Googleアドセンスを導入しようと考えています。
自分自身広告を貼るのは嫌いなのですが、独自でサーバーやドメインを用意している関係上、少しでもカバーしたいという面があります。
収益性を重視しているわけではないので邪魔にならないものにする予定です。

プラグイン

表面的な影響はありませんが、WordPressの各種プラグインを使用することで機能を拡張できます。
運営・管理の面で前より快適になった箇所は多いです。

記事内容と旧ブログの記事について

Unityや関連するソフトを用いたゲーム開発という点は変わりません。
自作ゲームを作る上で実装してみたい機能や、気になった点を重点的に取り上げていきます!
新ブログからはファイルアップロードの制限がなくなったので、サンプルなども問題なく置けるようになりました。
なるべく具体的に手段・方法を公開していきたいです。

旧ブログの記事内容は古くなっていたり、開発方針が変わっているものが多く、そのまま移転してくるのはよろしくない状態でした。
なので、記事はそのまま引っ越しをせず、開発メモや技術メモなどの重要な記事だけ再編集して投稿する予定です。
当分は旧ブログの記事を再編集して投稿することが多くなると思います。

まとめ

そんなわけで、独自サーバーにブログを移転しました!
まだ見切り発進に近い部分もあるので、気付き次第修正して慣れていきたいところです。
これからも心機一転、ゲーム開発を続けていきますので、よろしくお願いします!