オフメッシュリンクで狭い通路を通るときに、屈んで歩くアニメーションに変えて歩く速さも遅くしてみました。
オフメッシュリンクを作る
まず、壁と通路を作ってナビメッシュをベイクしました。通路の天井が低いのでこの中にはナビメッシュが作られていません。
そこで、通路の出入り口に小さなシリンダーを置いて片方にオフメッシュリンクコンポーネントを付け、2つのシリンダーをStartとEndにアタッチしました。
これでナビメッシュリンクが作られてナビメッシュエージェントがこの間を通過できるようになります。
ナビメッシュエージェント
キャラクターにナビメッシュエージェントコンポーネントを付けて、通路の反対側の目的地を設定しました。エージェントは通路のナビメッシュリンクのところまで来ますが、Auto Traverse Off Mesh Linkのチェックが入っていないと自動で通過できません。
チェックを入れるかスクリプトでNavMeshAgent.autoTraverseOffMeshLinkをtrueにすると通過できますが、アニメーションが変わらないと頭が通路の天井を突き抜けます。さらにオフメッシュリンクの上ではスピードが不自然に上がりました。
NavMeshAgent agent;
// ---
agent = GetComponent<NavMeshAgent>();
agent.autoTraverseOffMeshLink = true;
かがむアニメーションを設定
そこで、アニメーターコントローラーにかがむアニメーションを設定したステートを作って、デフォルトの歩行アニメーションから遷移させてみます。
Parametersタブの+ボタンでBool型のパラメーターを作り遷移の条件に使います。
歩行アニメーションから屈むアニメーションへの遷移では、Has Exit Timeのチェックを外して、Conditionsでこのパラメーターがtrueのときに遷移するようにしました。
Transition Durationでアニメーションが切り替わるのにかかる時間を変更できます。この間に2つのアニメーションがブレンドされます。
パラメーターがfalseだと逆に遷移するようにしました。
スクリプトを作る
キャラクターにスクリプトを付けて、オフメッシュリンクに出入りするタイミングでパラメーターの値やスピードを切り替えます。
オフメッシュリンク用のシリンダーをコピーしてゴール地点に置き、スクリプトにアタッチしています。
using UnityEngine;
using UnityEngine.AI;
[RequireComponent(typeof(NavMeshAgent))]
[RequireComponent(typeof(Animator))]
public class OffMeshLinkTest : MonoBehaviour
{
NavMeshAgent agent;
Animator animator;
bool isPassing;
[SerializeField] Transform goal;
float defaultSpeed;
[SerializeField] float linkSpeed = 0.2f;
// Start is called before the first frame update
void Start()
{
agent = GetComponent<NavMeshAgent>();
agent.autoTraverseOffMeshLink = true;
// 目的地を設定
agent.destination = goal.position;
// スピードを保存
defaultSpeed = agent.speed;
animator = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
// 通過中
if(isPassing)
{
// オフメッシュリンクから抜けると
if (!agent.isOnOffMeshLink)
{
// スピードを戻す
agent.speed = defaultSpeed;
// 通過中を解除
isPassing = false;
// アニメーションを元に戻す
animator.SetBool("BendDown", false);
}
}
// 通過中でないとき
else
{
// オフメッシュリンク上に来たら
if(agent.isOnOffMeshLink)
{
// スピードを遅くする
agent.speed = defaultSpeed * linkSpeed;
// 通過中にする
isPassing = true;
// かがむアニメーションにする
animator.SetBool("BendDown", true);
}
}
}
}
スクリプトでは、通過しているかどうかを表すbool型の変数を作って場合分けしています。通過中にオフメッシュリンクを抜けるとNavMeshAgent.isOnOffMeshLinkがfalseになるので、そのときにスピードとパラメーターの値を変えて、通過中でない状態にします。
// 通過中
if(isPassing)
{
// オフメッシュリンクから抜けると
if (!agent.isOnOffMeshLink)
{
// スピードを戻す
agent.speed = defaultSpeed;
// 通過中を解除
isPassing = false;
// アニメーションを元に戻す
animator.SetBool("BendDown", false);
}
}
通過中でないときにオフメッシュリンクまで来るとNavMeshAgent.isOnOffMeshLinkがtrueになるので、スピードを遅くして屈むアニメーションに切り替えます。
// 通過中でないとき
else
{
// オフメッシュリンク上に来たら
if(agent.isOnOffMeshLink)
{
// スピードを遅くする
agent.speed = defaultSpeed * linkSpeed;
// 通過中にする
isPassing = true;
// かがむアニメーションにする
animator.SetBool("BendDown", true);
}
}
これで自然に通過できるようになりました。
しかし、まだ屈むタイミングが遅くて頭がすこし突き抜けたりしているので、アニメーションの遷移にかかる時間を変えたり、オフメッシュリンク用のシリンダーの距離を変えたりして微調整しました。