LayerMask + RayCast does not work like described in the docs

My goal is to cast a ray that ignores all Layers but one. This…

… tells me I should do it like that:

private LayerMask layerMask = 1 << 9;

void Update(){
   RaycastHit hit;
   if (Physics.Raycast(origin.position, parent.transform.TransformDirection(Vector3.forward), out hit, layerMask))
   {
    print("I'm hitting layer 9 while ignoring all other layers"))
   }
}

But if I have a collider with a different layer in front of layer 9, it still hits it. I’m confused…

try if you add the distance parameter there?

2 Likes

It seems to have done something, but now I’m getting a NullReferenceException.

These are my LayerIDs: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 31

So the layer I’m referencing exists…

I even tried declaring it in Update() with the same result

@Di_o

Yes, what @mgear said the layer can accidentally replace the distance with this method overload:

Physics.Raycast(origin.position, transform.forward, out hit, layerMask))

So the last parameter here should be distance, and the layerMask (int) can be placed there too… but if you need to have layer mask, try this version instead:

Physics.Raycast(transform.position, transform.forward, out hit, 100f, layerMask))

A I got it now. I accidently copied the wrong line that caused the NullException. The distance did the trick.

THX @mgear & @eses

thank you very much, finally I understand what was wrong with my raycasts.

Gosh this is stupid, this has to be a bug right ?
I checked that my layermask is a int and not a float like the distance parameter, yet it doesn’t work…
Thanks for the workaround anyway !

Physics.Raycast() is a HORRIBLY overloaded function. I recommend ALWAYS specifying the named arguments rather than hoping you got them in the correct order.

This is because layerMask (an int) and maxDistance (a float) can be easily mistaken at the call site if you are passing an integer value for maxDistance. In this case, no error will be returned, and it will just fail mysteriously.

The time you save by typing out named arguments will be your own.

Instead of this:

Physics.Raycast(origin.position, transform.forward, out hit, layerMask)

ALWAYS do this:

Physics.Raycast(
     origin: origin.position,
     direction: transform.forward,
     hitInfo: out hit,
     layerMask: layerMask)

This will also reveal instantly if you have asked for a permutation of arguments that is not matched by the available overloads.

EDIT: the same goes for constructing Ray() and Plane() objects: the identical-typed arguments can easily be inadvertently swapped, leading to mass confusion, especially when they sort of work near (0,0,0) for instance.

12 Likes

Holy cow thanks for this tip. I just had a wild issue where I guess Unity thought the layerMask I was passing into the Raycast method was some other value so it wasn’t doing what I expected. I honestly have never used that syntax for calling a method but The More You Know!

2 Likes

I just opened a new thread to point out an irregularity with Physics.Raycast and Physics.Linecast

You can find it here: SERIOUS issue with Raycast/Linecast

1 Like