Немного сложнее
using UnityEngine;
public class Enemy : MonoBehaviour
{
// скорость ходьбы и скорость поворота в секунду
public float moveSpeed = 2;
public float turnSpeed = 90;
// угол области видимости
public float visibleAreaAngle = 120;
// дистанция видимости
public float visibleAreaDistance = 15;
private CharacterController _controller;
private Transform _thisTransform;
private Transform _playerTransform;
private bool _isPursuit = false;
public void Start()
{
// Получаем контроллер
_controller = GetComponent<CharacterController>();
// Получаем компонент трансформации объекта, к которому привязан данный компонент
_thisTransform = transform;
// Получаем компонент трансформации игрока
Player player = (Player)FindObjectOfType(typeof(Player));
_playerTransform = player.transform;
}
// Все что связано с физикой выполняем в FixedUpdate
public void FixedUpdate()
{
// направление на игрока
Vector3 playerDirection = (_playerTransform.position - _thisTransform.position).normalized;
// если не преследуем
if (!_isPursuit)
{
// переменная для результата попадания
RaycastHit hit;
// луч
Ray ray = new Ray(transform.position, playerDirection);
// тест попадания луча
if (Physics.Raycast(ray, out hit))
{
// рисуем луч для дебага
Debug.DrawLine(ray.origin, hit.point, Color.yellow);
// если попали в игрока, то начинаем преследование
if (hit.collider.GetComponent<Player>() != null)
{
// половина угла видимости
var halfAngle = visibleAreaAngle / 2;
// если угол между направлением врага и направлением на игрока входит в область видимости
// то начинаем преследование
if (Vector3.Angle(transform.forward, playerDirection) <= halfAngle)
{
_isPursuit = true;
}
}
}
return;
}
// угол поворота на игрока
float angle = Vector3.Angle(_thisTransform.forward, playerDirection);
// максимальный угол поворота на текущем кадре
float maxAngle = turnSpeed * Time.deltaTime;
// Вычисляем прямой поворот на игрока
var playerDir = _playerTransform.position - _thisTransform.position;
playerDir.y = 0;
var rot = Quaternion.LookRotation(playerDir);
// поворачиваем врага на игрока с учетом скорости поворота
if (maxAngle < angle)
{
_thisTransform.rotation = Quaternion.Slerp(_thisTransform.rotation, rot, maxAngle / angle);
}
else
{
_thisTransform.rotation = rot;
}
// если дистанция до игрока больше трех метров
if (Vector3.Distance(_playerTransform.position, _thisTransform.position) > 3.0f)
{
// двигаемся к игроку
_controller.Move(_thisTransform.forward * moveSpeed * Time.deltaTime);
}
else // если меньше или равна трем метрам
{
// здесь например стреляем в игрока
}
// гравитация
_controller.Move(Vector3.down * 10.0f * Time.deltaTime);
}
// рисуем область видимости
public void OnDrawGizmos()
{
var halfAngle = visibleAreaAngle / 2;
var startDir = Quaternion.AngleAxis(-halfAngle, Vector3.up) * transform.forward;
var count = Mathf.Max(1, (int)visibleAreaAngle / 5);
var stepRotation = Quaternion.AngleAxis(visibleAreaAngle / count, Vector3.up);
Gizmos.color = new Color(0.5f, 0.5f, 0, 0.5f);
Gizmos.DrawLine(transform.position, transform.position + startDir * visibleAreaDistance);
var currentVector = startDir;
for (int i = 1; i <= count; i++)
{
var prevPos = transform.position + currentVector * visibleAreaDistance;
currentVector = stepRotation * currentVector;
var curPos = transform.position + currentVector * visibleAreaDistance;
Gizmos.DrawLine(transform.position, curPos);
Gizmos.DrawLine(prevPos, curPos);
}
}
}
Чтобы снизить немного нагрузку - надо тестировать видимость не каждый апдейт физики.