Game Development Stack Exchange is a question and answer site for professional and independent game developers. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I've finally figured out why my layer masks for my ground collision code weren't working. I was using NameToLayer() to get the layer I needed, but layer masks use bit shifting to actually set the layer mask value. This is extremely unusual and I don't see any reason why this isn't handled in the code behind. Why do we have to use code like this:

mask = 1 << LayerMask.NameToLayer("Default");

when something like this:

mask = LayerMask.NameToLayer("Default");

makes more intuitive sense and works similar to the rest of the Unity API?

share|improve this question
1  
Using the string version takes more processing power. Not to mention the string is internally an array which is a reference type and gets added to the garbage collector. – Krythic 2 days ago
up vote 2 down vote accepted

This is extremely performant. That's all there is to it - comparing strings as the obvious example is slower by a factor of 10. And physics calculations have to be very optimized, so it's good that someone who knew what's going on wrote it this way.

So the obvious follow-up question is - why isn't this wrapped in a helper method to handle the conversion and bit-shifting. I think that no one actually got to it - I've rolled up my own nifty helper utility and that is the common practice.

share|improve this answer
    
The correct design choice by the Unity team would have been to use an integer as an indexer, instead of a string. I cringe when I think about how crazy the garbage collector is likely going with their current implementation, not to mention the string array allocations. – Krythic yesterday
1  
Absolutely - any array is best referenced by integers. Integers could easily become humanly readable by a simple enum. – Jedy 22 hours ago
    
A quick and dirty implementation works, but for bigger projects I use [Type Safe] (assetstore.unity3d.com/en/#!/content/35903). – Jedy 22 hours ago

Using bit shifting allows you to take into account multiple layers in one physics operation:

 Physics.Raycast(ray, out hitInfo, Mathf.Infinity, layerMask )

Without bit shifting, you would be allowed to raycast in one layer and only one. While with bit shifting, you can raycast in multiple specific layers:

layerMask = (1 << LayerMask.NameToLayer("MyLayer1")) | (1 << LayerMask.NameToLayer("MyLayer2")) ;

You can also raycast in every layers except specific ones :

layerMask = (1 << LayerMask.NameToLayer("MyLayer1")) | (1 << LayerMask.NameToLayer("MyLayer2")) ;
layerMask = ~layerMask;

If you look at the "Layer manager" in Unity, layers can be seen as the indices of a simple one-dimension array.

share|improve this answer
2  
You should use bitwise OR | instead of integer addition + when making union of masks, integer addition might produce unexpected behavior. – wondra 2 days ago
1  
But then again, they could have done that internally and provided a method like LayerMask.NamesToLayers(params string[] layerNames) – QBrute yesterday
    
Good point @wondra ! ;) - Yes, they could have done this QBrute, but it's far more flexible to use bit shiffting operation if you want to dynamically change the layer mask (adding, removing layer, inverting, ...) – Hellium yesterday
    
Bitwise operations are also extremely fast. They are an excellent way to composite large binary data. – Gusdor yesterday
    
This doesn't really answer the question of why the method doesn't just straight up return a layer mask instead of a layer number though. – Cubic yesterday

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.