I want to create a simulation with AI agents chopping down trees, then dropping off lumber.
I wrote a function to find the closest tree and go to it. But I am stuck on trying to figure out how I should know when the agent reched the specified tree.
Just to clarify, I know how to check if the agent reached it’s destination, but how do I check if he reached a tree? Maybe he reached his drop-off destination? I can’t trigger a function just because he reached a destination, I need to know WHICH destination he reached.
I set my destinations like so: navMeshAgent.SetDestination(target);
You should probably create a state machine for your AI controller. Then you will always be able to know exactly what state the AI is currently in (chopping down trees, dropping off lumber, idle etc.)
So if I understand this correctly, you want to have a separate state in your state machine for moving, instead of making the moving be one part of a state like ChopTree? And this is why you currently only know when an AI has reached a destination, but you don’t know why it was moving there in the first place. Well, you can make it work like this as well (sounds a bit strange though, unless I’m missing something here)…
You already have a function that finds a specific tree and orders your unit to start walking to it. You just need to cache a reference to the tree (and/or any other data that you need) in your unit when you send it moving towards it. Then when the NavMeshAgent has reached the current destination, you can let your other systems know that the destination has been reached, and pass the tree / any other needed data as arguments.
Here is a simple example demonstrating this. The MoveTo method can be used to tell the MoveController to move to a specific target. Once the target has been reached, a delegate will be invoked to inform your other systems.
public delegate void OnDestinationReachedCallback(AIUnit unit, Transform moveTarget);
public class MoveController : MonoBehaviour
{
public NavMeshAgent navMeshAgent;
public OnDestinationReachedCallback onDestinationReached;
public Transform nowMovingToTarget;
public void MoveTo(Transform moveTarget, OnDestinationReachedCallback onDestinationReachedListener)
{
nowMovingToTarget = moveTarget;
onDestinationReached += onDestinationReachedListener;
navMeshAgent.SetDestination(moveTarget.position);
}
private void Update()
{
if(nowMovingToTarget != null && HasDestinationBeenReached())
{
var moveTarget = nowMovingToTarget;
nowMovingToTarget = null;
if(onDestinationReached != null)
{
var callback = onDestinationReached;
onDestinationReached = null;
callback(this, moveTarget);
}
}
}
private bool HasDestinationBeenReached()
{
return navMeshAgent.isStopped;
}
}
Thanks for this example, this is what I had in mind as well. It would require me to rework some stuff since I only know the position of the object (I get it through a list storing object data, this list does not know what game object it belongs to since it’s save/load data).
Probably not a bad idea to keep a list of every gameobject in the game anyways, that I fill on load. Instead of just using lists of data only.