I have a NavMesh agent that wanders around every x seconds, moves to a random position, and lastly it repeats the sequence. I made a test using a coroutine, which was called through a context menu method.
However, when I reimplemented the logic in a behavior tree, the random point was only generated the first time. In the following turns of the sequence, the random point was always the same. I'm using this library, called Fluid Behavior Tree. I'm really not sure what's wrong, since the logic from the coroutine and the logic from the nodes of the tree is quite literally the same.
The code from the Coroutine:
CheckForSafeDestinationPoint(); // Caculates the random point and sets it as the destination of the agent
// wait until the path is ready
while (agent.pathPending)
{
yield return null;
}
if (agent.pathStatus == NavMeshPathStatus.PathComplete)
{
Debug.Log("Path is valid");
agent.isStopped = false;
while (agent.GetPathRemainingDistance() > agent.stoppingDistance)
{
// Wait until the agent reaches its destination
Debug.Log("Wandering");
yield return null;
}
}
yield break;
The code from the node of the tree (a leaf node called AgentDestination):
protected override void OnStart()
{
// Literally the same as CheckForSafeDestinationPoint(), with the exception that the random point (the Destination) is first calculated on the parent tree a passed as a parameter to this node
SetDestinationPoint(Destination);
}
// This code is executed on the Update method
protected override TaskStatus OnUpdate()
{
while (agent.pathPending)
{
return TaskStatus.Continue;
}
if (agent.pathStatus == NavMeshPathStatus.PathComplete)
{
agent.isStopped = false;
if (agent.GetPathRemainingDistance() > agent.stoppingDistance)
{
// This is the equivalent of yield return null
return TaskStatus.Continue;
}
}
// Once the node succeeded, the tree leaves this node
return TaskStatus.Success;
}
The previous logic is later implemented trough the tree:
void Awake()
{
agent = GetComponent<NavMeshAgent>();
tree = new BehaviorTreeBuilder(gameObject)
.Sequence()
.Wait(waitTicks)
// Here we pass in the random calculated point as a parameter
.AgentDestination("RandomDestination", ComputeRandomDestination())
.End()
.Build();
}
void Update()
{
tree.Tick();
}
I have my theories, though I'm not entirely sure about them. First, I think that every time I call the coroutine, a new instance is created, thus creating with it a new random point, as expected. However, I may be confusing the instance creating with the string-based call of the coroutine. Since the tree is created on the Awake() method, the ComputeRandomDestination may be getting cached somehow. However, I think this doesn't make a lot of sense since the agent can follow a moving target, which means that it can calculate a new path every frame, so in theory, it should be capable of calculating a random point more than once, right?
Anyway, point is, I have no idea what's wrong. All I know is that the leaf node AgentDestination is, after the first turn, always going to the same spot. It's not calculating a new random point. The node is in fact exiting, so it seems that it's working as expected.
AgentDestination
is notComputeRandomDestination
itself but the return value after calling it once. \$\endgroup\$Awake()
, and save the result value in the behavior tree and won't be called again. Maybe you should putComputeRandomDestination()
intoOnStart()
ofAgentDestination
. \$\endgroup\$Awake()
theory was right. It works now. Many, many thanks! \$\endgroup\$