For the past few hours I’ve been trying to recreate a GIF (which is how I learn) that consists out of balls that move to the opposite side and back in a loop. Every second a new ball starts moving and in the end it becomes one moving circle.
Now my problem is that I set all the balls in the level, but I need them to activate/start moving/show up with a delay that I can set. I’m no programmer and I use scripts by duct taping code together from all over the place but I can’t seem to find a solution to this. I did find out how to delay a moving platform (example) at points when it has already started moving but that is not quite what I need here.
I have the impression that this shouldn’t be as hard as I’m finding it to be. Any way to simply have a script on an object that says: “stay where you for … seconds” or “when the level is loaded spawn after … seconds” ?
You could create a sprite that switch after a couple of ms. You can create a class where the sprite is an array. Then create a coroutine func which will switch sprite after yield.
Depending on exactly how the GameObject is drawing something will make the details slightly different (Is it a 2D Sprite with an Image Script, is it a 3D object with a MeshRenderer,etc). But here is code that will make an object wait X Seconds then turn on.
void Awake()
{
Image image = GetComponent<Image>();
image.enabled = false; // this turns off the picture
// if you had a MeshRenderer you could do the same thing:
// You would only do ONE of these not both. depending on whats
// on your object
MeshRenderer renderer = GetComponent<MeshRenderer>();
renderer.enabled = false;
// this will wait 2 seconds before turning on
StartCoroutine(WaitToDisplay(2.0f));
}
IEnumerator WaitToDisplay(float seconds)
{
yield return new WaitForSeconds(seconds);
Image image = GetComponent<Image>();
image.enabled = true;
}
Its slightly more complicated to make something stop and start in the update function but not too tricky:
public float runTime = 2.0f; // how long we should run for
public float pauseTime = 2.0f // how long we should pause for
bool paused = false; // are we paused?
float currentRunTime =0.0f; // Tracks how long we've been runnning
void Update()
{
if (!paused)
{
// Do all you unPaused code here.
// animating stuff, moving it whatever
currentRunTime += Time.deltaTime;
if (currentRunTime >= runTime)
{
paused = true;
currentRunTIme = 0.0f;
StartCoroutine(DoPause());
}
}
}
IEnumerator DoPause()
{
yield return new WaitForSeconds(pauseTime);
paused = false;
}
I altered the first set of code to the one below (3D with game objects). It does turn off the game object but it doesn’t seem to turn it back on. I tried it with both and without the meshrenderer code. I get this error message: “Coroutine couldn’t be started because the the game object ‘Sphere’ is inactive! UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
StartDelay:Awake() (at Assets/StartDelay.cs:21”
using UnityEngine;
using System.Collections;
public class StartDelay : MonoBehaviour
{
void Awake()
{
GameObject gameobject = GetComponent<GameObject>();
gameObject.SetActive(false);
// this turns off the picture
// if you had a MeshRenderer you could do the same thing:
// You would only do ONE of these not both. depending on whats
// on your object
MeshRenderer renderer = GetComponent<MeshRenderer>();
renderer.enabled = false;
// this will wait 2 seconds before turning on
StartCoroutine(WaitToDisplay(2.0f));
}
IEnumerator WaitToDisplay(float seconds)
{
yield return new WaitForSeconds(seconds);
GameObject gameobject = GetComponent<GameObject>();
gameObject.SetActive(true);
}
}
With the other set of code I get a teleporting type of situation where the object disappears every few seconds, but I need it to only stay away at the start for a few seconds and then function as it normally would.
using UnityEngine;
using System.Collections;
public class StartDelay3 : MonoBehaviour
{
//use inspector for object position, adjust 0,0,0 for direction of object
public Vector3 pos1 = new Vector3(-4, 0, 0);
public Vector3 pos2 = new Vector3(4, 0, 0);
public float speed = 1.0f;
public float runTime = 2.0f; // how long we should run for
public float pauseTime = 2.0f; // how long we should pause for
bool paused = false; // are we paused?
float currentRunTime = 0.0f; // Tracks how long we've been runnning
void Update()
{
if (!paused)
{
// Do all you unPaused code here.
// animating stuff, moving it whatever
transform.position = Vector3.Lerp(pos1, pos2, (Mathf.Sin(speed * Time.time) + 1.0f) / 2.0f);
currentRunTime += Time.deltaTime;
if (currentRunTime >= runTime)
{
paused = true;
currentRunTime = 0.0f;
StartCoroutine(DoPause());
}
}
}
IEnumerator DoPause()
{
yield return new WaitForSeconds(pauseTime);
paused = false;
}
}
which turns Everything on that game Object off… including THIS script. So once its turned off it can’t turn itself back on.
You have just disable the image drawing portion with .enable = true/false; You can only use SetActive() from a different gameobject if you ever want to turn it back on.
Ah ok, I see. I thought that Image was for 2D and sprites or something so I turned them into game objects. I get the following error message with Image:
" Severity Code Description Project File Line Suppression State
Error CS0246 The type or namespace name ‘Image’ could not be found (are you missing a using directive or an assembly reference?)"
Image IS for 2D sprites, I commented in my original post you would have to change Image to whatever you were using to display your image. Are you using a Mesh and a MeshRenderer? is so you need to use this code:
Thank you. It works now. Sorry for the misunderstanding.
Is there a way to have the " StartCoroutine(WaitToDisplay(2.0f)); " visible and adjustable in the inspector? So I can have multiple objects with the same script but with different times of appearance?
Stick that on every GO that needs to be delayed. You can have other scripts on it too. Then change the StartDelay in the editor for how long it should delay before starting
Before, I changed Image/Meshrenderer to GameObject and that turned the object off completely right? Could I use another object as a spawning system and use this script to have the Objects actually become active at those set delays instead of just showing up / showing the image? Although the script works now it’s not quite what I had in mind because the balls move through each other since there is no delay in when they start moving, if that makes sense.
This is the code that I sort of scrambled together in the process:
using UnityEngine;
using System.Collections;
public class SpawnDelay2 : MonoBehaviour
{
//Sphere can be any object.
public GameObject Sphere1;
public GameObject Sphere2;
float timer = 0f;
void Start()
{
Instantiate(Sphere1, new Vector3(0, 0, 0), Quaternion.identity);
}
// Update is called once per frame
void Update()
{
timer += Time.deltaTime;
if (timer >= 2)
{
Instantiate(Sphere2, new Vector3(0, 0, 0), Quaternion.identity);
}
}
}
but I couldn’t get it to work properly and it creates an endless amount of clone objects, whereas I just want only the few objects on a pre set location that I’ve set in the editor. I just want them to activate with a delay as we’ve done with the Meshrenderer.
Make your sphere object with all its scripts + my Delay script… Then drag it down and make it a prefab. Call it DelaySphere. Don’t have any actual spheres in the Scene, Create a Empty GameObject with this script:
using UnityEngine;
using System.Collections;
public class SpawnDelay2 : MonoBehaviour
{
// I set it to create 4 objects, change it to what you need
int numberObjects = 4;
// These variables all need to be assigned in the editor
public GameObject prefab;
public Vector3[] positions = new Vector3[numberObjects];
public StartDelay; // the delay between each object
void Start()
{
for (int i=0;i<numberObjects;i++)
{
GameObject nextObj = Instantiate(Sphere1, new Vector3(0, 0, 0), Quaternion.identity);
nextObj.transform.position = positions[i];
DelayScript delayScript = nextObj.GetComponent<DelayScript>();
delayScript.DelayTime = (i+1)*StartDelay;
}
}
}
The positions variable will be an expandable one, that you can set the positions of all your objects in (x,y,z)
All your objects will slowly pop in each a set amount apart. If StartDelay =2seconds… then you will get an object popping in at 2,4,6,8 seconds
Thanks. I’ve made a DelaySphere prefab with scripts attached and an empty ‘spawner’ object, but for some reason I get all sorts of errors with the above script.
“Invalid token ‘;’ in class, struct, or interface member declaration - 11 - Active”
“A field initializer cannot reference the non-static field, method, or property 'SpawnDelay2.numberObjects - 10 - Active”
“The name ‘StartDelay’ does not exist in the current context.”
“The name ‘Sphere1’ does not exist in the current context - 16 - Active”
“Unexpected symbol `;’ in class, struct, or interface member declaration - 11”
I don’t even know how where to even begin how to solve this…
You’d have to post the code of script thats giving you errors
Though I can tell you this error:
Is because you have a class somewhere called SpawnDelay2. That class is the master blueprint for that class. Your not allowed to just modify or access that class directly. You need to make an instance of it. (Create an object from class). That is basically what your doing when you put a script on a Game Object. However, if you try to access SpawnDelay2 from another script, it will yell at you for trying to mess with the master blueprint you would need something like this:
SpawnDelay2 script = TheOtherGameObject.GetComponent<SpawnDelay2>();
// then we can modify things in spawndelay2 since we have a handle on the instance of spawndelay2 we created
script.numberObjects -10
Though you shouldn’t have to access SpawnDelay2 from somewhere else… Its your “controller”. You should be using the public variables I posted in the script to let SpawnDelay2 run everything.
Alright. So this is the DelayScript I have on the DelaySphere (prefab):
using UnityEngine;
using System.Collections;
public class DelayScript : MonoBehaviour
{
public float DelayTime;
void Awake()
{
MeshRenderer renderer = GetComponent<MeshRenderer>();
renderer.enabled = false;
StartCoroutine(WaitToDisplay(DelayTime));
}
IEnumerator WaitToDisplay(float seconds)
{
yield return new WaitForSeconds(seconds);
MeshRenderer renderer = GetComponent<MeshRenderer>();
renderer.enabled = true;
}
}
And this is the script that I’m having issues with that is for the spawner object:
using UnityEngine;
using System.Collections;
public class DelaySpawner : MonoBehaviour
{
// I set it to create 4 objects, change it to what you need
int numberObjects = 4;
// These variables all need to be assigned in the editor
public GameObject prefab;
public Vector3[] positions = new Vector3[numberObjects];
public StartDelay; // the delay between each object
void Start()
{
for (int i = 0; i < numberObjects; i++)
{
GameObject nextObj = Instantiate(Sphere1, new Vector3(0, 0, 0), Quaternion.identity);
nextObj.transform.position = positions[i];
DelayScript delayScript = nextObj.GetComponent<DelayScript>();
delayScript.DelayTime = (i + 1) * StartDelay;
}
}
}
These are the 2 active scripts (+1 for moving the spheres) but I’m not seeing where, or how, they cause the errors. The issue seems to be the word “StartDelay” and a ; sign that is seen as invalid?
Now these errors are remaining:
"A field initializer cannot reference the non-static field, method, or property ‘DelaySpawner.numberObjects’ "
" Unexpected symbol `;’ in class, struct, or interface member declaration "
"The name ‘Sphere1’ does not exist in the current context "
Any ideas about these? I tried to change the name of Sphere 1 to DelaySphere but that doesn’t work.
I can’t find any ; signs that are missing or can be removed to fix it.
And the error about the [numberObjects] does not even make sense to me.