Issues with Movement Pack's nav mesh integration

cfc

New member
Hi there,

I ran into an issue with AI using the Seek task to pursue the player, where the AI agent will just freeze in its tracks if the player stands in certain spots. This appears to be due to some frustrating limitations in the Movement Pack's integration with Unity's NavMeshAgent for path finding. I don't think the nav mesh can be expected to perfectly represent everywhere the player can get to. For one thing, the NavMeshAgent pathing seems to have a tendency to leave characters stuck on corners, so it seems to be necessary to bake a nav mesh with some buffer, in which case just cozying up to a wall can move the player ever so slightly off the nav mesh. But even without that, there end up being places, like on top of crates or on top of railings, that the player can get to that the nav mesh won't extend to.

Now, I have some programming background, but I'm very new to game dev, AI, etc., so if I'm missing something obvious, please let me know. But it took about 2 minutes on Google to find that positions passed to Unity's NavMeshAgent first need to be verified to ensure they're on the nav mesh (they provide a method for that), and if it's an invalid position, there's another method to get the closest valid position on the NavMesh. I would think accounting for that would be a basic implementation requirement for any nav-mesh-based movement AI, but again, I'm new to this. Maybe I'm expected to handle that myself through the Behavior Tree before passing the position to Seek. Fine, I can do that. There's a bunch of NavMeshAgent tasks, surely they expose those crucial methods... Nope.

Okay, I can work around that too. Behavior Designer has reflection. I can call any method on anything. I'll just use the Get Component task to grab this character's NavMeshAgent... Except I need to reference a GameObject to do that, and unless I'm missing something – I must be!? – there's no way to fetch the GameObject attached to the Behavior Agent. (I realize you could manually assign it to a variable, but that won't work when spawning the character from a prefab.)

I've tried several workarounds, and at this point, I'm out of ideas. It seems like either I'm missing something obvious, I'm using NavMeshes wrong, or the Movement Pack left out a key piece of integrating with Unity's nav mesh system and I'm going to have to rewrite its movement tasks for use in production. Given the popularity of this asset, I'm assuming/hoping it's one of the first two.

What's my best path forward here?
 
The Movement Pack just sets the position and then it is up to the NavMeshAgent to do the actual movement - the Movement Pack doesn't do the actual movement. If your agent is getting stuck you should report the bug to Unity. If you post a video of it getting stuck I should have a better idea of what the cause is.

Okay, I can work around that too. Behavior Designer has reflection. I can call any method on anything. I'll just use the Get Component task to grab this character's NavMeshAgent... Except I need to reference a GameObject to do that, and unless I'm missing something – I must be!? – there's no way to fetch the GameObject attached to the Behavior Agent. (I realize you could manually assign it to a variable, but that won't work when spawning the character from a prefab.)
If you leave the target field blank then it will reference the current GameObject that it is attached to.
 
Hey, thanks for the response. It doesn't look like I can solve the issue through BD's reflection tasks, as validating a position with the NavMesh appears to be a static method, and I don't see a way to access that. So I guess I'll have to write my own position validation task.

I've also looked at the issue I'm running into with Seek a bit closer, and I still think Seek's behavior should be considered a bug. According to the docs, at least, the NavMeshAgent should be returning a true/false value from SetDestination, depending whether it was successful or not (which presumably it won't be if it's an invalid position?). I see in your code the NavMeshMovement wrapper's SetDestination is passing this along. However, Seek does nothing with the returned result.

Please correct me if I'm missing something here, but if SetDestination returns false, isn't it inaccurate for Seek to turn around and report a status of "Running" instead of a status of "Failed"?
 
Last edited:
I need to test this out but if SetDestination returns false doesn't the agent move to the closest position? In any case if you change Seek.OnUpdate to:

Code:
            return SetDestination(Target()) ? TaskStatus.Running : TaskStatus.Failure;

That should return failure when SetDestination returns false. I'll test this situation out.
 
After doing more precise isolated testing (which I probably should have done in the first place instead of testing in a complicated game environment), I see you are correct. When the player is off-mesh, the AI Seeks to the nearest point it can get to, and then the Seek task completes, which is exactly the behavior I would expect. I can only reliably reproduce the freezing in place I was experiencing if the player is on a section of navmesh that is disconnected from the rest of the navmesh. Weirdly, there are spots in my game environment where the same thing happens when the player appears to be just slightly off-mesh, so my best guess is that maybe it has to do with the player being off-mesh, the agent trying to find the closest valid destination, and ending up grabbing one that's on a disconnected piece of nav mesh? In any case, it's a very different problem than I first thought, and seems to fall more under the category of "using nav mesh wrong" than a Behavior Designer issue. I'll have to review my level design and see if these issues can be cleaned up. Thanks so much for helping me troubleshoot this.
 
Top