【Unity】敵の視界に入ったときだけ反応させたい!Vector3.Angleで実現する

angle.png

 つい先日、🔍NavMeshで敵キャラが自キャラを追跡するようにするというエントリーで、感知用コリジョンを使って「プレイヤーが一定距離に近づいたら敵が反応する」というロジックを紹介しました。感知用コリジョンに侵入したら問答無用で反応しますので、敵の背後から近づこうがお構いなしでした。
今度は敵に「視野」の概念を導入して、敵の視界に入ったら感知するという風に改造したいと思います。

感知用コリジョンのおさらい

考え方として、敵キャラの子オブジェクトとして配置した「感知用コリジョン」に接触したコリジョンの持ち主(この場合プレイヤー)を特定します。

●前回行った手順
・敵キャラの子オブジェクトとして「CollisionDetector」を追加
・CollisionDetectorにSphireColliderをアタッチ
・On Trigger Stayにオブジェクトと関数を指定

敵の感知用コリジョン(Sphire Collider)の範囲内に入ると、そのコリジョンにアタッチされている CollisionDetector.cs から EnemyMove.cs に処理が渡され、OnDetectObject関数によってプレイヤーを感知します。

EnemyMove.csの改造箇所

CollisionDetector.csEnemyMove.csへの橋渡しをするだけなので修正しません。改造箇所はEnemyMove.csのみです。
using UnityEngine;
using UnityEngine.AI;

[RequireComponent(typeof(NavMeshAgent))]
public class EnemyMove : MonoBehaviour
{
  [SerializeField] float searchAngle = 130f;
private NavMeshAgent _agent;

void Start()
{
_agent = GetComponent();
}

public void OnDetectObject(Collider collider)
{
// 検知オブジェクトがPlayerなら追いかける
if (collider.CompareTag("Player"))
{
  var positionDiff = collider.transform.position - transform.position; // 自身(敵)とプレイヤーの距離
  var angle = Vector3.Angle(transform.forward, positionDiff); // 敵から見たプレイヤーの方向
  if (angle <= searchAngle)
{
_agent.destination = collider.transform.position;
}
}
}
}
searchAngle が敵の視野になります。サンプルでは片側130度という指定ですので合計260度の視野になります。
angle が敵の正面から見たプレイヤーの角度です。正面にいる場合は0度ということになります。
angle が searchAngle(視野)の範囲内なら感知となります。


見やすくするために OnDrawGizmos() で色を付けました。

angle1.png

赤い範囲が敵の視界です。
画面右上のチンチクリンな物体がプレイヤーです。
近づいてみます。

angle2.png

敵のSphire Collisionの範囲中にStayしていますが、angle=180の位置にプレイヤーがいるため敵は反応しません。
画面手前側に回り込んでみます。

angle3.png

感知して襲ってきました。


以上となります。

さらに「視界から外れても1秒は追い続ける」「障害物に視線を遮られたら感知から外れる」「見失ったら元の位置に戻る」など様々な改善をすることで、さらにリアルで面白いゲームになっていくと思いますが、今回はここまでとします。


ゲームのアンテナ