Random Object Placer for Procedural Design

You are here

Another script that is the result of the ProXedural project at the ZHdK. It produces a somewhat randomly generated level of the size of a collider that is placed over a terrain in Unity 3D.

By using a somewhat mixed approach of completely random raycast placing and placing objects using an array, the script can ensure that the different kinds of objects are distributed all over the terrain.

Again, the script may be oddly specific at times, so you might have to adapt it to your needs if you intend to reuse it.

using UnityEngine; using System.Collections;

///

/// Right now, this class does not do a whole lot. The principle, however, /// could be applied and extended for other purposes. The approach ensures /// that the objects are distributed all over the place. /// public class RandomPopuliser : MonoBehaviour {

public GameObject[] stuffToPlace;
private int[,] grid = new int[6, 6];

public int maxNumberOfObjectsToPlace = 30;

// Use this for initialization
void Start ()
{
    for (int i = 0; i < grid.GetLength (0); i++) {
        for (int j = 0; j < grid.GetLength (1); j++) {

            // Define some data we will need later on.
            float cellWidth = this.collider.bounds.size.x / grid.GetLength (1);
            float cellDepth = this.collider.bounds.size.z / grid.GetLength (0);
            float minX = cellWidth * j;
            float maxX = cellWidth * j + cellWidth;
            float minZ = cellDepth * i;
            float maxZ = cellDepth * i + cellDepth;

            // Let's define a counter that looks on which placeable we
            // are working on. There should be a more elegant way to
            // do this.
            int objectIndex = 0;

            // Objects that have been actually placed.
            int objectsPlaced = 0;

            // Number of objects that *could* have been placed.
            int possibleObjects = 0;

            // Now, let's put some stuff into the scene.
            foreach (GameObject placeable in stuffToPlace) {

                // A number that defines how many objects could be placed.
                // The further in the list, the more instances can be placed.
                int maxObjects;
                if (objectIndex + 1 == stuffToPlace.Length) {
                    maxObjects = maxNumberOfObjectsToPlace - possibleObjects;
                } else {
                    maxObjects = Mathf.RoundToInt (maxNumberOfObjectsToPlace / (stuffToPlace.Length) * (objectIndex + 1));
                }

                float chance = 1 / stuffToPlace.Length * (objectIndex + 1);

                for (int k = 0; k < maxObjects; k++) {

                    // Set new position
                    Vector3 newPosition = new Vector3 (Random.Range (minX, maxX) - this.collider.bounds.extents.x, this.transform.localPosition.y, Random.Range (minZ, maxZ) - this.collider.bounds.extents.z);
                    this.transform.TransformPoint (newPosition);

                    // Instantiate a new object
                    GameObject newObject = Instantiate (placeable, newPosition, Quaternion.identity) as GameObject;
                    newObject.transform.RotateAroundLocal (Vector3.up, Random.value * 2 * Mathf.PI);

                    // Check for terrain height
                    Ray ray = new Ray (newObject.transform.position, Vector3.down);
                    RaycastHit hit;
                    if (Physics.Raycast (ray, out hit, 600f) && hit.transform.name == "Terrain") {
                        newObject.transform.Translate (new Vector3 (0, -hit.distance, 0));
                        objectsPlaced++;
                    } else {
                        newObject.transform.Translate (new Vector3 (Random.Range (-5, 5), 0, Random.Range (-5, 5)));
                        if (Physics.Raycast (ray, out hit, 600f) && hit.transform.name == "Terrain") {
                            newObject.transform.Translate (new Vector3 (0, -hit.distance, 0));
                            objectsPlaced++;
                        } else {
                            print ("There was nothing I could do.");
                            Destroy (newObject);
                        }
                    }
                }

                possibleObjects = possibleObjects + maxObjects;
                objectIndex++;

            }
        }
    }
}

}