- Home /
how to call something just once from an update function
Hi,
I have level0 (small) and level1 (large). I have the build set up so level0 loads first. I would then like to load an object (a door) into level0 when level1 had finished loading. I am using the Update() function to determine when level 1 has finished loading, but I find that if I try to instantiate the door from inside the Update() function, I get many many doors. Is there a way to get just one door? Here's the code. Thanks. Zaffer
function Update() {
if(Application.GetStreamProgressForLevel(levelToLoad) == 1) {
Progress.message = "Level at index 1 has been fully streamed!";
Instantiate(door, Vector3(154, 1.8, 166), Quaternion.identity);
level1Ready = true;
}
else {
percentageLoaded = Application.GetStreamProgressForLevel(levelToLoad) * 100;
Progress.message = percentageLoaded.ToString();
level1Ready = false;
}
}
Thanks Eric5h5,
Would greatly appreciate it if you would show me how to set up the coroutine. Thanks.
Zaffer
Thanks for the tip. I will read up on coroutines and try to figure out.
Zaffer
Hi Tim and Eric5h5:
Still getting lots of doors. Am I getting warmer? Thanks. Zaffer
function Update() { if(Application.GetStreamProgressForLevel(levelToLoad) == 1) { Progress.message = "Level at index 1 has been fully streamed!"; StartCoroutine($$anonymous$$akeDoor()); level1Ready = true; } else { percentageLoaded = Application.GetStreamProgressForLevel(levelToLoad) * 100; Progress.message = percentageLoaded.ToString(); level1Ready = false; } }
function $$anonymous$$akeDoor(){ yield Instantiate(door, Vector3(154, 1.8, 166), Quaternion.identity);
}
I think you don't need the Update() function.
I'll write something down here which I think is more like what your coroutine should look like: (sorry it's in C#)
IEnumerator LoadInOrder() { level1Ready = false;
//Wait while the scene is loading, this while loop will act as a "temporary update" until the scene is fully loaded
while (Application.GetStreamProgressForLevel(levelToLoad) < 1)
{
percentageLoaded = Application.GetStreamProgressForLevel(levelToLoad) * 100;
Progress.message = percentageLoaded.ToString();
yield return new WaitForEndOfFrame();
}
//Scene was fully loaded
level1Ready = true;
Progress.message = "Level at index 1 has been fully streamed!";
Instantiate(door, Vector3(154, 1.8, 166), Quaternion.identity);
}
You should start this coroutine after you started loading the level. Then, this coroutine will perform the while loop until it is fully loaded, whereafter your door will only be instantiated once.
Hope this is what you want to achieve.
Answer by Eric5h5 · Jun 19, 2012 at 01:52 AM
You'd be better off not using Update, but rather a coroutine, since the point of Update is that it runs every frame. With a coroutine you can just wait until the event is done and run the code afterward once.
Answer by Tim-Michels · Jun 19, 2012 at 08:27 AM
Here's an exampe on how to use a coroutine: In this (really simple) example the coroutine gets started in the Start() function.
void Start()
{
StartCoroutine(DoSomeStuff());
}
IEnumerator DoSomeStuff()
{
//"Ready" gets logged
Debug.Log("Ready");
//Coroutine will wait 1 second to continue
yield return new WaitForSeconds(1.0f);
//"Set" gets logged
Debug.Log("Set");
//Coroutine will wait 1 second to continue
yield return new WaitForSeconds(1.0f);
//"Go" gets logged
Debug.log("Go");
...
}
You can do anything you like within a coroutine, the "yield" statement simply sets the function on "hold" for how long you choose.
You can also use "yield return new WaitForEndOfFrame()" and other functions. When you get the hang of coroutines, you can do some really cool stuff with it.
Cheers.
Answer by Zaffer · Jun 19, 2012 at 02:30 PM
Hi,
It took me awhile, but I finally figured out I could do what I wanted with a simple Boolean variable, doorPresent, which I set false in the Start() function. Then I set that to true after making only one door. Seems to be working so far. Coroutines and yield look really interesting -- will study them more. Thanks. Zaffer
function Update() {
if(Application.GetStreamProgressForLevel(levelToLoad) == 1) {
Progress.message = "Level at index 1 has been fully streamed!";
//StartCoroutine(MakeDoor());
MakeDoor();
level1Ready = true;
}
else {
percentageLoaded = Application.GetStreamProgressForLevel(levelToLoad) * 100;
Progress.message = percentageLoaded.ToString();
level1Ready = false;
}
}
function MakeDoor(){
//yield;
if(doorPresent == false){
Instantiate(door, Vector3(154, 1.8, 166), Quaternion.identity);
doorPresent = true;
}
}
Well, this is merely a hack. It will work, but you're better off using the method I just posted.
Greets
This is how I handle everything haha, coroutines scare me! Thanks for the question though. Do you know if this method slows down the game at all or if it is okay?
Answer by Zaffer · Jul 03, 2012 at 08:24 PM
Hi Eric5h5 and Tim,
I wanted to take your advice about coroutines being better, and after some work, I was able to set up a loading sequence using a while loop, yield and coroutines instead Update(). I needed a little help from regular forum, but everything works. Here's the code. Zaffer
P.S. You are right, Tim, couroutines are very cool!
function Start(){ ManageLoadingElements(); }
function ManageLoadingElements(){
yield StartCoroutine("SetUpLoadingElements");
TakeDownLoadingElements();
}
function SetUpLoadingElements(){
while(Application.GetStreamProgressForLevel(levelToLoad) < 1){
percentageLoaded = Application.GetStreamProgressForLevel(levelToLoad) * 100;
progressCylinder.transform.localScale.x = percentageLoaded * 0.1;
progressCylinder.transform.position = progressCylinderPosition;
progressText3D.text = Mathf.RoundToInt(percentageLoaded) + "%";
yield;
}
}
function TakeDownLoadingElements(){
Destroy(progressCylinder);
Destroy(progressText3D);
MakeDoor();
}
function MakeDoor(){
var door : GameObject;
if(doorPresent == false){
door = Instantiate(doorPrefab, Vector3(157, 2.65, 169.59), Quaternion.identity);
doorPresent = true;
door.name = "Iron Door";
}
}
Answer by Luci85 · Jul 03, 2012 at 08:34 PM
I would use a boolean variable, that is true only for the first run.
var firstCall:Boolean;
void Start()
{
firstCall = true;
}
function Update() {
if(Application.GetStreamProgressForLevel(levelToLoad) == 1) {
Progress.message = "Level at index 1 has been fully streamed!";
//StartCoroutine(MakeDoor());
if(firstCall)
{
MakeDoor();
firstCall = false;
}
level1Ready = true;
}
else {
percentageLoaded = Application.GetStreamProgressForLevel(levelToLoad) * 100;
Progress.message = percentageLoaded.ToString();
level1Ready = false;
}
}
But if you get more than one door, then that means the else branch isn't called as it should be, right?
I have not actually tried your idea, just thought it looked like a good solution.
Your answer
Follow this Question
Related Questions
How should i add raycast to multiple game objects??? 0 Answers
Prefabs Transforms LookAt 0 Answers
Refrencing Instantiated Object 1 Answer
How to detect empty slot and spawn gameobject there? 1 Answer