Randomly switching between prefabs

hi guys,

I’m a total noob at unity so I hope this question isn’t too dumb,

I have made 3 prefabs each with different scripts attached (c#) and I need them to switch randomly between one another. For example, I have a platform block (with certain properties in the script)and I need it to possibly “become” another type of block with a different script attached or even stay the same.

I there any way to do this? I would also be helpful if this were attached to a counter so that it would change say, every 5 seconds.

I would be very grateful for your help but like I say I am new so you may have to spell it out LOL.

Thanks

(I’m coding in c#)

As far as I understand from your question, your trying to randomly change a “Script” attached to a prefab depending on some condition or randomly.

I don’t know if it is possible to remove a script which is already applied to a prefab but as a solution I could suggest you make a “switch case” combining the 3 or 4 scripts your trying to jump between in a single file.

The randomness of the number can be taken from here. (you would need to typecast or round off the randomness to an int which the switch case would use)

Hope it helps, I have not tried this myself though.

You can for example make an empty GameObject, and make each block child of that empty. Then you can activate random blocks from a script attached to the empty. I have created an example script you can attach your empty GameObject. If the blocks have to repositioning or something like that each time before the block is activated, you can create a StartOver function in the scripts attached to the blocks. Then just call that function from the script attached to the empty. Maybe not the best way to do it, but I think it should work. I assumed the mesh and/or material in each prefab were different from the other prefabs’ mesh, and a property script is attached in each prefab.

using UnityEngine;
using System.Collections;

public class BlockSwitcher : MonoBehaviour {
	public float secondsToNextBlock = 5.0f;
	private Transform[] blocks;
	private bool timeToChange = false;
	private int currentBlock = 1;
	
	void Awake () {
		blocks = gameObject.GetComponentsInChildren<Transform>();

	}
	
	void Start () {
		foreach (Transform t in blocks) {
			if (t.gameObject!=gameObject)
				t.gameObject.active = false;
		}
		timeToChange = true;
	}
	
	void Update () {
		if (timeToChange) {
			timeToChange = false;
			StartCoroutine("ChangeBlock");
		}
	}
	
	IEnumerator ChangeBlock () {
		blocks[currentBlock].gameObject.active = false;
		currentBlock = Random.Range(1,blocks.Length);
		blocks[currentBlock].gameObject.active = true;
		
		yield return new WaitForSeconds(secondsToNextBlock);
		timeToChange = true;
	}
	
}

To make a counter - or make something happen every X seconds - there are a few approaches. You can use a decremented float with Time.deltaTime, have an infinite loop with a yield instruction or just use InvokeRepeating etc.

Some approaches are demonstrated in this script here:

using UnityEngine;
System.Collections;
    
class TimerExamples: MonoBehaviour
{ 

	//array of supplied prefabs to choose from
	public GameObject[] PrefabPool;

	//arbitrary value to demonstrate the difference between first invoke and future invokes
	public float TimeToFirstInvoke = 2;
    
	//the time to wait between future invokes beyond the first
	public float FutureInvokeInterval = 5;

	//the actual timer
	public float RunningTimer;
    
	// Use this for initialization
	IEnumerator Start()
	{
		//resetting the timer to the initial value
		RunningTimer = FutureInvokeInterval;
   		
		//this will invoke the black magic method after the TimeToFirstInvoke, and then every FutureInvokeInterval seconds
		InvokeRepeating("BlackMagicMethod", TimeToFirstInvoke, FutureInvokeInterval);
    
		//wait for the first invoke
		yield return new WaitForSeconds(TimeToFirstInvoke);

		BlackMagicMethod();
   		
		//this loop will run forever, calling the black magic method every FutureInvokeInterval seconds
		while (true)
		{
			BlackMagicMethod();
  
			//wait for the interval between future invokes
			yield return new WaitForSeconds(FutureInvokeInterval);
		}
	}
    
	// Update is called once per frame
	void Update()
	{
		if (RunningTimer > 0)
		{
			//this will decrement the timer gradually over time
			RunningTimer -= Time.deltaTime;
		}
		else
		{
			//this resets the timer 
			RunningTimer = FutureInvokeInterval;
    
			BlackMagicMethod();
		}
	}

	/// <summary>
	/// this method switches the current prefab with a random one from the supplies array
	/// by instantiating the substitute and then killing the current prefab
	/// </summary>
	void BlackMagicMethod()
	{
		//first instantiate the substitute, choosing a random prefab from the array
		Instantiate(PrefabPool[Random.Range(0, PrefabPool.Length)], transform.position, transform.rotation);

		//we destroy the gameObject and not the transform or 'this' because 
		//those would only destroy the component and we want to get rid of everything
		Destroy(gameObject);
	}
}

The BlackMagicMethod first creates a substitute for the existing prefab by choosing a random prefab from the supplied array and then kills the current object this script is attached to to create the illusion of a ‘switch’ between prefabs.

It’s not the perfect approach, and obviously you should never actually attach this script to anything (unless you want three separate calls to the BlackMagicMethod), it’s here to demonstrate a point. Or three. :slight_smile: