Search Unity

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

Discussion in 'Scripting' started by DaveyJJ, Nov 16, 2007.

  1. DaveyJJ

    DaveyJJ

    Joined:
    Mar 24, 2005
    Posts:
    1,558
    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 ...

    Code (csharp):
    1.  
    2. function Update ()
    3. {
    4.  
    5.     /* mathf.floor forces it to round to 0 */
    6.     timershow.text = "time left=" + Mathf.Floor(GameController.timeLeft);      
    7.     // sets up time to count down and control the time counting down
    8.     GameController.timeLeft -= Time.deltaTime;  
    9.        
    10.     // checks to see if time has run out
    11.     if (GameController.timeLeft < 0) {
    12.         // put "0" into the timeleft display
    13.         timershow.text = "0";
    14.        
    15.         // play whistle sound twice
    16.                // HOW DO I GET THE CLIP TO PLAY FOR ONLY ONE SECOND??
    17.         audio.clip = whistleClip;
    18.         audio.Play();
    19.        
    20.         // pause time time - either with Time.timeScale = 0 or using our method of pausing game
    21.         GamePlayScript = GameObject.Find("ScriptHolder").GetComponent(GamePlay);
    22.         GamePlayScript.AreWePaused = true;
    23.         // Time.timeScale = 0;
    24.        
    25.     // HOW DO I SHOW THIS ONLY FOR 3 SECONDS???
    26.           // display level done message in text Status GO for 3 seconds
    27.         gameovermessage.text = "Time has run out!";
    28.        
    29.         // AFTER 3 SECONDS SHOW THE GUI STUFF
    30.         // show GUI stuff from above
    31.                        
    32.         // show cursor and unlock screen and disable mouse look off of player character
    33.         // MOUSELOOK DISABLED
    34.         Screen.lockCursor = false;
    35.         Screen.showCursor = true;                  
    36.     }
    37.    
    38. }
    39.  
    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 ...

    Code (csharp):
    1.  
    2. function OnGUI () {
    3.     // Assign the skin to be the one currently used.
    4.     GUI.skin = mySkin;
    5.     // create a window with controls inside it
    6.     var windowRect : Rect = Rect (Screen.width / 2 - 150, Screen.height / 2 - 100, 300, 200);
    7.     windowRect = GUI.Window (0, windowRect, WindowFunction, "Level complete!");
    8. }
    9.  
    10. // control the contents of the submit score window here for simplicity
    11. function WindowFunction (windowID : int) {
    12.     // Draw controls inside the window here for ease of later fixes
    13.     var levelOverInstructions = "\nTime has run out. You can now submit your score online, play again, or quit the game.\n";
    14.     GUI.Label (Rect (25,20,250,60), levelOverInstructions);
    15.    
    16.     // need to add a field to show player final score with multiplier here
    17.    
    18.     var submitNameString = "Click here to enter your name";
    19.     submitNameString = GUI.TextField (Rect (50,80,200,20), submitNameString);
    20.    
    21.     // then we show three buttons to submit score, play again, or quit
    22.     if (GUI.Button (Rect (75,110,150,25), "Submit Score")) {
    23.             // submit scores to server code goes here -- I have this done but not added
    24.             // load level Scores
    25.             Application.LoadLevel ("Scores");
    26.         }
    27.     if (GUI.Button (Rect (40,155,100,25), "Play Again")) {
    28.             // don't submit score and simply take player back to select screen
    29.             Application.LoadLevel ("Select");
    30.         }
    31.     if (GUI.Button (Rect (160,155,100,25), "Quit")) {
    32.             // don't submit score and send player to credit screen
    33.             Application.LoadLevel ("Credits");
    34.         }
    35. }
    36.  
    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 :)

    Edit ... it's something like this isn't it ...

    Code (csharp):
    1.  
    2. function Update ()
    3. {
    4.  
    5.     /* mathf.floor forces it to round to 0 */
    6.     timershow.text = "time left=" + Mathf.Floor(GameController.timeLeft);      
    7.     // sets up time to count down and control the time counting down
    8.     GameController.timeLeft -= Time.deltaTime;  
    9.        
    10.     // checks to see if time has run out
    11.     if (GameController.timeLeft < 0) {
    12.         // DO function restofstuff ();             
    13.     }
    14.    
    15. }
    16.  
    17. function restofstuff ()
    18. {
    19. // put "0" into the timeleft display
    20.         timershow.text = "0";
    21.        
    22.         // play whistle sound twice
    23.                // HOW DO I GET THE CLIP TO PLAY FOR ONLY ONE SECOND??
    24.         audio.clip = whistleClip;
    25.         audio.Play();
    26.        
    27.         // pause time time - either with Time.timeScale = 0 or using our method of pausing game
    28.         GamePlayScript = GameObject.Find("ScriptHolder").GetComponent(GamePlay);
    29.         GamePlayScript.AreWePaused = true;
    30.         // Time.timeScale = 0;
    31.        
    32.     // HOW DO I SHOW THIS ONLY FOR 3 SECONDS???
    33.           // display level done message in text Status GO for 3 seconds
    34.         gameovermessage.text = "Time has run out!";
    35.        
    36.         // AFTER 3 SECONDS SHOW THE GUI STUFF
    37.         // show GUI stuff from above
    38.                        
    39.         // show cursor and unlock screen and disable mouse look off of player character
    40.         // MOUSELOOK DISABLED
    41.         Screen.lockCursor = false;
    42.         Screen.showCursor = true;  
    43. }
    44.  
    But isn't there a problem pulling yeilds into an update??
     
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    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:
    Code (csharp):
    1.  
    2. function Update() {
    3.     if (GameController.timeLeft < 0) {
    4.       // put "0" into the timeleft display
    5.       timershow.text = "0";
    6.       PlaySoundForOneSecond();
    7. }
    8. }
    9.  
    10. function PlaySoundForOneSecond() {
    11.       audio.clip = whistleClip;
    12.       audio.Play();
    13.       yield WaitForSeconds(1);
    14.       audio.Stop();
    15. }
    16.  
    Note that a yield can't be used in Update itself - you have to put it in a separate function.
     
  3. DaveyJJ

    DaveyJJ

    Joined:
    Mar 24, 2005
    Posts:
    1,558
    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.
     
  4. forestjohnson

    forestjohnson

    Joined:
    Oct 1, 2005
    Posts:
    1,370
    Code (csharp):
    1.  
    2. function Update() {
    3.     if (GameController.timeLeft < 0) {
    4.       // put "0" into the timeleft display
    5.       timershow.text = "0";
    6.       PlaySoundForOneSecond();
    7. }
    8. }
    9.  
    10. function PlaySoundForOneSecond() {
    11.       audio.clip = whistleClip;
    12.       audio.Play();
    13.       yield WaitForSeconds(1);
    14.       audio.Stop();
    15. }
    16.  
    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:

    Code (csharp):
    1.  
    2. function Start ()
    3. {
    4.     LevelRoutine();
    5. }
    6.  
    7. function LevelRoutine ()
    8. {
    9.     // wait for the time to run down, in a loop this time:
    10.     while(GameController.timeLeft > 0)
    11.     {
    12.         GameController.timeLeft -= Time.deltaTime; // subtract the time last frame took from the time left..
    13.         timershow.text = "time left=" + Mathf.Floor(GameController.timeLeft);  // .. and then display it, never less than 0
    14.         yield;  // wait one frame
    15.     }
    16.  
    17.     // put "0" into the timeleft display (this is redundant because we subtract first and then clamp in our loop)
    18.     timershow.text = "0";
    19.      
    20.     // play whistle sound twice!
    21.     audio.clip = whistleClip;
    22.      
    23.     audio.Play();
    24.     yield   WaitForSeconds(whistleClip.length);
    25.      
    26.     audio.Play();
    27.     yield   WaitForSeconds(whistleClip.length);
    28.      
    29.     // pause time time - either with Time.timeScale = 0 or using our method of pausing game
    30.     GamePlayScript = GameObject.Find("ScriptHolder").GetComponent(GamePlay);
    31.     GamePlayScript.AreWePaused = true;
    32.     // Time.timeScale = 0;
    33.      
    34.     // display level done message in text Status GO for 3 seconds
    35.     gameovermessage.text = "Time has run out!";
    36.    
    37.     yield WaitForSeconds(3);
    38.      
    39.     // show GUI stuff from above
    40.                  
    41.     // show cursor and unlock screen and disable mouse look off of player character
    42.     // MOUSELOOK DISABLED
    43.     Screen.lockCursor = false;
    44.     Screen.showCursor = true;              
    45.  
    46. }
    47.