Set Random Material from folder

I’m making an underground system made of Capsules and I have around 100 Materials all originate from Sprites texture. Eventually, there would be around 500 Capsules to cover a large area.

My goal, Give a different random Material from a folder to each Capsules at Start-Runtime.

-All the Materials are in a Folder named FirstLayerMaterials that is itself in a Folder named UnderGround.

-All the Capsules have the Script UnderGroundCapsules.

-All the Capsules are children of a GameObject named UnderGroundBlocks with the Script

-All the Capsules have a tag “NotDurt”.

-All the Capsules Shader must be set to Sprites/Default.

In C# in the Parent UnderGroundBlocks (Script UnderGroundBlocks) that holds the Capsules.

public class UnderGroundBlocks : MonoBehaviour {

GameObject[] Durts;

void Start(){
            Material[] materials = (Material[]) Resources.LoadAll("FirstLayerMaterials");
	Durts = GameObject.FindGameObjectsWithTag("NotDurt");
	foreach(GameObject capsule in Durts){
		capsule.GetComponent<Renderer>().material = materials[Random.Range(0, 100)];


My problem:
Its giving an Error:
InvalidCastException: Cannot cast from source type to destination type.
UnderGroundBlocks.Start () (at Assets/WorldObject/UnderGound/UnderGroundBlocks.cs:13)

Thank you


To answer for certain, I’d need to know which line ‘line 13’ is (i.e. the line the error refers to).

I suspect it is this line:

Material[] materials = (Material[]) Resources.LoadAll("FirstLayerMaterials");

The documentation seems to imply this is fine, but I’m fairly certain it isn’t, as Resources.LoadAll won’t necessarily return an array of materials. In fact I thought it would return a simple array of objects, possibly unless you actually specify a type as the 2nd parameter of Resource.LoadAll.

You could try:

    Material[] materials = (Material[]) Resources.LoadAll("FirstLayerMaterials", typeof(Material));

From the docs that looks like it might work, though I’ve not tried it.

Or if not, this should certainly work:

void Start()
    //allow Resource.LoadAll to just return a list of objects (filtered to only have materials in)
    Object[] materials = Resources.LoadAll("FirstLayerMaterials", typeof(Material));

    //get our 'Durts' and iterate over each one
    Durts = GameObject.FindGameObjectsWithTag("NotDurt");
    foreach(GameObject capsule in Durts)
        //set material, adding a static cast to the Material type
        capsule.GetComponent<Renderer>().material = (Material)materials[Random.Range(0, 100)];

Though finally, to be on the safe side, use the materials array length instead of ‘100’ in the random:

        capsule.GetComponent<Renderer>().material = (Material)materials[Random.Range(0, materials.Length)];

Hope that helps


Thank you Chris,
yeah that was the line 13…
Almost works, now its saying :

IndexOutOfRangeException: Array index is out of range.
UnderGroundBlocks.Start () (at Assets/WorldObject/UnderGound/UnderGroundBlocks.cs:15)

line 15 is :
capsule.GetComponent().material = (Material)materials[Random.Range(0, materials.Length)];

How do I make the material change once every 3 seconds or more?