I have a script for my NPC system, this script gets a random point from the path points on a navmesh and sets the agent’s destination as this point with the SetDestination() function.
Then when the agent reaches this point, the Idle animation is activated, a timer starts and after a certain amount of time a new random destination is set and the previous steps are repeated…
At least that’s how it SHOULD work, but the last step never happens. So when the agent stops, it doesn’t never move again. What could be the problem here?
Note: All points are on the Navmesh surface, no runtime errors occur.
- Agent Components
-
Debug.Logs On Play - First Destination
-
When the agent reaches it’s destination:
Timer works but when it elapsed nothing happens
- NPC Controller Script
NPCControllerRandomize.cs (5.6 KB)
public class NPCControllerRandomize : MonoBehaviour
{
private NavMeshAgent agent;
private Transform[] pathPoints;
private int index = 0;
private int minDistance = 6;
private float walkingAnimParameter = 0;
[SerializeField]
private GameObject path;
[Title("PathPoints only")]
[Required]
[SerializeField]
private Transform pathStartPoint;
[Required]
[SerializeField]
private Transform pathFinishPoint;
private System.Random random;
private static Timer timer;
private bool isTimerRunning = false;
private void Awake()
{
agent = GetComponent<NavMeshAgent>();
pathPoints = new Transform[path.transform.childCount];
random = new();
timer = new Timer(4000);
}
private void Start()
{
for (int i = 0; i < pathPoints.Length; i++)
{
pathPoints[i] = path.transform.GetChild(i);
}
timer.AutoReset = false;
timer.Elapsed += OnTimed;
SetNewDestination(); // Initial random target
Debug.Log(Vector3.Distance(transform.position, pathPoints[0].position));
Debug.Log(pathPoints.Length);
}
private void Update()
{
Roam();
SetStatusAnimationParameter();
}
private void Roam()
{
if (!agent.pathPending && agent.remainingDistance <= agent.stoppingDistance)
{
if (!agent.hasPath || agent.velocity.sqrMagnitude == 0f)
{
if (!isTimerRunning)
{
Debug.Log("Agent is stopped!");
timer.Start();
isTimerRunning = true;
agent.isStopped = true;
agent.velocity = Vector3.zero;
}
}
}
else if (agent.destination == pathFinishPoint.position)
{
if (agent.isStopped)
Destroy(agent);
}
}
private void SetNewDestination()
{
try
{
if (!agent.isOnNavMesh)
{
Debug.LogError("Agent is not on NavMesh!");
return;
}
Debug.Log("Agent is on NavMesh");
agent.ResetPath();
Debug.Log("Path reset");
agent.isStopped = false;
Debug.Log("Agent is started");
int randomNum = random.Next(0, pathPoints.Length - 1);
Debug.Log("Random number generated: " + randomNum);
var destination = agent.SetDestination(pathPoints[randomNum].position);
if (!destination)
{
Debug.Log("Invalid destination");
return;
}
Debug.Log("Destination set: " + pathPoints[randomNum].position);
isTimerRunning = false;
Debug.Log("Timer reset");
Debug.LogWarning("New destination is : " + agent.destination + " " + destination);
}
catch (Exception e)
{
Debug.LogError("Exception caught: " + e.Message);
}
}
private void OnTimed(object source, ElapsedEventArgs e)
{
Debug.Log("Time has finished.");
Invoke(nameof(SetNewDestination), 0.0f);
}
public float SetStatusAnimationParameter()
{
walkingAnimParameter = !agent.isStopped ? 1 : 0;
return walkingAnimParameter;
}
}
- NPC Animator:
NPCAnimator.cs (873 Bytes)
public class NPCAnimator : MonoBehaviour
{
private const string walkingParameterName = "vertical";
private Animator animator;
[Title("Choose one of the controllers:")]
[SerializeField]
private NPCControllerRandomize npcr;
// OR
[SerializeField]
private NPCController npc;
private void Awake()
{
animator = GetComponent<Animator>();
}
private void Update()
{
SetFloatParameter();
}
private void SetFloatParameter()
{
if (npc != null)
animator.SetFloat(walkingParameterName, npc.SetStatusAnimationParameter());
else
animator.SetFloat(walkingParameterName, npcr.SetStatusAnimationParameter());
}
}