Задача такая - объект Враг патрулирует по списку точек с координатами. Это задается с помощью вызова корутины FollowPath.
Помимо этого по полю перемещается другой объект Player. Когда враг видит player - он должен начать преследовать его, тут я подключаю NavMesh, но после того как враг теряет player из виду он должен вернуться исполнению скрипта в корутине, т.е. патрулированию.
У меня он перестает двигаться, после того как дойдёт до точки в которой последний раз видел player.
Как я понимаю корутина в данном случае запускается из метода Start и поэтому только один раз проходит.
Синтаксис:
Используется csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class Guard : MonoBehaviour
{
public static event System.Action OnGuardHasSpottedPlayer;
public float speed = 5f;
public float waitTime = .3f;
public float turnSpeed = 90;
public float timeToSpotPlayer = 1f;
public Light spotlight;
public float viewDistance;
public LayerMask viewMask;
float viewAngle;
float playerVisibleTimer;
public Transform pathHolder;
Transform player;
Color originalSpotLightColour;
public Transform MyPlayer;
private NavMeshAgent myAgent;
private bool corout;
void Start()
{
myAgent = GetComponent<NavMeshAgent>();
player = GameObject.FindGameObjectWithTag("Player").transform;
viewAngle = spotlight.spotAngle;
originalSpotLightColour = spotlight.color;
Vector3[] waypoints = new Vector3[pathHolder.childCount];
for (int i = 0; i < waypoints.Length; i++)
{
waypoints[i] = pathHolder.GetChild(i).position;
waypoints[i] = new Vector3(waypoints[i].x, transform.position.y, waypoints[i].z);
}
StartCoroutine(FollowPath(waypoints));
}
private void Update()
{
if (CanSeePlayer())
{
playerVisibleTimer += Time.deltaTime;
}
else
{
playerVisibleTimer -= Time.deltaTime;
}
spotlight.color = Color.Lerp(originalSpotLightColour, Color.red, playerVisibleTimer / timeToSpotPlayer);
playerVisibleTimer = Mathf.Clamp(playerVisibleTimer, 0, timeToSpotPlayer);
if (playerVisibleTimer >= timeToSpotPlayer)
{
if (OnGuardHasSpottedPlayer != null)
{
OnGuardHasSpottedPlayer();
}
//myAgent.SetDestination (MyPlayer.transform.position);
}
}
bool CanSeePlayer()
{
if (Vector3.Distance(transform.position, player.position) < viewDistance)
{
Vector3 dirToPlayer = (player.position - transform.position).normalized;
float angleBetweenGuardAndPlayer = Vector3.Angle(transform.forward, dirToPlayer);
if (angleBetweenGuardAndPlayer < viewAngle / 2f)
{
if (!Physics.Linecast(transform.position, player.position, viewMask))
{
return true;
}
}
}
return false;
}
private IEnumerator FollowPath(Vector3[] waypoints)
{
transform.position = waypoints[0];
int targetWaypointIndex = 1;
Vector3 targetWaypoint = waypoints[targetWaypointIndex];
transform.LookAt(targetWaypoint);
while (true)
{
transform.position = Vector3.MoveTowards(transform.position, targetWaypoint, speed * Time.deltaTime);
if (transform.position == targetWaypoint)
{
targetWaypointIndex = (targetWaypointIndex + 1) % waypoints.Length;
targetWaypoint = waypoints[targetWaypointIndex];
yield return new WaitForSeconds(waitTime);
yield return StartCoroutine(TurnToFace(targetWaypoint));
}
yield return null;
}
}
private IEnumerator TurnToFace(Vector3 lookTarget)
{
Vector3 dirToLookTarget = (lookTarget - transform.position).normalized;
float targetAngle = 90 - Mathf.Atan2(dirToLookTarget.z, dirToLookTarget.x) * Mathf.Rad2Deg;
while (Mathf.Abs(Mathf.DeltaAngle(transform.eulerAngles.y, targetAngle)) > 0.05f)
{
float angle = Mathf.MoveTowardsAngle(transform.eulerAngles.y, targetAngle, turnSpeed * Time.deltaTime);
transform.eulerAngles = Vector3.up * angle;
yield return null;
}
}
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class Guard : MonoBehaviour
{
public static event System.Action OnGuardHasSpottedPlayer;
public float speed = 5f;
public float waitTime = .3f;
public float turnSpeed = 90;
public float timeToSpotPlayer = 1f;
public Light spotlight;
public float viewDistance;
public LayerMask viewMask;
float viewAngle;
float playerVisibleTimer;
public Transform pathHolder;
Transform player;
Color originalSpotLightColour;
public Transform MyPlayer;
private NavMeshAgent myAgent;
private bool corout;
void Start()
{
myAgent = GetComponent<NavMeshAgent>();
player = GameObject.FindGameObjectWithTag("Player").transform;
viewAngle = spotlight.spotAngle;
originalSpotLightColour = spotlight.color;
Vector3[] waypoints = new Vector3[pathHolder.childCount];
for (int i = 0; i < waypoints.Length; i++)
{
waypoints[i] = pathHolder.GetChild(i).position;
waypoints[i] = new Vector3(waypoints[i].x, transform.position.y, waypoints[i].z);
}
StartCoroutine(FollowPath(waypoints));
}
private void Update()
{
if (CanSeePlayer())
{
playerVisibleTimer += Time.deltaTime;
}
else
{
playerVisibleTimer -= Time.deltaTime;
}
spotlight.color = Color.Lerp(originalSpotLightColour, Color.red, playerVisibleTimer / timeToSpotPlayer);
playerVisibleTimer = Mathf.Clamp(playerVisibleTimer, 0, timeToSpotPlayer);
if (playerVisibleTimer >= timeToSpotPlayer)
{
if (OnGuardHasSpottedPlayer != null)
{
OnGuardHasSpottedPlayer();
}
//myAgent.SetDestination (MyPlayer.transform.position);
}
}
bool CanSeePlayer()
{
if (Vector3.Distance(transform.position, player.position) < viewDistance)
{
Vector3 dirToPlayer = (player.position - transform.position).normalized;
float angleBetweenGuardAndPlayer = Vector3.Angle(transform.forward, dirToPlayer);
if (angleBetweenGuardAndPlayer < viewAngle / 2f)
{
if (!Physics.Linecast(transform.position, player.position, viewMask))
{
return true;
}
}
}
return false;
}
private IEnumerator FollowPath(Vector3[] waypoints)
{
transform.position = waypoints[0];
int targetWaypointIndex = 1;
Vector3 targetWaypoint = waypoints[targetWaypointIndex];
transform.LookAt(targetWaypoint);
while (true)
{
transform.position = Vector3.MoveTowards(transform.position, targetWaypoint, speed * Time.deltaTime);
if (transform.position == targetWaypoint)
{
targetWaypointIndex = (targetWaypointIndex + 1) % waypoints.Length;
targetWaypoint = waypoints[targetWaypointIndex];
yield return new WaitForSeconds(waitTime);
yield return StartCoroutine(TurnToFace(targetWaypoint));
}
yield return null;
}
}
private IEnumerator TurnToFace(Vector3 lookTarget)
{
Vector3 dirToLookTarget = (lookTarget - transform.position).normalized;
float targetAngle = 90 - Mathf.Atan2(dirToLookTarget.z, dirToLookTarget.x) * Mathf.Rad2Deg;
while (Mathf.Abs(Mathf.DeltaAngle(transform.eulerAngles.y, targetAngle)) > 0.05f)
{
float angle = Mathf.MoveTowardsAngle(transform.eulerAngles.y, targetAngle, turnSpeed * Time.deltaTime);
transform.eulerAngles = Vector3.up * angle;
yield return null;
}
}