Skip to main content
added 1 character in body
Source Link
DMGregory
  • 140.8k
  • 23
  • 257
  • 401
// This attribute makes the asset show up in the editor's Assets -> Create menu
// and when right-clicking in your Project window and choosing Create
[CreateAssetMenu(filename = "New Material Library", menuName = "Custom/Material Library"]Library")]
public class MaterialLibrary:ScriptableObject {

    // You could also expose individual named fields, or provide a public method
    // to retrieve a material based on an enum key or other input...
    public Material[] materials;

}
// This attribute makes the asset show up in the editor's Assets -> Create menu
// and when right-clicking in your Project window and choosing Create
[CreateAssetMenu(filename = "New Material Library", menuName = "Custom/Material Library"]
public class MaterialLibrary:ScriptableObject {

    // You could also expose individual named fields, or provide a public method
    // to retrieve a material based on an enum key or other input...
    public Material[] materials;

}
// This attribute makes the asset show up in the editor's Assets -> Create menu
// and when right-clicking in your Project window and choosing Create
[CreateAssetMenu(filename = "New Material Library", menuName = "Custom/Material Library")]
public class MaterialLibrary:ScriptableObject {

    // You could also expose individual named fields, or provide a public method
    // to retrieve a material based on an enum key or other input...
    public Material[] materials;

}
Source Link
DMGregory
  • 140.8k
  • 23
  • 257
  • 401

Quite often I'll use a ScriptableObject to hold this kind of shared data.

It's similar to OC_RaizW's suggestion of a MonoBehaviour, but doesn't require a GameObject to host this content - a ScriptableObject can exist as its own asset:

// This attribute makes the asset show up in the editor's Assets -> Create menu
// and when right-clicking in your Project window and choosing Create
[CreateAssetMenu(filename = "New Material Library", menuName = "Custom/Material Library"]
public class MaterialLibrary:ScriptableObject {

    // You could also expose individual named fields, or provide a public method
    // to retrieve a material based on an enum key or other input...
    public Material[] materials;

}

Now all your edges can share a reference to this MaterialLibrary.

I often use this for collecting up pools of foley sounds that many characters use, or for sharing configuration parameters used by multiple player/enemy instances. This gives me a single place to make changes to tune all instances currently running or that have yet to be spawned. This is a form of the flyweight pattern.

Another trick I like to use for materials in particular is to prepare a general-purpose material variant cache:

public static class MaterialCache {

    struct Variant {
        public Material originalMaterial;
        public Color32  color;
    }

    static Dictionary<Variant, Material> _cache;

    public static Material GetMaterialVariant(Material originalMaterial, Color32 color) {
        var key = new Variant{originalMaterial = originalMaterial, color = color};

        Material output;
        if(_cache.TryGetValue(key, out output) == false)
        {
            output = Instantiate<Material>(originalMaterial);
            output.color = color;
            _cache.Add(key, output);
        }
        return output;
    }

    // You may also want to provide a Flush method to destroy cached materials,
    // in case your game ever enters a state where you don't need them anymore.
}

Now anything that wants to modify its display colour can do so like so...

public class ColorChanger : MonoBehaviour {
    Material _originalMaterial;
    Renderer _renderer;

    void Start() {
        _renderer = GetComponent<Renderer>();
        _originalMaterial = _renderer.sharedMaterial;
    }

    public void ChangeColor(Color32 color) {
        var mat = MaterialCache.GetMaterialVariant(_originalMaterial, color);
        _renderer.sharedMaterial = mat;
    }
}

If I'm using only a handful of easily-standardized colours like Color.Red, then every instance with the same base material asking for a red variant will get a reference to the same red material instance, rather than creating copies all over the place. And best of all, I don't have to manually create and assign all those near-duplicate materials - they're just created on demand. :)