違うフロアにいるとき等にナビメッシュエージェントの目的地にプレイヤーの位置を毎フレーム設定すると、エージェントの移動がカクついてスムーズにプレイヤーを追尾しません。
毎フレーム目的地を入れて、経路が変わることが原因でしょうか。プレイヤーが近くにいたり、ナビメッシュがシンプルなときは起こらないので、プレイヤーと敵が同じフロアにいるとき以外は、間隔をあけて目的地を更新してみました。
そのためには、まずプレイヤーと敵のスクリプトで各々がどのフロアや階段にいるかを判定します。これには階段の出入り口にコライダーを置いてOnTriggerExitを使いました。今回は2階建てで階段は2つです。
また、このコライダーの親オブジェクトとして、階段の中央あたりに空のゲームオブジェクトを置いて、プレイヤーがコライダーを通過して階段に入ったときにそのオブジェクトをプレイヤーにもたせて、エージェントが取得できるようにします。
目的地の設定は、プレイヤーと敵が同じフロアにいるときは毎フレーム、それ以外のときは20フレームに一度行うようにしました。
public int Floor { get; protected set; } = 1;
Transform[] stairPoints; // 階段
int num;
void TrackPlayer()
{
// 同じフロアにいるとき
if (Floor == FirstPersonController1.GetInstance().Floor)
{
// 毎回通常
//Debug.Log("同じフロアにいるとき");
// 目的地を設定
// ...
num = 0;
}
// 別のフロアのとき
else
{
if (num > 0)
{
num++;
if(num >= 20)
{
num = 0;
}
}
// 20フレーム毎に目的地を更新
else
{
// エージェントが階段にいるときか、プレイヤーが外にいるとき
if (Floor == -1 || FirstPersonController1.GetInstance().Floor == 0)
{
Debug.Log("エージェントが階段にいるときか、プレイヤーが外にいるとき");
// 目的地を設定
// ...
num = 0;
}
// プレイヤーが階段にいるとき
else if (FirstPersonController1.GetInstance().Floor == -1)
{
Debug.Log("プレイヤーが階段にいるとき");
// プレイヤーのいる階段を目的地にする
// ...
num = 0;
}
// 別のフロアにいるとき
else
{
Debug.Log("別のフロアにいるとき");
// エージェントが近い方の階段へ
if (Vector3.Distance(transform.position, stairPoints[0].position) <= 20f)
{
agent.destination = stairPoints[0].position;
}
else if (Vector3.Distance(transform.position, stairPoints[1].position) <= 20f)
{
agent.destination = stairPoints[1].position;
}
// 中間の位置にいるとき
else
{
// プレイヤーから近い方の階段へ
// ...
}
}
num++;
}
}
}
敵が階段にいるときは普通に目的地を設定しますが、プレイヤーが階段にいるときは、プレイヤーのスクリプトから、プレイヤーが現在いる階段を表す空のゲームオブジェクトを取得して、その位置を目的地に設定です。
別のフロアにいる場合、敵が2つあるどちらかの階段に近ければ、その階段にまず向かいます。どちらにも近くない中間の位置にいるときは、プレイヤーに近い方の階段を選択しました。
これで、同じフロアにいるとき以外は間隔を置いて目的地を更新するので、敵がスムーズに移動するようになりました。