Korvash’s Randomized Object & Material Scripts (Unity)

Over in the Shroud of the Avatar forums, Korvash Bloodbourne posted some scripts for the Dev+ community to use. With his permission, I am reposting them here. Here is his explanation of the scripts:

While I’ve been working on a personal project, I have been using a lot of prefabs. And, as in most projects that use a lot of prefabs, I was seeing a huge amount of repetition in how things were looking, i.e. it was the same house over and over again, to the point it was extremely boring.

Well, while watching a DevBlog video for a different game on YouTube, I seen something they were doing and decided to give it a go myself. You can find the video, and the effect I was after here (at about the 9:52 mark).

https://www.youtube.com/watch?v=utQfuTSs0ik&t=592

So, I spent some, writing up a couple scripts that, at least for me, recreated what I had seen in the video. What I ended up with, worked pretty well, at least for what I am aiming for. So, I figured that I would share the scripts with you.

The scripts can be used individually, or together. If you want to use them together, the RandomMaterial script, needs to be applied to the objects that are generated by RandomObject script.

A quick disclaimer:

I am not an amazing coder, so there is probably a good portion of these scripts that are not the most efficient. So, feel free to make any changes you want to the scripts.

I’ve done some quick tests, and they seem to work fairly well (depending on your objects and materials). To use either of the scripts, create a new C# script in Unity (New | C# Script), rename it (RandomMaterial.cs/RandomObject.cs), and then copy and paste the code. Save the script, and then add the scripts to an object.

Randomized Material

This script will randomize the material applied to the parent object, from a selection of materials that the user can define. The intent, is for this script to be used on objects that have a single common mesh, but multiple different materials that can be applied to it.

The randomization is based on the correct location of the object, and the randomization can be change to be based on different transform vectors.

RandomMaterial.cs
using UnityEngine;
using System.Collections;
 
[ExecuteInEditMode]
public class RandomMaterial : MonoBehaviour {
 
    public enum vectorEnum { X, Y, Z, XY, XZ, YZ };
    [Header("Generation")]
    [Tooltip("The transform plane the randomization is based on")]
    public vectorEnum ranomdizeationVector;
    [Tooltip("The possible materials to randomize between")]
    public Material[] Materials;
    private GameObject matTaget;
    private Material targetMaterial;
    private Renderer rend;
    [Header("Manual Control")]
    [Tooltip("Manually control the material")]
    public bool overrideMaterial = false;
    [Tooltip("Material index to use for manual override")]
    public int OverrideIndex = 0;
    [Header("Apply")]
    [Tooltip("This will apply all of the settings and delete the script")]
    public bool ApplyChanges = false;
 
    public void Update (){
 
        if (Application.isPlaying) // fail safe in case the script is still applied at run time.
        {
            this.enabled = false;
            Destroy(this);
        }
 
        if (Materials.Length >= 1 && Materials[Materials.Length-1] != null) // this stop the script from removing the default material until the array has been filled.
        {
            matTaget = this.gameObject;
            if (ranomdizeationVector == vectorEnum.X)
            {
                float p = randomValueFromFloat(matTaget.transform.position.x);
                int x = 0;
                while (x < Materials.Length)
                {
                    if (applyMaterial(p, Materials.Length, x))
                    {
                        targetMaterial = Materials[x];
                        break;
                    }
                    x++;
                }
 
            }
            if (ranomdizeationVector == vectorEnum.Y)
            {
                float p = randomValueFromFloat(matTaget.transform.position.y);
                int x = 0;
                while (x < Materials.Length)
                {
                    if (applyMaterial(p, Materials.Length, x))
                    {
                        targetMaterial = Materials[x];
                        break;
                    }
                    x++;
                }
 
            }
            if (ranomdizeationVector == vectorEnum.Z)
            {
                float p = randomValueFromFloat(matTaget.transform.position.z);
                int x = 0;
                while (x < Materials.Length)
                {
                    if (applyMaterial(p, Materials.Length, x))
                    {
                        targetMaterial = Materials[x];
                        break;
                    }
                    x++;
                }
 
            }
            if (ranomdizeationVector == vectorEnum.XY)
            {
                float p = randomValueFromFloat(matTaget.transform.position.x * matTaget.transform.position.y);
                int x = 0;
                while (x < Materials.Length)
                {
                    if (applyMaterial(randomValueFromFloat(matTaget.transform.position.x * matTaget.transform.position.y), Materials.Length,x))
                    {
                        targetMaterial = Materials[x];
                        break;
                    }
                    x++;
                }
 
            }
            if (ranomdizeationVector == vectorEnum.XZ)
            {
                float p = randomValueFromFloat(matTaget.transform.position.x * matTaget.transform.position.z);
                int x = 0;
                while (x < Materials.Length)
                {
                    if (applyMaterial(p, Materials.Length, x))
                    {
                        targetMaterial = Materials[x];
                        break;
                    }
                    x++;
                }
 
            }
            if (ranomdizeationVector == vectorEnum.YZ)
            {
                float p = randomValueFromFloat(matTaget.transform.position.y * matTaget.transform.position.z);
                int x = 0;
                while (x = Materials.Length)
                {
                    OverrideIndex = Materials.Length - 1; // stops the index value going above the array limit.
                }
                targetMaterial = Materials[OverrideIndex];
            }
            rend = matTaget.GetComponent();
            rend.material = targetMaterial;
 
            if (ApplyChanges)
            {
                //Destroy(this);
                DestroyImmediate(this);
            }
        }
    }
 
    private float randomValueFromFloat(float seed)
    {
        Random.seed = (int)seed;
        return (Random.value);
        
    }
 
    private bool applyMaterial(float p, int length, int x)
    {
        if (p < (1f / length) + ((float)x / length)){return (true);}
        else { return (false); }
    }
 
}

Randomized Objects

This script will randomize the game object from a selection of game objects that the user can define. The intent, is for this script to be used on an empty game object, to prevent object overlap. The script will remove the empty game object when its applied.

The randomization is based on the correct location of the object, and the randomization can be change to be based on different transform vectors.

RandomObject.cs
using UnityEngine;
using System.Collections;
 
[ExecuteInEditMode]
public class RandomObject : MonoBehaviour {
 
    public enum vectorEnum { X, Y, Z, XY, XZ, YZ };
    [Header("Generation")]
    [Tooltip("The transform plane the randomization is based on")]
    public vectorEnum ranomdizeationVector;
    [Tooltip("The possible prefabs to randomize between")]
    public GameObject[] Objects;
    private GameObject objTaget = null;
    private GameObject targetObject = null;
    private GameObject currentprefab = null;
    [Header("Manual Control")]
    [Tooltip("Manually control the object")]
    public bool OverrideObject = false;
    [Tooltip("Object index to use for manual override")]
    public int OverrideIndex = 0;
    [Header("Has Random Material")]
    [Tooltip("Calls the Randomize Material script if present on the objects.")]
    public bool RandomizeObjectMaterial = false;
    [Header("Apply")]
    [Tooltip("This will apply all of the settings and delete the script")]
    public bool ApplyChanges = false;
 
    void Update (){
 
        if (Application.isPlaying) // fail safe in case the script is still applied at run time.
        {
            this.enabled = false;
            Destroy(this);
        }
 
        if (Objects.Length >= 1 && Objects[0] != null) // this stop the script from removing the default object until the array has 1 object added.
        {
            objTaget = this.gameObject;
            if (ranomdizeationVector == vectorEnum.X)
            {
                float p = randomValueFromFloat(objTaget.transform.position.x);
                int x = 0;
                while (x < Objects.Length)
                {
                    if (applyObject(p, Objects.Length, x))
                    {
                        targetObject = Objects[x];
                        break;
                    }
                    x++;
                }
 
            }
            if (ranomdizeationVector == vectorEnum.Y)
            {
                float p = randomValueFromFloat(objTaget.transform.position.y);
                int x = 0;
                while (x < Objects.Length)
                {
                    if (applyObject(p, Objects.Length, x))
                    {
                        targetObject = Objects[x];
                        break;
                    }
                    x++;
                }
 
            }
            if (ranomdizeationVector == vectorEnum.Z)
            {
                float p = randomValueFromFloat(objTaget.transform.position.z);
                int x = 0;
                while (x < Objects.Length)
                {
                    if (applyObject(p, Objects.Length, x))
                    {
                        targetObject = Objects[x];
                        break;
                    }
                    x++;
                }
                
            }
            if (ranomdizeationVector == vectorEnum.XY)
            {
                float p = randomValueFromFloat(objTaget.transform.position.x * objTaget.transform.position.y);
                int x = 0;
                while (x < Objects.Length)
                {
                    if (applyObject(p, Objects.Length, x))
                    {
                        targetObject = Objects[x];
                        break;
                    }
                    x++;
                }
 
            }
            if (ranomdizeationVector == vectorEnum.XZ)
            {
                float p = randomValueFromFloat(objTaget.transform.position.x * objTaget.transform.position.z);
                int x = 0;
                while (x < Objects.Length)
                {
                    if (applyObject(p, Objects.Length, x))
                    {
                        targetObject = Objects[x];
                        break;
                    }
                    x++;
                }
 
            }
            if (ranomdizeationVector == vectorEnum.YZ)
            {
                float p = randomValueFromFloat(objTaget.transform.position.y * objTaget.transform.position.z);
                int x = 0;
                while (x = Objects.Length)
                {
                    OverrideIndex = Objects.Length - 1; // stops the index value going above the array limit.
                }
                targetObject = Objects[OverrideIndex];
            }
            if (currentprefab != null)
            {
                DestroyImmediate(currentprefab);
            }
            Vector3 ool = objTaget.transform.position;
            currentprefab = Instantiate(targetObject);
            currentprefab.transform.position = ool;
            currentprefab.transform.parent = objTaget.transform;
            if (RandomizeObjectMaterial)
            {
                if (currentprefab.GetComponent()) // checks to see if the current prefab has the Random Material script, if so updates that.
                {
                    RandomMaterial childScript = currentprefab.GetComponent() as RandomMaterial;
                    childScript.Update();
                }
                
                if (ApplyChanges)
                {
                    currentprefab.transform.parent = null;
                    DestroyImmediate(objTaget);
                }
            }
        }
    }
 
    private float randomValueFromFloat(float seed)
    {
        Random.seed = (int)seed;
        return (Random.value);
        
    }
 
    private bool applyObject(float p, int length, int x)
    {
        if (p < (1f / length) + ((float)x / length)){return (true);}
        else { return (false); }
        
    }
 
}

The above scripts can be downloaded as individual C# files in the package below:

License

These scripts have been released under the CC-BY-NC license. If you wish to use them commercially, contact Korvash directly.

Browncoat Jayson

Join me in New Britannia!

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *