Remind me again ... stuff AFTER function Update () is true?

Good morning all!

I’m actually getting much better at coding than I ever was (thanks mostly to a couple of forum regulars here who are remarkably patient with the old guy) … but I’ve forgotten how to call or make functions happen that are dependent on a condition in the function Update () statement being true.

This mostly revolves around a yeild/waitforseconds need … so that the general idea is that if time has run out (being tested in a function Update () then several thing have to happen …

This is my current function Update () code that works well so far …

function Update () 
{

	/* mathf.floor forces it to round to 0 */
	timershow.text = "time left=" + Mathf.Floor(GameController.timeLeft);		
	// sets up time to count down and control the time counting down
	GameController.timeLeft -= Time.deltaTime;   
	 	
	// checks to see if time has run out 
    if (GameController.timeLeft < 0) {
		// put "0" into the timeleft display
		timershow.text = "0";
		
		// play whistle sound twice
               // HOW DO I GET THE CLIP TO PLAY FOR ONLY ONE SECOND??
		audio.clip = whistleClip;
		audio.Play();
		
		// pause time time - either with Time.timeScale = 0 or using our method of pausing game
		GamePlayScript = GameObject.Find("ScriptHolder").GetComponent(GamePlay);
		GamePlayScript.AreWePaused = true;
	    // Time.timeScale = 0;
		
	// HOW DO I SHOW THIS ONLY FOR 3 SECONDS???	
          // display level done message in text Status GO for 3 seconds
		gameovermessage.text = "Time has run out!";
		
		// AFTER 3 SECONDS SHOW THE GUI STUFF
		// show GUI stuff from above
						
		// show cursor and unlock screen and disable mouse look off of player character
		// MOUSELOOK DISABLED
		Screen.lockCursor = false;
		Screen.showCursor = true;					
    }
	
}

The parts I need clarification on and need to be taken out of Update are noted with a comment.

Here is the GUI code that is referred to … again this works perfectly well but obviously appears right away since my test scenario has the time already down to 0 …

function OnGUI () {
	// Assign the skin to be the one currently used.
	GUI.skin = mySkin;
	// create a window with controls inside it
	var windowRect : Rect = Rect (Screen.width / 2 - 150, Screen.height / 2 - 100, 300, 200);
	windowRect = GUI.Window (0, windowRect, WindowFunction, "Level complete!");
}

// control the contents of the submit score window here for simplicity
function WindowFunction (windowID : int) {
	// Draw controls inside the window here for ease of later fixes
	var levelOverInstructions = "\nTime has run out. You can now submit your score online, play again, or quit the game.\n";
	GUI.Label (Rect (25,20,250,60), levelOverInstructions);
	
	// need to add a field to show player final score with multiplier here
	
	var submitNameString = "Click here to enter your name";
	submitNameString = GUI.TextField (Rect (50,80,200,20), submitNameString);
	
	// then we show three buttons to submit score, play again, or quit
	if (GUI.Button (Rect (75,110,150,25), "Submit Score")) {
			// submit scores to server code goes here -- I have this done but not added
			// load level Scores
			Application.LoadLevel ("Scores");
		}
	if (GUI.Button (Rect (40,155,100,25), "Play Again")) {
			// don't submit score and simply take player back to select screen
			Application.LoadLevel ("Select");
		}
	if (GUI.Button (Rect (160,155,100,25), "Quit")) {
			// don't submit score and send player to credit screen
			Application.LoadLevel ("Credits");
		}
}

I have commented out the stuff I know I need to remove from Update but what’s the format for bringing it in from another function elsewhere in the code? And how do you get around the issue of not being able to use yield/waitforseconds inside an Update again?

Thanks for the repeated patience :slight_smile:

Edit … it’s something like this isn’t it …

function Update () 
{

	/* mathf.floor forces it to round to 0 */
	timershow.text = "time left=" + Mathf.Floor(GameController.timeLeft);		
	// sets up time to count down and control the time counting down
	GameController.timeLeft -= Time.deltaTime;   
	 	
	// checks to see if time has run out 
    if (GameController.timeLeft < 0) {
		// DO function restofstuff ();				
    }
	
}

function restofstuff ()
{
// put "0" into the timeleft display
		timershow.text = "0";
		
		// play whistle sound twice
               // HOW DO I GET THE CLIP TO PLAY FOR ONLY ONE SECOND??
		audio.clip = whistleClip;
		audio.Play();
		
		// pause time time - either with Time.timeScale = 0 or using our method of pausing game
		GamePlayScript = GameObject.Find("ScriptHolder").GetComponent(GamePlay);
		GamePlayScript.AreWePaused = true;
	    // Time.timeScale = 0;
		
	// HOW DO I SHOW THIS ONLY FOR 3 SECONDS???	
          // display level done message in text Status GO for 3 seconds
		gameovermessage.text = "Time has run out!";
		
		// AFTER 3 SECONDS SHOW THE GUI STUFF
		// show GUI stuff from above
						
		// show cursor and unlock screen and disable mouse look off of player character
		// MOUSELOOK DISABLED
		Screen.lockCursor = false;
		Screen.showCursor = true;	
}

But isn’t there a problem pulling yeilds into an update??

There are two ways to do it. One is to have a timer variable: when you “start” it you set it to Time.time and start the audioclip playing, and then you test the variable and when (Time.time > yourTimerVariable + 3.0) you can stop the sound.

The other way is to write coroutines. That’d look something like:

function Update() {
    if (GameController.timeLeft < 0) { 
      // put "0" into the timeleft display 
      timershow.text = "0"; 
      PlaySoundForOneSecond();
}
}

function PlaySoundForOneSecond() { 
      audio.clip = whistleClip; 
      audio.Play();
      yield WaitForSeconds(1);
      audio.Stop(); 
}

Note that a yield can’t be used in Update itself - you have to put it in a separate function.

Yield can be used in a function outside of update and then be called in! That’s what I need to figure out the rest on my own … thanks a bunch StarManta! I keep forgetting this fact.

function Update() {
    if (GameController.timeLeft < 0) {
      // put "0" into the timeleft display
      timershow.text = "0";
      PlaySoundForOneSecond();
}
}

function PlaySoundForOneSecond() {
      audio.clip = whistleClip;
      audio.Play();
      yield WaitForSeconds(1);
      audio.Stop();
}

However, in this case you will basically create a new copy of the PlaySoundForOneSecond function every frame, therefore you will hear the first part of the sound over and over. What I am assuming you want to do is somewhat like a playlist of actions that happen one after another with specified times in between. However, you want to have some actions get called every frame while you wait (setting the timer for example). There are two ways to do this, one is a state machine running in update and the other is a more complicated coroutine. I think the coroutine method is simplest, so here goes an example:

function Start ()
{
	LevelRoutine();	
}

function LevelRoutine ()
{
	// wait for the time to run down, in a loop this time:
	while(GameController.timeLeft > 0)
	{
		GameController.timeLeft -= Time.deltaTime; // subtract the time last frame took from the time left..
		timershow.text = "time left=" + Mathf.Floor(GameController.timeLeft);  // .. and then display it, never less than 0
		yield;	// wait one frame
	}

	// put "0" into the timeleft display (this is redundant because we subtract first and then clamp in our loop)
	timershow.text = "0";
      
	// play whistle sound twice!
	audio.clip = whistleClip;
      
	audio.Play();
	yield	WaitForSeconds(whistleClip.length);
      
	audio.Play();
	yield	WaitForSeconds(whistleClip.length);
      
	// pause time time - either with Time.timeScale = 0 or using our method of pausing game
	GamePlayScript = GameObject.Find("ScriptHolder").GetComponent(GamePlay);
	GamePlayScript.AreWePaused = true;
	// Time.timeScale = 0;
      
	// display level done message in text Status GO for 3 seconds
	gameovermessage.text = "Time has run out!";
	
	yield WaitForSeconds(3);
      
	// show GUI stuff from above
                  
	// show cursor and unlock screen and disable mouse look off of player character
	// MOUSELOOK DISABLED
	Screen.lockCursor = false;
	Screen.showCursor = true;               

}