HasArrived() of the Seek block from the A* Pathfinding Pro integration never returns TaskStatus.Success

chris73it

Member
Please, check the two screenshots in the attachment to this post to get a better sense of the issue I describe below. Thank you.
The first screenshot shows the tree and the inspector of the Seek block, plus the window of the Global variables, while the second screenshot shows the game running with the zombie basically kissing the avatar while the tree insists that the Seek block is still running.

A long ago I put together the visual script in the picture using Behavior Designer and so far it has worked well: the Find block fills up Global/Avatar with a reference to the Avatar GameObject during bootstrap, then CanSeeObject looks for him, Seeks chases him, and finally Damage hurts him, then after a small delay, it all repeats itself. Currently, I have this visual script on a zombie NPC that tries to damage the avatar.

Today I decided that I needed to use NavMesh Cuts for the car, so I "ported" the navigation system from the builtin NavMesh in Unity to the A* Pathfinding Pro plugin, and I did all the necessary changes, including swapping the Seek block I have been using so far with the one from the A* Pathfinding Pro integration, and I noticed how the zombie keeps moving towards the avatar even after it has reached him and never reaches the Damage block. To be clear, the only block that has changed is the Seek one, while all the others are the same as before the "port".

After some debugging, I figured that OnUpdate of the Seek block never returns TaskStatus.Success:

public override TaskStatus OnUpdate()
{
if (HasArrived()) {
return TaskStatus.Success;
}

SetDestination(Target());

return TaskStatus.Running;
}

The reason is that HasArrived() never returns true:

protected override bool HasArrived()
{
return !agent.pathPending && (agent.reachedEndOfPath || !agent.hasPa th);
//return !agent.pathPending && (agent.reachedDestination || !agent.hasPath);
//return !agent.pathPending && (agent.remainingDistance < 0.85f || !agent.hasPath);
}

As you can see I tried a couple of workarounds, and the bottom one works for me (after establishing that the zombie always gets up to about 0.8f from the avatar) while the first workaround doesn't work, i.e. checking for reachedDestination produces the same result as checking for reachedEndOfPath.
Notice that even when the zombie is face to face with the avatar, the code keeps producing these logs:
Path Completed : Computation Time 0.00 ms Searched Nodes 2 Path Length 2
again and again, because clearly the Seek block doesn't think it has reached the avatar yet.

It seems to me that the current code in the Seek block for the A* Pathfinding integration currently only returns TaskStatus.Success if the position of the zombie is more or less identical to the one of the avatar, but as it is currently, this code will never work because both the zombie and the avatar have a capsule collider added by the Ultimate Character Controller wizard that prevents them from ever overlapping (that is a good thing, but still it seems to prevent TaskStatus.Success from being returned.)

What am I missing?

Any help is welcome.

Thank you, Chris
 

Attachments

  • Zombie-Seeks-And-Damages-Avatar-1.png
    Zombie-Seeks-And-Damages-Avatar-1.png
    600 KB · Views: 5
  • Zombie-Seeks-And-Damages-Avatar-2.png
    Zombie-Seeks-And-Damages-Avatar-2.png
    823.9 KB · Views: 5
Last edited:
Before the A* HasArrived method underwent some fine tuning last year there would be reports like this all of the time. Since then I haven't received any more of these type of reports so I'm curious why you are having problems.

Does the demo scene work correctly in a fresh project? If it does, are you able to get it to break?
 
Hi Justin,

I am using 2021.1.16f1: do you think the reason it fails is that the Unity version is too old? All the plugins I use have been updated to their latest versions.

I can make a fresh project with only the Ultimate CC, Behavior Designer, and the A* Pathfinding plugin in it and upload it to GitHub and share it with you: would that help? If so, please let me know what email ID I am supposed to use to share the repo with you.

FYI I made one more experiment. I reduced the radius of the capsule collider on both the avatar and the zombie from the default 0.4 to progressively smaller values to see whether it would help: 0.4 -> 0.2 -> 0.1 -> 0.01. The last value 0.01 (again, on both the avatar's and the zombie's capsule collider) sometimes works, but only once, i.e. the zombie damages the avatar once, and then never again, and it doesn't happen very consistently (maybe once every other time.)

Thank you, Chris
 
I am going to try the demo scene and let you know. In the meanwhile, can you let me know what parts you would like me to specifically test?
 
I would test with just the Movement Pack and Behavior Designer rather than introducing UCC into the mix. Using the demo scene you should be able to get the same results if it's related to the HasArrived method,
 
Hi Justin,

FYI I went through the entire UCC demo and it seems to work fine.

I built a simple scene with (see screenshots in attachment):
1. A 3x3 plane named Ground
2. An empty GameObject named A* with a Pathfinder component that was used to create a Recast Graph
3. One cube named Avatar
4. Another cube named Zombie with a Behavior Tree component, plus an AIRich and Seeker components

It worked the very first few times I ran it. Then it stopped working: Find would not find the GO named "Avatar". No reason why I could discern. I tried to delete and then recreate the global variable, reassign it, save everything and restart Unity, etc to no avail. This is not my first time noticing that Find stops working for no apparent reason, and usually, nothing fixes it other than recreating the Behavior from scratch. I think this is not related to the main issue (please, keep reading and you will understand why) but I figured I let you know.

I recreated an identical scene but it still doesn't work (all the screenshots refer to this one.) Now Find works again, but CanSeeObject fails. No reason why I can understand: it simply doesn't work. The CanSeeObject has never failed me before, but it is not the first time that a Behavior stops working for what appears - to my untrained eye - more or less random reasons. Another small thing, that I also think is unrelated to the main issue, but that I figured I let you know: sometimes it seems impossible to visualize the yellow cone associated with CanSeeObject, even if the GO with the Behavior Tree is selected in the Hierarchy, but then after some random clicking it reappears again (a Unity bug?)

Please, see the screenshots in the attachment and let me know if you need more.
 

Attachments

  • Astar-Inspector.png
    Astar-Inspector.png
    608.1 KB · Views: 3
  • Avatar-Inspector.png
    Avatar-Inspector.png
    506.4 KB · Views: 3
  • Zombie-Inspector.png
    Zombie-Inspector.png
    568.7 KB · Views: 3
Last edited:
3 more screenshots
 

Attachments

  • Zombie-BDInspector-CanSeeObject.png
    Zombie-BDInspector-CanSeeObject.png
    549.1 KB · Views: 3
  • Zombie-BDInspector-Find-plus-GlobalVariable.png
    Zombie-BDInspector-Find-plus-GlobalVariable.png
    558.9 KB · Views: 3
  • Ground-Inspector.png
    Ground-Inspector.png
    513.1 KB · Views: 3
Last 2 screenshots.
 

Attachments

  • Zombie-BDInspector-Seek.png
    Zombie-BDInspector-Seek.png
    556.3 KB · Views: 3
  • Zombie-BDInspector-Sequence.png
    Zombie-BDInspector-Sequence.png
    549.1 KB · Views: 3
With Can See Object you can enable the debug ray and see why it's failing. The page below lists what the different colors mean.

 
Hi Justin,

When the field of view is shorter than the distance between the center of the two cubes, the debug line is red ("The target is not within the field of view of the agent.")
When I extend it to be long enough, it becomes yellow ("Another object is blocking the target") which puzzles me, because - as you can see from the screenshots - there is nothing "solid" between the two.

A curiosity of mine. What is the difference between:
Magenta: The target is too far away from the agent.
and:
Red: The target is not within the field of view of the agent.
To me they sound about the same: is there any subtle difference?

One small suggestion: make the debug line a different shade of yellow, so it becomes easier to tell apart from the yellow cone of the field of view: for instance, if it were orange, one wouldn't need to tweak the y offsets to separate them. Even though, in theory, if the yellow line is not visible, one could infer that it must be yellow, it is better to actually see that "it is there." My 2 cents.
 

Attachments

  • FOV-Too-Short.png
    FOV-Too-Short.png
    641.3 KB · Views: 4
  • FOV-Long-Enough.png
    FOV-Long-Enough.png
    591.2 KB · Views: 3
Last edited:
FYI
All of the above posts of mine refer to version 2021.1.16f1 because it is the version I have to develop my current project for.

As a curiouity, I tried to do the same thing in 2021.2.16f1 and everything seems to work fine. I used the same versions of the A* Pathfinder and the Behavior Designer plugins, but somehow the Unity version seems to affect the outcome of whether CanSeeObject and Seek (from the A* integration) work properly. I hope this helps. Please, let me know if you need more information.
 
When I extend it to be long enough, it becomes yellow ("Another object is blocking the target") which puzzles me, because - as you can see from the screenshots - there is nothing "solid" between the two.
You could place a breakpoint within the MovementUtility line of check method to determine what object is in the way. Unfortunately there's not a way to visualize that though I could see doing something like highlighting it in the editor.

Magenta: The target is too far away from the agent.
and:
Red: The target is not within the field of view of the agent.
Yes, there is a difference. If the target is too far away then the raycast won't hit the target and you need to increase the distance. If it's not within the field of view then the angle is off and you need to increase the field of view threshold.


One small suggestion: make the debug line a different shade of yellow, so it becomes easier to tell apart from the yellow cone of the field of view: for instance, if it were orange, one wouldn't need to tweak the y offsets to separate them. Even though, in theory, if the yellow line is not visible, one could infer that it must be yellow, it is better to actually see that "it is there." My 2 cents.
Thanks for the suggestion :)
 
Hi Justin,

I was able to make both versions work.
I had the idea of running both versions side by side and seeing what differences could possibly cause one to work but not the other: the version that didn't work (2021.1.16f1) had a box collider component on the cube representing the zombie: once that was eliminated, everything worked.
Unfortunately, that doesn't make any sense to me: do you know why the presence of a collider would cause the zombie to fail to see the avatar and claim that the reason is that there is something in between them?

One more thing.
I have noticed that when the zombie can finally see the avatar and starts Seek-ing it, it will not turn towards the avatar, i.e. it is as if the zombie started moving from left to right to reach the avatar but did so without adjusting its y-rotation on its way to its destination.
This fact in turn may cause the zombie to immediately go to Idle immediately after having reached the avatar and having executed the Wait block only once.
Basically, because the zombie keeps looking to the right (is this a case of a stiff neck?!) a FOV of 90 degrees will fail to see the avatar once the zombie is too close to it and will have the Sequence block fail, resulting in the Idle block being executed.
This is not the behavior I was hoping for, because when I use the UCC I would have a Damage block between the Seek and the Wait blocks that take 1% health from the player after every second of contact between the zombie and the avatar, instead of as it stands right now, taking only 1% and that's it.
I have verified that if the FOV is increased from the current 90 degrees to 158. the CanSeeObject block keeps returning success and the zombie never enters the Idle state.
I have attached 3 screenshots to show when the zombie starts Seek-ing the avatar, and when it reaches the avatar in one case with a FOV of 90 and the other with an FOV of 158: from these you can see the effects on the behavior tree I explained above.

Now, comparing the two Seek blocks, the one from the Movement pack and the one from the A* integration, I noticed that the latter is missing an Angular Speed property: would it be possible to add it, so that, while using the A* plugin, an agent Seek-ing something would also turn towards it as it does in the default Navmesh Seek-ing?
Another property that the A*'s Seek block misses is the Arrive Distance: I am not sure if it would be really useful, but it looks like it might as well.

Now, I see that there is a Rotate Towards block in the movement pack, but because Seek is synchronous, i.e. it monopolized the tree until it succeeds, there is no way to use it progressively in each frame. Do you have a suggestion on how to make the zombie turn towards the avatar while Seek-ing it?

Finally, there is still the initial outstanding issue that when the UCC is involved, the default radius of both the avatar and the zombie is 0.4, which means their relative distance is never less than 0.8 even when they are grazing each other, effectively preventing the Seek block from ever returning success. Even a work-around would do.
 

Attachments

  • Zombie-Starts-Seeking-The-Avatar.png
    Zombie-Starts-Seeking-The-Avatar.png
    554.2 KB · Views: 0
  • Zombie-Reaches-Avatar-Without-Y-Turning.png
    Zombie-Reaches-Avatar-Without-Y-Turning.png
    575.6 KB · Views: 0
  • Zombie-Keeps-Seeing-The-Avatar-When-FOV-IS-158.png
    Zombie-Keeps-Seeing-The-Avatar-When-FOV-IS-158.png
    639.5 KB · Views: 0
Last edited:
Since 2021.1.16f1 was now working for me, I decided to reintroduce the UCC: now both the zombie and the avatar use a character from the Apocalypse Synty series.

Initially, it wasn't working too well: if the avatar didn't move, the zombie would behave correctly and after reaching the avatar would keep Damage-ing it, but if the avatar would move from its initial position, the zombie would keep Seek-ing it and never get to the Damage block.

At this point, I started playing with the values of the A* Pathfinder component, but I couldn't get consistent results until I noticed the Character Radius property: this is set to 1.5 by default, and its tooltip says "Radius of the character. It is good to add some margin [...]"

That gave me an idea.
I had already noticed that the zombie would stop somewhat far from the avatar if the avatar did not move at all after bootstrapping the game, whereas if the avatar would start escaping and then stopped, the zombie would get really really close to the avatar, but - paradoxically - in such case, it would usually keep Seek-ing it, so I thought that maybe it was good to try to do something to keep the zombie at some distance from the avatar at all time, and so I added a Navmesh Cut component to the avatar.
Unfortunately, that didn't seem to work initially, but then I noticed that the default radius of the Circular cut is 1, so I increased it to 1.5, and now it is pretty solid, i.e. even when the avatar escapes, and then waits to be bitten by the zombie, it always gets Damage-d (and keep being Damage-d!) by the zombie.

This is good. Someone should really document the need for a circular Navmesh Cut around the target of the Seek block. For instance, it could be a suggestion given here: https://opsive.com/support/document...oller/integrations/astar-pathfinding-project/

One more thing: it used to be that the "Astar AI Agent Movement ability" could be in any position, but now it won't work, and indeed a Warning is produced by UCC asking to move this ability above the Move TOwards ability: when I did it, the zombie started walking again. My suggestion would be to update the integration pager (same URL as the above) because it still claims that any position is fine. My 2 cents.

Thank you for the support.
 
Top