Instantiating a random prefab.

So I once asked about this code before with random materials but now I need this for random prefabs and i’m not sure how to achieve it. (It won’t work currently as I changed the prefab variable to a list to store the objects in the inspector)

using UnityEngine;
using System.Collections.Generic;

public class SkylineManager : MonoBehaviour {

	public List<Transform> prefab;
	public int numberOfObjects;
	public float recycleOffset;
	public Vector3 minSize, maxSize, minGap, maxGap;
	public float minY, maxY;

	private Vector3 nextPosition;
	private Queue<Transform> objectQueue;

	void Start () {
		objectQueue = new Queue<Transform>(numberOfObjects);
		for(int i = 0; i < numberOfObjects; i++){
			objectQueue.Enqueue((Transform)Instantiate(prefab));
		}
		nextPosition = transform.localPosition;
		for(int i = 0; i < numberOfObjects; i++){
			Recycle();
		}
	}

	void Update () {
		if(objectQueue.Peek().localPosition.x + recycleOffset < Player.distanceTraveled){
			Recycle();
		}
	}

	private void Recycle () {
		Vector3 scale = new Vector3(
			Random.Range(minSize.x, maxSize.x),
			Random.Range(minSize.y, maxSize.y),
			Random.Range(minSize.z, maxSize.z));

		Vector3 position = nextPosition;
		position.x += scale.x * 0.5f;
		position.y += scale.y * 0.5f;

		Transform o = objectQueue.Dequeue();
		o.localScale = scale;
		o.localPosition = position;
		objectQueue.Enqueue(o);

		nextPosition += new Vector3(
			Random.Range(minGap.x, maxGap.x) + scale.x,
			Random.Range(minGap.y, maxGap.y),
			Random.Range(minGap.z, maxGap.z));

		if(nextPosition.y < minY){
			nextPosition.y = minY + maxGap.y;
		}
		else if(nextPosition.y > maxY){
			nextPosition.y = maxY - maxGap.y;
		}
	}
}

RIght to explain the code, first start a new scene and do this.

  1. Create a new scene
  2. Add the script to a game object with a visible object like a cube or sphere
  3. populate the prefabs array/List on the object with some cubes of different variations(i tested with cubs with different materials)
  4. set the cubeSpawnPoint transform to an empty game object and stick it close to the player.
  5. run it

Basically what is happening is that its instantiating an object and picking a random object from the prefabs list, its then parenting it to an empty game object so that al the blocks are organised in your hierarchy, then it is moving the blocks to the position of the cumbeSpawnPoint Transform and translating them based of the last cube position an the current cubes size, so in theory this will work with any shape size cubes as long as they are being stacked in the z axis. (i may have over looked something but I will do more testing later to check that this works)

Looping Functionality

I have started to build in looping functionality for you so but got distracted last night, it just involves a switch and an enum (for ease of use). Basically when the enum is on a certain value it stops adding to the blocksInLevel list and receiving a random index of the prefab list for instantiation. It then could either use the current in game blocks and set their position so that you only ever have a certain amount of blocks in game or it can iterate through the blocksInLevel list and instantiate new blocks based on the current sequence.

Pretty simple stuff.

Pastebin link, might be easier to copy and paste from

I have tried to document the script and make it as self documenting as possible, if there are any questions let me know.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class LevelBlockSpawner : MonoBehaviour {
	
	public List<GameObject> prefabs = new List<GameObject>(); 			// This contains the different type of blocks
	private List<GameObject> blocksInLevel = new List<GameObject>(); 	// This contains a reference to current configuration of the block in game	
	
	
	private GameObject BlockStorage;									// This GameObject is used to organise all the instantiated cubes  
	private Vector3 lastBlockPosition = new Vector3(0,0,0);				//
		
	public Transform cubeSpawnPoint;
	
	private int initialBlockAmount = 12;
	private int blocksAhead = 8;
	private int blockCreateAmount = 3;
	
	private int blockDeleteCounter = 0;
	
	public enum Mode 
	{
		continuous,
		looping
	}
		
	public Mode BlockMode = Mode.continuous;
	
	// INIT
	// -------------------------------------------------------------------------------------------------------------------------------------------
	void Start () {
				
		BlockStorage = new GameObject("Block Storage"); // Instantiates the block storage object
		
		// Error handeling for if thhe cubeSpawnPoint transform was not chosen  (avoids null reference)
		if(cubeSpawnPoint == null){
			cubeSpawnPoint = this.transform;
		}
		
		// Instantiates n amount of blocks (based on the initialBlockAmoun variable) just to populate the level at the start of game
		for (int i = 0; i < initialBlockAmount; i++) {
			CreateBlock();
		}
				

	}
	// -------------------------------------------------------------------------------------------------------------------------------------------
	
	void Update () {
		
		/*	This if statement checks to see if the players position ( specifically, this game object) has got the size of the cube * blockAhead
		 * 	 distance away form the last block. Essentially blocksAhead variable tests to see if the player is that many blocks away from hitting the end
		 * It then creates an amount of blocks based on blockCreateAmount variable ... so 3 which seems to be enough at most speeds.
		 */
		
		if(this.transform.position.z >= lastBlockPosition.z - (blocksInLevel[blocksInLevel.Count-1].transform.lossyScale.z * blocksAhead)){
			for (int i = 0; i < blockCreateAmount; i++) {
				CreateBlock();
				Destroy(blocksInLevel[blockDeleteCounter]);
				blockDeleteCounter++;
			}
			
		}
	}
	
	/*
	 * This cretes a single block and adds it to the blocksInLevel List <GameObject> : This is done to keep an eye on the order and allow you to remove 
	 * Blocks based on their order or loop blocks or slice parts out of the list for isolated selection.
	 */
	
	void CreateBlock (){
		try {
			GameObject tmpCube = (GameObject)Instantiate(prefabs[ Random.Range(0, prefabs.Count - 1) ] );
			tmpCube.transform.parent = BlockStorage.transform;
			blocksInLevel.Add(tmpCube);
			tmpCube.transform.position = cubeSpawnPoint.position; 			
			tmpCube.transform.Translate(0.0f ,0.0f , lastBlockPosition.z + tmpCube.transform.localScale.z);
			lastBlockPosition = tmpCube.transform.position;
			
			
		} catch{
			print("There is an issue with the prefabs array, make sure it has at is populated and there are no empty slots.");
		}
		
	}
	
	
	// THIS IS FOR DEMONSTRATION YOU MAY REMOVE THIS
	// -------------------------------------------------------------------------------------------------------------------------------------------
	void FixedUpdate()
	{
		float speed = 0.05f;
	    rigidbody.AddForce(transform.forward * speed, ForceMode.VelocityChange);
	}
	// -------------------------------------------------------------------------------------------------------------------------------------------

	
}

Your code returned an error. ArgumentOutOfRangeException: Argument is out of range.
Parameter name: index