Click based navigation is ignoring prefab

Still fairly new to Unity and presumably missing something obvious here, but ref this navmesh:

In a nutshell, I’ve a terrain with a lowered section for a river, and a bridge prefab that’s broken up in to object groups. The parts of the prefab that make the walls and parapets I’ve set to not walkable in the navmesh, and the part that joins both sides of the river I’ve set to walkable. As you can see in the screenshot, the navmesh itself seems to have baked fine with this.

The terrain and this same prefab element, i.e. the part highlighted with an orange outline, are both on a layer I’ve named AcceptMovementClicks, and I then have a movement script which on click events is supposed to raycast to objects on this layer. My thinking being that clicking for example the wall of a building should continue to cast through that wall and hit the floor inside, to then move the player to inside the building. Or in this case, clicking on top of the bridge, should move the player to on top of the bridge even if the camera is rotated in a way where you’re clicking through the parapet. Hence having the walkable areas on a specific layer and casting to that layer only:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class MovementController : MonoBehaviour
{
    private NavMeshAgent agent;
    private bool triggerMovement = false;
    private Vector2 mouseDownPosition;
    private Vector2 mouseUpPosition;
    private int layerMask;

    // Start is called before the first frame update
    void Start()
    {
        agent = GetComponent<NavMeshAgent>();

        // Layer 3 is our AcceptMovementClicks layer, where terrain and floors etc are. Physics.Raycast uses bitmasks though so we need to bitshift the layer number to get to the right part of the mask
        layerMask = 1 << LayerMask.NameToLayer("AcceptMovementClicks");
    }

    // Update is called once per frame
    void Update()
    {
        if(Input.GetMouseButtonDown(0) && !triggerMovement) {
            triggerMovement = true;
            mouseDownPosition = Input.mousePosition;
        } else if(Input.GetMouseButtonUp(0) && triggerMovement) {
            triggerMovement = false;

            mouseUpPosition = Input.mousePosition;

            if(Vector2.Distance(mouseUpPosition, mouseDownPosition) < 10) {
                // Movement is small enough that we can assume the player wasn't trying to drag
                RaycastHit hit;

                if(Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit, 1000, layerMask)) {
                    agent.destination = hit.point;
                }
            }
        }
    }
}

What seems to be happening though, is that the movement is always trying to set the destination to a place on the terrain. The bridge is used to get there, as per the navmesh blueprint, but clicking on top of the bridge never lands the player at that location. As though the bridge is being ignored completely despite being on the correct layer, and the ray is casting to the terrain below it.

Any thoughts please?

Hello there! :slight_smile:

A few things:

1.- have you tried moving onto your bridge without any layer filtering?
2.- does your child Objects which are supposed to be in the layer, having the right layer? Or is it just the Parent having the layer? If so, change the children to have it.
3.- i have done something similar right over here (At: 10:31m):

i have used here no bitshifting but straight the LayerMask to filter everything out except the one i need.

If you fixed your error, would love to hear the solution :slight_smile:

Thanks @Terraya

1 - I seem to get the same result without the layer filtering, though I know the filtering does work as without it, clicking the player character moves back towards the camera as if the ray is bouncing off and hitting the terrain between it and the camera, where with the filtering the ray passes through the character and hits the terrain on the other side.

2 - Only the child object is on the layer. The root prefab and all other child elements of it are on the default layer. Although if I do set the entire prefab to be on this layer, it still seems to be ignored. I did wonder if there was a hierarchy issue before trying this, but I guess not.

3 - Thanks for sharing. LayerMask.GetMask without the bitshift seems a better approach than LayerMask.NameToLayer admittedly. Not sure how I didn’t find that before! Same result though unfortunately. My bridge seems to be totally ignored.

Ha - just this second spotted the problem while writing this actually - I didn’t have any colliders set up on the bridge! Silly mistake… added a mesh collider to just the ground part of it and voila, all is working now.

Ach nice! :smile:

Happens to the best of us, thanks for sharing your mistake! :slight_smile: