Random Object Placer for Procedural Design

21 Oct 2010
Posted by xeophin

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;
 
/// <summary>
/// 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.
/// </summary>
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++;
 
                }
            }
        }
    }
}
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.

Post new comment

The content of this field is kept private and will not be shown publicly. If you have a Gravatar account associated with the e-mail address you provide, it will be used to display your avatar.
By submitting this form, you accept the Mollom privacy policy.


Navigation



Languages