- Home /
Delay a prefab instantiate
I am doing a infinite ball rolling game and I have a script to instantiate obstacles for the player to avoid. Here it is:
using UnityEngine;
using System.Collections.Generic;
public class ColliderManager : MonoBehaviour {
public Transform prefab;
public int numberOfObjects;
public float recycleOffset;
public Vector3 minSize, maxSize, minGap, maxGap;
public float minx, maxx;
public Material[] materials;
public PhysicMaterial[] physicMaterials;
//public Booster booster;
private Vector3 nextPosition;
private Queue<Transform> objectQueue;
void Start () {
//GameEventManager.GameStart += GameStart;
//GameEventManager.GameOver += GameOver;
//GameStart();
//objectQueue = new Queue<Transform>(numberOfObjects);
//for(int i = 0; i < numberOfObjects; i++){
// objectQueue.Enqueue((Transform)Instantiate(prefab, new Vector3(0f, 0f, 0f), Quaternion.identity));
//}
//enabled = true;
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.z + recycleOffset < Runner.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.z += scale.z * 0.5f;
position.y += scale.y * 0.5f;
//booster.SpawnIfAvailable(position);
Transform o = objectQueue.Dequeue();
o.localScale = scale;
o.localPosition = position;
int materialIndex = Random.Range(0, materials.Length);
o.renderer.material = materials[materialIndex];
o.collider.material = physicMaterials[materialIndex];
objectQueue.Enqueue(o);
nextPosition += new Vector3(
Random.Range(minGap.x, maxGap.x),
Random.Range(minGap.y, maxGap.y),
Random.Range(minGap.z, maxGap.z) + scale.z);
if(nextPosition.x < minx){
nextPosition.x = minx - minGap.x;
}
else if(nextPosition.x > maxx){
nextPosition.x = maxx - maxGap.x;
}
}
}
The problem is that sometimes when you start the game you run straight into on of the collider obstacles. So my question is if there is a way for me to delay the script for just a few seconds so the player can get going (it's not exactly fun blowing up on start). Thanks in advance for any help.
Answer by Fattie · Sep 08, 2012 at 07:07 AM
simply use Invoke() in Unity to time things and start things off at different times.
it's a strange thing that many beginners seem not to know about this command (who knows why). it is a basic command you use constantly, all the time, in video games - it's how you start basically anything happening in your game.
you also have InvokeRepeating, and CancelInvoke
so you might have something like
// have this line of code in say Start() ...
InvokeRepeating( "makeAmazingObstacle", 5, 5 );
function makeAmazingObstacle()
{
// write your obstacle routine here
// instantiate an obstacle or whatever
}
Note that inside makeAmazingObstacle, you could well have code like this for example...
Invoke( "hugeFlashingLight", 2.0 );
Invoke( "shakeScreen", 2.1 );
Invoke( "hugeFlashingLight", 2.5 );
Invoke( "changeColoursOfObstacleToRed", 4.75 );
invoke( "getRidOfTheObstacle", 4.95 );
you get it? it's the basic command you use to make video games.
That is extremely useful, and a lot easier then the timers I've been using. I'm surprised this hasn't been in any of the tutorials I've looked at so far. Thank you very much for the info.
it tells me that it needs to be a string, not a GameObject
Thanks. Invoke was obvious but i didn't know "CancelInvoke" :)
Answer by ow3n · Feb 26, 2017 at 01:20 PM
Adding this for others' reference... I tried some of these but used frameCount and modulus instead. This will add a new prefab every time another 20 frames passes.
public class GameController : MonoBehaviour {
private int count = 0;
private int limit = 25;
public GameObject prefab;
void Update(){
Debug.Log(Time.frameCount);
if (count < limit && Time.frameCount % 20 == 0) {
Instantiate(prefab);
count++;
}
}
}
This is an old answer, but... The problem with this approach is that the time to calculate 20 frames will be different on every machine, depending on the framerate. With the Invoke() method described in the accepted answer is much better as it relies on time, not on frames.
Answer by ThermalFusion · Sep 07, 2012 at 09:58 PM
Add a simple started bool you check for, and toggle it on some seconds into the game.
Have the script disabled on start, then enable it a few seconds later.
Answer by kottabos · Sep 08, 2012 at 03:02 AM
First off thanks for the response, technically it worked. problem is though is that now the colliders all spawn at once including where the player is. So I guess I'll have to figure something else out. Thanks again though.
Answer by RetepTrun · Sep 10, 2012 at 02:14 PM
Add this 1st thing in your start
yield WaitForSeconds(2);
using "Yield" inside Start is a troubling idea - it would be better to avoid this
very simply, go Invoke("actionBegins!", 2.0); inside Start or Awake.
then in your routine "Action begins!", just do anything you want to have fun in the game.
it's the simplest and tidiest way.