Here is my solution to Spreading the Load:
Summary
I look for a random point to hide using various nested coroutines.
These points are created in a list of hiding places from the ever increasing loop Sam gave us.
In creating this list I wait a frame before checking the next one.
Code
This text will be hidden
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class HideAI : MonoBehaviour
{
[SerializeField] float timeBetweenChecks = 1;
[SerializeField] float minRemainingDistance = 1;
List<Vector3> filteredPoints = new List<Vector3>();
Vector3 newPoint;
FirstPersonMover player;
NavMeshAgent agent;
void Awake()
{
player = FindObjectOfType<FirstPersonMover>();
}
IEnumerator Start()
{
agent = GetComponent<NavMeshAgent>();
while (true)
{
yield return GetRandomFilteredPoint(1, 100);
agent.SetDestination(newPoint);
yield return new WaitUntil(() => !NavMeshAgentIsMoving());
yield return new WaitUntil(() => CanBeSeenByPlayer(transform.position));
}
}
IEnumerator GetRandomFilteredPoint(float interval, float maxDistance)
{
yield return FindFilteredPoints(interval, maxDistance);
newPoint = filteredPoints[UnityEngine.Random.Range(0, filteredPoints.Count)];
}
IEnumerator FindFilteredPoints(float interval, float maxDistance)
{
filteredPoints.Clear();
Vector3 location = transform.position;
for (float distance = interval; distance < maxDistance; distance += interval)
{
Vector2 randomCircle = Random.insideUnitCircle * distance;
Vector3 randomOffset = new Vector3(randomCircle.x, 0, randomCircle.y);
var point = location + randomOffset;
if (NavMesh.SamplePosition(point, out NavMeshHit hit, 10, NavMesh.AllAreas))
{
if (!CanBeSeenByPlayer(hit.position)) filteredPoints.Add(location + randomOffset);//TODO add point
}
yield return null;
}
if (filteredPoints.Count == 0)
{
filteredPoints.Add(Vector3.zero);
}
}
bool NavMeshAgentIsMoving()
{
//print($"{agent.pathPending} {agent.pathStatus} {agent.remainingDistance > 0} {agent.remainingDistance} ");
if (agent.pathPending) return true;
if (agent.pathStatus != NavMeshPathStatus.PathComplete) return false;
return agent.remainingDistance > minRemainingDistance;
}
bool CanBeSeenByPlayer(Vector3 point)
{
Vector3 direction = point - player.transform.position;
float distance = direction.magnitude;
if (Physics.Raycast(player.transform.position, direction, distance))
{
return false;
}
return true;
}
}