完成イメージ
ホラーゲームのように、家の中を徘徊、プレイヤーを見つけ次第追いかけてくるようなイメージです。
実装
1.WindowのPackageManagerからAI navigatiionをインストール
2.Foortile(地面として使っているオブジェクト)にnav mesh surfaceをアタッチし、bakeを押します。ここで敵の行動できる範囲が青色で表示されるようになります。
3.敵オブジェクトにnav agentをアタッチし、回転速度や登れる角度を指定します。
4.敵が徘徊してほしいポイントを複数個の空のオブジェクトとして作成し、設置します。
5.敵に次のコードを実装します。goalsに4で作ったポイントを指定します。
public float movespeed;
public Rigidbody theRB;
public bool chasing;
public float distanceToChase = 10f, distanceToLose = 15f, distanceToStop = 2f;
private Vector3 targetPoint, startPoint;
public NavMeshAgent agent;
public Transform[] goals;
private int destNum = 0;
public float keepChasingTime = 5f;
public float chaseCounter;
private void Start()
{
startPoint = transform.position;
agent = GetComponent<NavMeshAgent>();
agent.destination = goals[destNum].position;
}
private void Update()
{
targetPoint = PlayerController.instance.transform.position;
targetPoint.y = transform.position.y;
if (!chasing)
{
if (Vector3.Distance(transform.position, targetPoint) < distanceToChase)
{
chasing = true;
}
if (chaseCounter > 0)
{
chaseCounter -= Time.deltaTime;
if (chaseCounter <= 0)
{
nextGoal();
}
}
if (agent.remainingDistance < 0.5f)
{
nextGoal();
//nextGoalを3.5秒後に呼び出す
//Invoke(nameof(nextGoal), 5.0f);
}
}
else
{
if (Vector3.Distance(transform.position, targetPoint) > distanceToStop)
{
agent.destination = targetPoint;
}
else
{
agent.destination = transform.position;
}
if (Vector3.Distance(transform.position, targetPoint) > distanceToLose)
{
chasing = false;
chaseCounter = keepChasingTime;
}
}
}
void nextGoal()
{
destNum = Random.Range(0, 9);
agent.destination = goals[destNum].position;
}
}
bool関数でplayerを追いかけているか判定を行い、追いかけているときとそうでない時で大きく処理を分けています。
詳しく見ていきます。
private void Start()
{
startPoint = transform.position;
agent = GetComponent<NavMeshAgent>();
agent.destination = goals[destNum].position;
}
まずStart関数内で敵の向かう位置というのを決めています。agentにさきほどつけたnav agentを指定し、その向かう先をのちに出てくるgoalの位置にしています。
update関数の中は次のようになっています
targetPoint = PlayerController.instance.transform.position;
targetPoint.y = transform.position.y;
まずは、Playerの場所を知るため、PlayerController(自分のplayerを操作しているscript)からpositionを取得し、それをターゲットとします。
if (!chasing)
{
if (Vector3.Distance(transform.position, targetPoint) < distanceToChase)
{
chasing = true;
}
if (chaseCounter > 0)
{
chaseCounter -= Time.deltaTime;
if (chaseCounter <= 0)
{
nextGoal();
}
}
if (agent.remainingDistance < 0.5f)
{
nextGoal();
}
}
追っていないときの処理です。指定した距離よりプレイヤーとの距離が小さくなったらchasingをonにします。また、指定したcounter(追いかける時間)が減っていきます。そしてこれが0より小さくなった時点であきらめてnextGoalを探しにいきます。また、nextGoalとの距離が0.5より小さくなった時点で次のnextGoalに向っていきます。追いかけていない時else以降はコードを読めばわかると思います。
続いてnextGoalの指定の仕方について、
void nextGoal()
{
destNum = Random.Range(0, 9);
agent.destination = goals[destNum].position;
}
今回は9個の探索ポイントを設けたためこの9からランダムで一つ数値を選び、goalの位置として指定しています。