0

I am using the navmesh/agent on the player as an assistance autopathing function where the agent is disabled at all times unless the user clicks a point on the floor to walk towards. Then the agent will be disabled again once the destination is reached.

I need a way to check if the player is currently on the navmesh, within a tolerable threshold without the navmeshagent being enabled. Or, if there is a way to remove the player-binding 'effect' of the navmeshagent without disabling it, as I could use that to solve my problem too.

I guess in pseudocode, this is what i'm trying to accomplish with navmeshagent disabled:

if (!agent.isOnNavMesh){ DisableClickSelection();}

I was thinking of the possibility of comparing the Y transform of the player and the navmesh to get a height difference and using that to determine if the player is on the navmesh but i don't know how to go about getting the Y transform of the navmesh at a specific X and Z point. Maybe i can use a raycast? I'm not sure the best way. Like i said, if there is a way to remove the player-binding 'effect' of the agent on the player but keep the agent enabled I would be able to work with that too.

Serlite
  • 12,130
  • 5
  • 38
  • 49
Mike H
  • 387
  • 9
  • 25

1 Answers1

6

You should be able to do this through use of NavMesh.SamplePosition(). This method basically searches in a spherical radius around a given position for the nearest point on the navmesh. All you need to do is verify that the returned position is vertically in line with the player position, and is on/above it.

Here's an idea on how you might apply this in code:

// Don't set this too high, or NavMesh.SamplePosition() may slow down
float onMeshThreshold = 3;

public bool IsAgentOnNavMesh(GameObject agentObject)
{
    Vector3 agentPosition = agentObject.transform.position;
    NavMeshHit hit;

    // Check for nearest point on navmesh to agent, within onMeshThreshold
    if (NavMesh.SamplePosition(agentPosition, out hit, onMeshThreshold, NavMesh.AllAreas))
    {
        // Check if the positions are vertically aligned
        if (Mathf.Approximately(agentPosition.x, hit.position.x)
            && Mathf.Approximately(agentPosition.z, hit.position.z))
        {
            // Lastly, check if object is below navmesh
            return agentPosition.y >= hit.position.y;
        }
    }

    return false;
}

So for using it with your example, you'd write:

if (!IsAgentOnNavMesh(agent.gameObject))
{
    DisableClickSelection();
}

Hope this helps! Let me know if you have any questions.

Serlite
  • 12,130
  • 5
  • 38
  • 49
  • 10/10 flawless response and exactly what i was talking about. Thank you. – Mike H Jul 31 '17 at 17:31
  • What do you think about using the same exact concept for registering if a click is located outside the navmesh? Is that the best course or is there easier – Mike H Jul 31 '17 at 19:07
  • 1
    @MikeH That's a bit more difficult if you're not clicking anything in particular, since a click is more of a ray than a single position to check. This could work if you had a rough collider approximately lined up with the navmesh (could just be big box collider on another physics layer to avoid interacting with the rest of the scene). On click, raycast to hit that collider, then use the hit point against the logic provided in this answer. If this isn't possible...then I don't think this approach will work with click. – Serlite Jul 31 '17 at 19:16