今回はUnityで主人公キャラを追いかけてくるサブキャラの作成をします。
サブキャラにはNavMeshAgentを取りつけてNavMeshしたフィールド上を歩ける状態にしておきます。
これに関しては前回の
の記事でやりましたのでそちらを参考にしてください。
正直なところ前回の内容の敵キャラが主人公を追いかけていくスクリプトと同じなんですが・・・・(^_^;)
今回はそれ専用のスクリプトを作って、記述しますので、他の機能とごっちゃになることはないかと思います。
サブキャラクターの準備と追いかけるスクリプトFollowChara
まずはサブキャラクターを用意し、アニメーターコントローラーをつけIdleとWalkの状態を作成してください。
アニメーターコントローラで使うアニメーションパラメータはSpeedというパラメータのみになります。
サブキャラにNavMeshAgentのコンポーネントを取りつけたら、新しいスクリプトFollowCharaを作成し取りつけます。
このFollowCharaが主人公キャラを追いかける専用のスクリプトになります。
Unity5.5バージョン?以降でC#でスクリプトを組んでいる場合は
using UnityEngine.AI;
というusingディレクティブを記述しておくといいです。
1 2 3 4 5 6 7 8 9 10 11 12 13 | private NavMeshAgent agent; // 追いかけるキャラクター [SerializeField] private GameObject player; private Animator animator; // 到着したとする距離 [SerializeField] private float arrivedDistance = 1.5f; // 追いかけ始める距離 [SerializeField] private float followDistance = 1f; |
上のようなフィールドを宣言します。
agentはNavMeshAgent、playerは主人公キャラクターをインスペクタで設定します。
animatorはサブキャラのアニメーション制御で使います。
1 2 3 4 5 6 | void Start () { animator = GetComponent <Animator> (); agent = GetComponent <NavMeshAgent> (); } |
Startメソッド内でコンポーネントの取得をします。
次に追いかける部分の処理を作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | void Update () { agent.SetDestination(player.transform.position); // 到着している時 if(agent.remainingDistance < arrivedDistance) { //agent.Stop(); // Unity5.6バージョン以降の停止 agent.isStopped = true; animator.SetFloat("Speed", 0f); // 到着していない時で追いかけ出す距離になったら } else if(agent.remainingDistance > followDistance) { //agent.Resume(); // Unity5.6バージョン以降の再開 agent.isStopped = false; animator.SetFloat("Speed", agent.desiredVelocity.magnitude); } } |
agent.remainingDistanceで目的地とサブキャラとの距離を調べ、目的地(主人公)との距離agent.remainingDistanceがarrivedDistanceより下になったらagent.Stopでエージェントの動きを止めアニメーションをIdleにする為にアニメーションパラメータのSpeedを0fに設定します。
目的地との距離がまだある場合でサブキャラと目的地の距離agent.remainingDistanceが追いかける距離followDistanceより大きい場合はアニメーションパラメータのSpeedをエージェントの速さに設定します。
これで完成です!
・・・というだけでは前回のを少し変更しただけになってしまいますので・・・(^_^;)
サブキャラが主人公キャラの方を見る機能の追加
サブキャラが到着している間はサブキャラが主人公キャラを見るようにしてみます。
1 2 3 4 5 6 7 8 9 10 11 12 | void OnAnimatorIK() { var weight = Vector3.Dot(transform.forward, player.transform.position - transform.position); if(weight < 0) { weight = 0; } animator.SetLookAtWeight(weight, 0f, 1f, 0f, 0f); animator.SetLookAtPosition(player.transform.position + Vector3.up * 1.5f); } |
OnAnimatorIKは特別なメソッドで、アニメーターコントローラーのレイヤーの設定でIK Passのチェックを入れると、呼び出されます。
まずはVector3.Dotでサブキャラが向いている方向とプレイヤーの位置からサブキャラの位置を引いてプレイヤーキャラのいる方向とのベクトルの内積を求めます。
ベクトルの内積とはなんぞや!?と思った方も多いと思いますが、サブキャラの向いている方向の単位ベクトル(長さが1のベクトル)と主人公キャラのいる方向の単位ベクトルが完全に同じなら1、
反対方向なら-1が返ってきます。
という事は主人公キャラがサブキャラの見える範囲内180度以内の時にいれば正の値が、見えづらくなってきたあたりから負の値が返ってきます。
それを利用して追いかけるキャラクターの方向を求めます。
1 2 3 4 | animator.SetLookAtWeight(weight, 0f, 1f, 0f, 0f); animator.SetLookAtPosition(player.transform.position + Vector3.up * 1.5f); |
animator.SetLookAtWeightでウエイトを指定します。
第1引数は全体のウエイト、第2は体の関係度合い、第3は頭の関係度合い、第4は目の関係度合い、第5はモーションの制限で0は制限なしで1で完全に制限されます。
とりあえずウエイトをさきほど計算したweightを設定します。
weightが負の値だった場合はウエイトを0にして主人公キャラを見ないようにします。
1 2 3 | animator.SetLookAtPosition(player.transform.position + Vector3.up * 1.5f); |
で見るポイントを主人公に設定します。主人公キャラの基点は足元になっていますので、Vector3.upでY方向に1.5をかけ、
主人公の1.5mの高さの部分を見るようにしています。
第5の引数がキャラクターのモーションの制限なので、ここを0.5にすると変に体が曲がってしまう事がなくなります。
このパラメータを使えばさきほどのスクリプトのようにDot関数を使う必要もなくすっきり出来ます
1 2 3 4 5 6 | void OnAnimatorIK() { animator.SetLookAtWeight(1f, 0.3f, 1f, 0f, 0.5f); animator.SetLookAtPosition(player.transform.position + Vector3.up * 1.5f); } |
それではUnityの実行ボタンを押して試してみましょう。
静止画像だけで追いかけてくるかどうかわかりません・・・。
少年がガン付けられているようにしか見えませんね・・・。
とにかくサブキャラ(実はmasasi君)が主人公キャラを追いかけてきて、到着状態の時は主人公キャラを見るようになりました。
RPGのパーティの隊列を作る
主人公キャラクターが一定の距離離れたら追いかけてくるサブキャラの作成が出来たので、RPGによくある主人公に付いてくる仲間たちを作りたいと思います。
仲間たちはさきほど使った「masasi」君をコピーして名前をmasasi2、masasi3とします。
↑のような感じで右から主人公、masasi、masasi2、masasi3となっています。
ちょっと怖い・・・・(^_^;)
masasi、masasi2、masasi3にはFollowCharaスクリプトを作り取りつけます。
それぞれにキャラクターのplayerに主人公を設定してしまうと隊列が出来ないので、playerには別のキャラクターを設定します。
playerにはそれぞれ
masasi→chara
masasi2→masasi
masasi3→masasi2
に設定し追いかけるキャラクターを別々にし、数珠繋ぎのような感じで指定してあげます。
これでうまく追いかけてくれるかUnityの実行ボタンを押して確認してみましょう。
↑のように主人公が移動すると仲間が前の人間を追いかけるようになりました。
怖いお兄ちゃんに追いかけられるどころか、軍人さんたちに追いかけられる少年に変わりました・・・・((+_+))