Search Unity

Timer Problem: WaitForSeconds

Discussion in 'Scripting' started by Chris11, Oct 2, 2014.

  1. Chris11

    Chris11

    Joined:
    Sep 26, 2014
    Posts:
    9
    Hey Guys,

    i just did the Tutorial to the Space Shooter and started to add some features on my own.

    i created another Object that increases my fireRate. That works fine so far.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class PickUpBuff : MonoBehaviour {
    5.  
    6.     private PlayerController playerController;
    7.     private float safe;
    8.     public float buffTime;
    9.     public float newFireRate;
    10.  
    11.  
    12.     void Start ()
    13.     {
    14.         GameObject playerControllerObject = GameObject.FindWithTag ("Player");
    15.         if (playerControllerObject != null)
    16.         {
    17.             playerController = playerControllerObject.GetComponent <PlayerController>();
    18.         }
    19.         if (playerController == null)
    20.         {
    21.             Debug.Log ("Cannot find 'PlayerController' script");
    22.         }
    23.  
    24.     }
    25.  
    26.     void OnTriggerEnter(Collider other)
    27.     {
    28.         if (other.tag == "Player")
    29.         {
    30.             Destroy(gameObject);
    31.             StartCoroutine (BuffTimer ());
    32.         }
    33.     }
    34.  
    35.     IEnumerator BuffTimer()
    36.     {
    37.         safe = playerController.fireRate;
    38.         playerController.fireRate = newFireRate;
    39.         yield return new WaitForSeconds (buffTime);
    40.         playerController.fireRate = safe;
    41.      
    42.     }
    43. }

    So this code changes the fireRate that is a variable of PlayerController.
    But this code doenst seem to work:

    Code (CSharp):
    1. yield return new WaitForSeconds (buffTime);
    2. playerController.fireRate = safe;
    it doesnt change the fireRate back to the normal rate.

    anyone has the time to help me? please
     
    Last edited: Oct 2, 2014
  2. aoe_labs

    aoe_labs

    Joined:
    Nov 4, 2013
    Posts:
    42
    Try passing in buffTime as a parameter in the StartCoroutine(BuffTimer ()); call, and add a paramter for the IEnumerator. Like so:
    Code (CSharp):
    1. void OnTriggerEnter(Collider other)
    2.     {
    3.         if (other.tag == "Player")
    4.         {
    5.             Destroy(gameObject);
    6.             StartCoroutine (BuffTimer (buffTime));  //here
    7.         }
    8.     }
    9.  
    10.     IEnumerator BuffTimer(float buffTime) //here
    11.     {
    12.         safe = playerController.fireRate;
    13.         playerController.fireRate = newFireRate;
    14.         yield return new WaitForSeconds (buffTime);
    15.         playerController.fireRate = safe;
    16.    
    17.     }
    That's my first guess. Let me know if that works.
     
  3. Chris11

    Chris11

    Joined:
    Sep 26, 2014
    Posts:
    9
    Hey
    thx for your help, but that doesnt work either.

    i tested a lot with other functions and i think it doesnt work because of

    Code (CSharp):
    1. Destroy(gameObject);
    the actions after waiting arnt executed because the object is destroyed.

    so i used
    Code (CSharp):
    1. gameObject.SetActive = false;
    and destroy it later.
    This works if i use the invoke method.

    Code (CSharp):
    1. void BuffEnd()
    2.     {
    3.         playerController.fireRate = safe;
    4.         Destroy(gameObject);
    5.     }
    6.  
    7.  
    8.     void BuffStart()
    9.     {
    10.         gameObject.SetActive = false;
    11.         safe = playerController.fireRate;
    12.         playerController.fireRate = newFireRate;
    13.         Invoke ("BuffEnd", 5);
    14.     }
    15.  
    16.     void OnTriggerEnter(Collider other)
    17.     {
    18.         if (other.tag == "Player")
    19.         {
    20.             Invoke ("BuffStart", 0);
    21.         }
    22.     }
    so far so good, now i tried to add a soundfile,
    Code (CSharp):
    1.   void OnTriggerEnter(Collider other)
    2.     {
    3.         if (other.tag == "Player")
    4.         {
    5.             audio.Play();
    6.             Invoke ("BuffStart", 0);
    7.         }
    8.     }
    But because of
    Code (CSharp):
    1. gameObject.SetActive = false;
    the Audio is not played.

    so change the method again to renderer.enable = false;

    Code (CSharp):
    1. void BuffStart()
    2.     {
    3.         Renderer[] renderers = gameObject.GetComponentsInChildren<Renderer>();
    4.         foreach (Renderer r in renderers)
    5.         {
    6.             r.enabled = false;
    7.         }
    8.  
    9.         safe = playerController.fireRate;
    10.         playerController.fireRate = newFireRate;
    11.         Invoke ("BuffEnd", 5);
    12.     }
    and again a new problem :D
    i can pick up the PowerUp all the time even if its invisible for me and i get the buff over and over again until the timer is up and it gets destroyed

    well i could make it so the Object changes the position where i cant get it but that would be a pretty bad workaround,

    anyone a good idea how to solve my problem ?

    EDIT:
    so i got a better solution than moving the Object,
    i disabled the collider too.
    Code (CSharp):
    1. void OnTriggerEnter(Collider other)
    2.     {
    3.         if (other.tag == "Player")
    4.         {
    5.             audio.Play ();
    6.             StartCoroutine (BuffTimer ());
    7.         }
    8.     }
    9.  
    10.     IEnumerator BuffTimer()
    11.     {
    12.        
    13.         collider.enabled = false;
    14.         Renderer[] renderers = gameObject.GetComponentsInChildren<Renderer>();
    15.         foreach (Renderer r in renderers)
    16.         {
    17.             r.enabled = false;
    18.         }
    19.        
    20.         safe = playerController.fireRate;
    21.         playerController.fireRate = newFireRate;
    22.         yield return new WaitForSeconds (buffTime);
    23.         playerController.fireRate = safe;  
    24.         Destroy(gameObject);
    25.     }
    but i wonder if there is a better way to program a powerup that increases your fireRate for 10 seconds ?
     
    Last edited: Oct 2, 2014
  4. aoe_labs

    aoe_labs

    Joined:
    Nov 4, 2013
    Posts:
    42
    I re-read everything now and I see why my suggestion did not work.
    You could have the powerup pass a variable to a script on an object that is not being destroyed, set inactive, etc, and then destroy or deactivate the powerup. You could also use a static variable for buffs if you know how to use static variables.

    Your ideas would work though: moving the powerup to a different position, then you could destroy it after 10 seconds or whatever you set to be the buff time; as well as disabling the collider. You could also set a bool that checks if the user has already gotten that powerup. This way, the method only gets called once when you enter the powerup trigger to prevent you from getting the powerup over and over again. For example, some psuedocode:
    Code (CSharp):
    1. bool poweredUp = false;
    2.  
    3. void OnTriggerEnter(Collider col) {
    4.     // do stuff here
    5.     if (!poweredUp) {
    6.          buffMethod();
    7.     }
    8. }
    9.  
    10. void buffMethod () {
    11.    // do stuff here
    12.     poweredUp = true;
    13. }
    But then it would be up to you to decide what to do with the actual powerup. You could disable the mesh renderer and collider, you could relocate the object, etc.
     
    Chris11 likes this.