ArgumentException: NameToLayer can only be called from the main thread

I was hoping to cache the response of the NameToLayer function as I suspect it will offer better performance (even if only minimal). Whilst the following source does in fact work, I would like to avoid the warning/error.

public class MyObject : MonoBehaviour {

    public static readonly int LAYER_PROJECTILE;

    static MyObject() {
        LAYER_PROJECTILE = LayerMask.NameToLayer("Projectile");
    }

    ...

    void OnTriggerEnter(Collider collider) {
        if (collider.gameObject.layer == LAYER_PROJECTILE) {
            ...
        }
        else { ... }
    }

}

Is there a better approach to this (that doesn’t involve storing the layer number in every single object instance?

Well, since you are using C#, I can give you plenty of better ways!

For starters, you shouldn’t be using the constructor in a MonoBehaviour-derived class, for any reason. Any functionality you put in there should be invoked in the

void Awake()
{
}

method, instead.

If you want to make a lazily-evaluated constant int for the layer, try doing it like this:

int _projectileLayer = -1;

int projectileLayer{
    get {
        if(_projectileLayer == -1)
        {
            _projectileLayer = LayerMask.NameToLayer("Projectile");
        }
        return _projectileLayer;
    }
}

Then, you can use ‘projectileLayer’, and it will only ever calculate the value once per run.

You should avoid using static variables, just on principle- after all, it is possible that you’ll want to use the same script to shoot projectiles from several different layers at one point, so storing it in a static variable will limit you in the indeterminite future.

In any case, you’re right to try to speed things up- although keep in mind that in the timeless words of Donald Knuth: “premature optimisation is the root of all evil”.