0
\$\begingroup\$

I have a class which is changing the player speed. Here is the code:

using UnityEngine;
using System.Collections;

public class MultiplySpeed : MonoBehaviour {
    public int multiplier = 2;
    public Controls player;
    bool flag = false;
    void OnTriggerExit(Collider c){
        if(c.tag == "Player"){
            player = c.gameObject.GetComponent<Controls>();
            if(!flag){
                multiplySpeed();
                StartCoroutine(powerUp());
            }
            flag = true;
        }
    }
    public IEnumerator powerUp(){
        yield return new WaitForSeconds(10);
        backToNormal ();
        StopCoroutine(powerUp ());
    }
    public void multiplySpeed(){
        player.speed = player.speed * multiplier;
    }
    public void backToNormal(){
        player.speed = player.speed/ multiplier;
    }
}

I have two problems, the first one is that after starting the coroutine and the flag varaible is set to true, the method OnTriggerExit is called once again, and the flag is false and everything is executed again. The second problem is that the method backToNormal seems like it's never executed, it simply multiplies the speed and never take it back to normal.

Any help is appreciated.

\$\endgroup\$
  • \$\begingroup\$ couple small points: multiplySpeed() should be called as the first line in the coroutine not before the coroutine, and you don't need StopCoroutine() at the end of the coroutine. Neither of these changes should affect how this script works, but eg. it'll be clearer that multiplying speed is part of the power up. \$\endgroup\$ – jhocking Sep 22 '15 at 21:23
  • \$\begingroup\$ At the beggining the code was exacly like this without StopCouroutine, and everything was in the powerup method, however I have tried a lot of such small things without any success. \$\endgroup\$ – Planet_Earth Sep 22 '15 at 21:31
1
\$\begingroup\$

To address question 1:

Based on this code, after the initial call to OnTriggerExit it will not begin the coroutine again because your flag is set to false. It would only ever fire again if flag is set back to true or there's another power up object firing a duplicate.

To address question 2:

It appears that it does in fact fire after 10 seconds, but if you aren't certain, I would suggest printing to the console when each method is fired like this:

public void multiplySpeed() {
    Debug.Log("multiplySpeed() has been fired.");
    player.speed = player.speed * multiplier;
}
public void backToNormal() {
    Debug.Log("backToNormal() has been fired.");
    player.speed = player.speed / multiplier;
}

If it still hasn't fired at this point, then that means the power up object has been deleted or something else stopped the coroutine. I would suggest removing the line:

StopCoroutine(powerUp());

because it could potentially end another power up objects coroutine early.

\$\endgroup\$
  • \$\begingroup\$ I'm still unable to fix the first issue, however it's no so important as the second one. \$\endgroup\$ – Planet_Earth Sep 22 '15 at 21:46
  • \$\begingroup\$ just semantics but: "... it will not begin the coroutine again because your flag is set to true. It would only ever fire again if flag is set back to false ..." \$\endgroup\$ – Fuzzy Logic Sep 22 '15 at 22:15
  • \$\begingroup\$ flag should be set to true just above the call to multiplySpeed() (which should be the first lines inside the powerUp() coroutine) and reset to false as the last line of powerUp() \$\endgroup\$ – Fuzzy Logic Sep 22 '15 at 22:15
0
\$\begingroup\$

So you already have your answer marked, but there's a few things here that are more complicated than they need to be, and may be contributing to the issues as listed. I'd like to throw in a Coroutine pattern that I find myself using quite a bit. You can have the coroutine manage itself; there's little need for OnTriggerExit to worry about whether the coroutine should be activated or not.

bool running = false;
public IEnumerator testCoroutine()
{
    if(!running)
    {
        running = true;

        //Do stuff here

        running = false;
    }
}

This means that you can trigger the coroutine as many times as you like, and the coroutine itself will enforce only one instance of itself at a time is running (or executing, rather; copies will be spun up, but they will die after a single frame, since they can't get past the flag test).

On top of that, you can pass variables into coroutines; I'm not sure if you're aware of that or not, but it's the primary benefit over using Invoke() and friends.

Here's your code after I've taken a whack at it:

public float multiplier = 2.0f;

void OnTriggerExit(Collider c)
{
    if(c.tag == "Player")
        StartCoroutine(powerUp(c.gameObject.GetComponent<Controls>()));
}

private bool powered = false;
IEnumerator powerUp(Controls player)
{
    if(!powered && player != null)
    {
        powered = true;

        player.speed = player.speed * multiplier;
        yield return new WaitForSeconds(10);
        player.speed = player.speed/ multiplier;

        powered = false;
    }
}

This should eliminate your first problem (if I'm understanding it correctly) while incorporating the solution to your second. It's also much simpler to follow.

\$\endgroup\$
-1
\$\begingroup\$

i really don't understand what exactly you need, but i hope this helps you.

using UnityEngine;
using System.Collections;

public class MultiplySpeed : MonoBehaviour 
{

public int multiplier = 2;
public Controls player;
bool flag = false;

void OnTriggerExit(Collider c)
{
    if(c.tag == "Player")
    {
        player = c.gameObject.GetComponent<Controls>();

        if(!flag)
        {
            StartCoroutine(powerUp());
        }
    }
}
    public IEnumerator powerUp()
    {
       while(true)
        {
            multiplySpeed();
            yield return new WaitForSeconds(10);
            backToNormal ();

            flag = true;
            yield break;
        }
    }

   public void multiplySpeed()
   {
      Debug.Log("multiplySpeed() work!");
      player.speed = player.speed * multiplier;
   }

   public void backToNormal()
   {
      Debug.Log("backToNormal() work!");
      player.speed = player.speed/ multiplier;
   }
} 
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.