Issues with The Movement Pack and its Integration

JohnnyRobert

New member
Hello,

I have two agents, one is chasing the other, the agent being chased will always end up raycasting outside any generated navmesh, causing it to get stuck in the corners if the map/level is enclosed between 4 walls. This happens no matter what pathfinding algorithm is being used and no matter what navmesh generator solution is being used, being it Unity's or A* Project. I think the issue is caused by the code inside the "Evade" and "Flee" tasks and I haven't tested the wander task that much yet but I do have a feeling that all the tasks in this pack have the exact same issue.

My setup is as simple as it can get: I have a terrain of 50x50 enclosed by 4 walls and by another wall at the top and I have two entities inside the room, with one entity chasing the other. What happens after a while is at some point when the chaser gets close to the agent being chased and they're near a corner the chaser raycasts outside the navmesh and of course tries running through the corner and gets stuck there in the corner and it doesn't throw another raycast once that happens.

I've tried everything from switching up the pathfinding algorithms to switching the navemesh itself, the graph type and played with the settings of the tasks and of the nave mesh agent, it's also pretty complicated to understand exactly what is causing this issue.

I am no coder but I've managed to modify the evade task a bit with some help and the raycasting issue disappeared, it's just that now the chased entity is running in a circle around the chaser after a while and I don't know how to fix that because again I am not a coder but if it wasn't the movement tasks themselves the root of the issue then modifying their code should've have no impact on fixing the issue with the raycasts.

I've tried everything from putting stuff on different layers to switching up the pathfinders and changing the settings in the nodes themselves; I think it's the way these tasks are choosing to generate the waypoints.

Please let me know what to do to fix this issue, I can also share my project.
 

Attachments

  • Screenshot at Dec 30 22-25-12.png
    Screenshot at Dec 30 22-25-12.png
    135.6 KB · Views: 3
Last edited:
Moving this to the Behavior Designer board.

In order to handle this situation when the evade or flee task fails you could set a shorter lookAheadDistance that the task should move to. I actually think that the task failing when a destination can't be found is the correct solution - if the agent were to move in the other direction then the task would no longer be evading. While this can be correctly handled within the behavior tree I do think that it would be useful to have a range that the task selects and it progressively tests closer ranges. This would be fairly trivial to do - within the evade task you'd have something like below:

Code:
        [Tooltip("The agent has evaded when the magnitude is greater than this value")]
        public SharedFloat evadeDistance = 10;
        [Tooltip("The distance to look ahead when evading")]
        public SharedFloat lookAheadDistance = 5;
        [Tooltip("How far to predict the distance ahead of the target. Lower values indicate less distance should be predicated")]
        public SharedFloat targetDistPrediction = 20;
        [Tooltip("Multiplier for predicting the look ahead distance")]
        public SharedFloat targetDistPredictionMult = 20;
        [Tooltip("The GameObject that the agent is evading")]
        public SharedGameObject target;
        public int maxInterations = 1;

        // The position of the target at the last frame
        private Vector3 targetPosition;

        public override void OnStart()
        {
            base.OnStart();

            targetPosition = target.Value.transform.position;
            if (maxInterations == 0) {
                Debug.LogWarning("Error: Max iterations must be greater than 0");
                maxInterations = 1;
            }
            SetDestination(Target(0));
        }

        // Evade from the target. Return success once the agent has fleed the target by moving far enough away from it
        // Return running if the agent is still fleeing
        public override TaskStatus OnUpdate()
        {
            if (Vector3.Magnitude(transform.position - target.Value.transform.position) > evadeDistance.Value) {
                return TaskStatus.Success;
            }

            var interation = 0;
            while (!SetDestination(Target(interation)) && interation < maxInterations - 1) {
                interation++;
            }

            return TaskStatus.Running;
        }

        // Evade in the opposite direction
        private Vector3 Target(int iteration)
        {
            // Calculate the current distance to the target and the current speed
            var distance = (target.Value.transform.position - transform.position).magnitude;
            var speed = Velocity().magnitude;

            float futurePrediction = 0;
            // Set the future prediction to max prediction if the speed is too small to give an accurate prediction
            if (speed <= distance / targetDistPrediction.Value) {
                futurePrediction = targetDistPrediction.Value;
            } else {
                futurePrediction = (distance / speed) * targetDistPredictionMult.Value; // the prediction should be accurate enough
            }

            // Predict the future by taking the velocity of the target and multiply it by the future prediction
            var prevTargetPosition = targetPosition;
            targetPosition = target.Value.transform.position;
            var position = targetPosition + (targetPosition - prevTargetPosition) * futurePrediction;

            return transform.position + (transform.position - position).normalized * lookAheadDistance.Value * ((maxInterations - iteration) / maxInterations);
        }

With that said, evade will only evade following a straight line. If the agent is stuck in a corner or something like that then evade will fail and this is the correct behavior. If evade fails then you should run another task within the behavior tree, such as wander with a wide radius.
 
Moving this to the Behavior Designer board.

In order to handle this situation when the evade or flee task fails you could set a shorter lookAheadDistance that the task should move to. I actually think that the task failing when a destination can't be found is the correct solution - if the agent were to move in the other direction then the task would no longer be evading. While this can be correctly handled within the behavior tree I do think that it would be useful to have a range that the task selects and it progressively tests closer ranges. This would be fairly trivial to do - within the evade task you'd have something like below:

Code:
        [Tooltip("The agent has evaded when the magnitude is greater than this value")]
        public SharedFloat evadeDistance = 10;
        [Tooltip("The distance to look ahead when evading")]
        public SharedFloat lookAheadDistance = 5;
        [Tooltip("How far to predict the distance ahead of the target. Lower values indicate less distance should be predicated")]
        public SharedFloat targetDistPrediction = 20;
        [Tooltip("Multiplier for predicting the look ahead distance")]
        public SharedFloat targetDistPredictionMult = 20;
        [Tooltip("The GameObject that the agent is evading")]
        public SharedGameObject target;
        public int maxInterations = 1;

        // The position of the target at the last frame
        private Vector3 targetPosition;

        public override void OnStart()
        {
            base.OnStart();

            targetPosition = target.Value.transform.position;
            if (maxInterations == 0) {
                Debug.LogWarning("Error: Max iterations must be greater than 0");
                maxInterations = 1;
            }
            SetDestination(Target(0));
        }

        // Evade from the target. Return success once the agent has fleed the target by moving far enough away from it
        // Return running if the agent is still fleeing
        public override TaskStatus OnUpdate()
        {
            if (Vector3.Magnitude(transform.position - target.Value.transform.position) > evadeDistance.Value) {
                return TaskStatus.Success;
            }

            var interation = 0;
            while (!SetDestination(Target(interation)) && interation < maxInterations - 1) {
                interation++;
            }

            return TaskStatus.Running;
        }

        // Evade in the opposite direction
        private Vector3 Target(int iteration)
        {
            // Calculate the current distance to the target and the current speed
            var distance = (target.Value.transform.position - transform.position).magnitude;
            var speed = Velocity().magnitude;

            float futurePrediction = 0;
            // Set the future prediction to max prediction if the speed is too small to give an accurate prediction
            if (speed <= distance / targetDistPrediction.Value) {
                futurePrediction = targetDistPrediction.Value;
            } else {
                futurePrediction = (distance / speed) * targetDistPredictionMult.Value; // the prediction should be accurate enough
            }

            // Predict the future by taking the velocity of the target and multiply it by the future prediction
            var prevTargetPosition = targetPosition;
            targetPosition = target.Value.transform.position;
            var position = targetPosition + (targetPosition - prevTargetPosition) * futurePrediction;

            return transform.position + (transform.position - position).normalized * lookAheadDistance.Value * ((maxInterations - iteration) / maxInterations);
        }

With that said, evade will only evade following a straight line. If the agent is stuck in a corner or something like that then evade will fail and this is the correct behavior. If evade fails then you should run another task within the behavior tree, such as wander with a wide radius.
I tried your code, but the AI still gets stuck in the corners.
 
I tried your code, but the AI still gets stuck in the corners.
It's been a while, can't test it right now but I think this was the script in which I solved it. However you may experience a more "circling" outcome but it does go around the issue, if this is the correct script. Play around with the values in the fields until it works in your case, i think that's what I've done as it may need a bit of calibration.
 

Attachments

  • EvadePredators.cs
    5.4 KB · Views: 3
  • Like
Reactions: EVG
It's been a while, can't test it right now but I think this was the script in which I solved it. However you may experience a more "circling" outcome but it does go around the issue, if this is the correct script. Play around with the values in the fields until it works in your case, i think that's what I've done as it may need a bit of calibration.
Thanks, I'll try
 
It's been a while, can't test it right now but I think this was the script in which I solved it. However you may experience a more "circling" outcome but it does go around the issue, if this is the correct script. Play around with the values in the fields until it works in your case, i think that's what I've done as it may need a bit of calibration.
I just noticed that the code is for NavMesh, and I use A*
I use Flee
 
Last edited:
I just noticed that the code is for NavMesh, and I use A*
I use Flee
Perhaps someone here will be able to help, I used Chat GPT to make that script so you may give that a try too, maybe it can modify it for you to work for A*. I would help you but I am a beginner as well.
 
@Justin, hello, please tell me if this bug will be officially fixed? Or how to fix it now? I am using Flee component in A* implementation
 
The A* version doesn't have the changes in the post above. You'll need to make similar changes for now. I will be releasing an update to the Movement Pack soon and will also make a similar change.

Regardless it's not going to fix all cases. Evade will only in a straight line away from the target. If A* returns that it's an invalid destination then the task will fail and you'll need to handle it some other way.
 
The A* version doesn't have the changes in the post above. You'll need to make similar changes for now. I will be releasing an update to the Movement Pack soon and will also make a similar change.

Regardless it's not going to fix all cases. Evade will only in a straight line away from the target. If A* returns that it's an invalid destination then the task will fail and you'll need to handle it some other way.
Thanks for the reply, but I don't understand what exactly needs to be fixed. When will the official update be released?
 
The change above adds different iterations to the navmesh version of evade. The same thing needs to be done for the A* version. I don't have an ETA of the next update but it should be soon.
 
I don’t know if this is the correct solution (most likely not), but I added these lines in the OnUpdate method:
C#:
if (agent.reachedEndOfPath)
    return TaskStatus.Failure;
else
    return TaskStatus.Running;
AI no longer gets stuck on corners.
 
I changed my code a little more and now the OnUpdate() method looks like this:
C#:
        public override TaskStatus OnUpdate()
        {
            if (Vector3.Magnitude(transform.position - target.Value.transform.position) > fleedDistance.Value)
            {
                return TaskStatus.Success;
            }

            SetDestination(Target());

            if (agent.reachedEndOfPath)
            {
                GameObject newTarget = new GameObject();
                newTarget.transform.position = agent.position;
                target.Value = newTarget;
            }
            return TaskStatus.Running;
        }
Now, when the agent gets stuck on the corners, he runs in the opposite direction from himself.
Can you please tell me @Justin how this solution is correct?
 
If that works for your project then I'd go with it. The only thing that I notice is that you are creating a new target every time the end of the path is reached and I would change that so it doesn't keep instantiating new GameObjects.
 
Edit: Apologies, I see this thread is about Flee and Evade. Regardless, this may be helpful for those getting stuck in walls and corners. :)

I had the same issue. I consulted the A* Pathfinding Project wander recommendations and took those into consideration. Below is a rather naive override to `BehaviorDesigner.Runtime.Tasks.Movement.AstarPathfindingProject.Wander` but it solves the issue of getting stuck by checking valid A* Path nodes. Note that I am using a grid graph, YMMV depending on the graph type you're using. Also, I am using the pro version of A* Pathfinding Project.

C#:
private bool TrySetTarget()
{
    for (int i = 0; i < targetRetries.Value; i++) {
        // Generate a random direction.
        var direction = transform.forward + Random.insideUnitSphere * wanderRate.Value;

        // Get a potential destination in the chosen direction.
        var potentialDestination = transform.position + direction.normalized * Random.Range(minWanderDistance.Value, maxWanderDistance.Value);

        // Sample the potential destination.
        var sampledPosition = SamplePosition(potentialDestination);

        // Get the closest node to the sampled position.
        var node = AstarPath.active.GetNearest(sampledPosition).node;

        if (node.Walkable) {
            // If the node is walkable and has not been visited, set the destination and add it to the visited nodes.
            SetDestination(sampledPosition);
            return true;
        }
    }

    // If no valid destination found after all retries, return false.
    return false;
}
 
Last edited:
Top