How to handle end reached distance, thinner than obstacle wall

Unity 2022.3.22f1
Astar v 5.0.6
RichAI
Recast Graph
Rootmotion Movement

I am looking for advice on how to handle the situation in which my AI monsters, “find” their target and get close enough to it that they are satisfied. But the character is in not their FoV because the there is an obstacle in the way. Like in the image. When the player is visible the line would be white. So I am detecting the situation from code.

Here is where it detects the issue in the code, I was trying SearchPath(); but that just generates the same path.

public override AIState Tick(AICharacterManager aiCharacter)
        {
            // Check if we are performing an action
            if(aiCharacter.isPerformingAction) return this;
            
            // Check if our target is null, return to the idle state
            if(aiCharacter.characterCombatManager.currentTarget == null)
                return SwitchState(aiCharacter, aiCharacter.idle);
            
            // Make sure our Navmesh Agent is active
            if(!aiCharacter.agent.enabled) aiCharacter.agent.enabled = true;
            
            // Keep facing the target at all times
            aiCharacter.aiCharacterLocomotionManager.RotateTowardsAgent(aiCharacter);
            
            // Check to see if there is an obstacle in the way when not moving
            if(!aiCharacter.aiCharacterNetworkManager.isMoving.Value)
            {
                if (!aiCharacter.aiCharacterCombatManager.isInLineOfSight(aiCharacter))
                {
                    // calculate a new path to the target
                    aiCharacter.agent.SearchPath();
                    DebugController.Log("Obstacle in the way");
                }
            }
            
            // If we are within combat range of our target, switch to the combat state
            
            // If the target is not Reachable and they far away, return home,
            
            // Pursue the target
            if(aiCharacter.destinationSetter.target == null)
            {
                aiCharacter.destinationSetter.target = aiCharacter.characterCombatManager.currentTarget.transform;
            }

            return this;

        }

Any suggestions on how to try to mitigate this issue?

Here is the LineOfSight Check

        public bool isInLineOfSight(AICharacterManager aiCharacter)
        {
            if (currentTarget == null) return false;
            
            CharacterManager targetCharacter = aiCharacter.characterCombatManager.currentTarget;
                
            Vector3 targetsDirection = targetCharacter.transform.position - aiCharacter.transform.position;
            float angleOfPotentialTarget = Vector3.Angle(targetsDirection, aiCharacter.transform.forward);
            
            if(angleOfPotentialTarget > minimumFOV && angleOfPotentialTarget < maximumFOV)
            {
                // Check for Environment Obstructions
                if(Physics.Linecast(eyesTransform.position, targetCharacter.headTransform.position ,WorldUtilityManager.Instance.GetEnvironmentLayers()))
                {
                    Debug.DrawLine(eyesTransform.position, targetCharacter.headTransform.position, Color.red, 0.1f);
                    return false;
                }
                else
                {
                    Debug.DrawLine(eyesTransform.position, targetCharacter.headTransform.position, Color.white, 0.1f);

                    return true;
                }
            }
            
            return false;
        }

Hi

You can set the stop distance to something low, and then do something like:

void Update () {
    ai.isStopped = isEnemyInLineOfSight() && ai.remainingDistance < threshold;
}

That’s a good idea, I implemented something similar, since its a multiplayer game it was a little more convoluted than that but very good input, the essential code became more like this:

if (aiCharacter.agent.hasPath)
{
    // Get the destination of the AI character's agent and calculate the remaining distance to it
    // (using agent.remainingDistance is not reliable)
    Vector3 agentDestination = aiCharacter.agent.destination;
    float remainingDistance = Vector3.Distance(agentDestination, aiCharacter.transform.position);
    // If the AI character has a clear line of sight to its target and is within 3 units of it, stop the agent
    // 3 will made into a variable later
    aiCharacter.agent.isStopped = aiCharacter.aiCharacterCombatManager.isInLineOfSight(aiCharacter) &&
                                  remainingDistance < 3f;
    // If the agent is stopped, set the AI character's isMoving value to false so that the animator can be stopped across the network
    if (aiCharacter.agent.isStopped)
    {
        aiCharacter.aiCharacterNetworkManager.isMoving.Value = false;
        // If the AI character's viewable angle is outside the acceptable window, make the AI character face its target
        if(aiCharacter.aiCharacterCombatManager.viewableAngle < aiCharacter.aiCharacterCombatManager.minimumFaceTargetWindow || aiCharacter.aiCharacterCombatManager.viewableAngle > aiCharacter.aiCharacterCombatManager.maximumFaceTargetWindow)
        {
            aiCharacter.aiCharacterCombatManager.FaceTarget(aiCharacter);
        }
    }
    // If the agent is not stopped, set the AI character's isMoving value to true
    else
        aiCharacter.aiCharacterNetworkManager.isMoving.Value = true;
}

I’m surprised how well the localavoidance actually works even with rootmotion.

My Patreon for those interested in following progress.

1 Like