1

I want to create a bonus object in my game. When player picks it up, a timer should start.

public void OnCollisionEnter2D(Collision2D col) //player collide with bonus
{
    if (col.gameObject.name == "Cube")
    {
        StartTimer();
    }
}

public void StartTimer(){

}
Tim M.
  • 53,671
  • 14
  • 120
  • 163
Alex Hard
  • 35
  • 4
  • I mean, when you pick up this bonus, you start the timer (for example 5sec) and in this 5sec i want to add some action – Alex Hard Jul 12 '20 at 16:08

2 Answers2

2

There are many solutions here! Depends a bit on your needs. Among the favorites for your situation would probably be

you can either use a Coroutine

public void OnCollisionEnter2D(Collision2D col) //player collide with bonus
{
    if (col.gameObject.name == "Cube")
    {    
        StartCoroutine (Timer());
    }
}

private IEnumerator Timer()
{
    yield return new WaitForSeconds (3f);

    // Something that happens after 3 seconds
}

You can directly turn the collision message itself into a Coroutine

public IEnumerator OnCollisionEnter2D(Collision2D col) //player collide with bonus
{
    if (col.gameObject.name == "Cube")
    {     
        yield return new WaitForSeconds (3f);

        // Something happens after 3 seconds
    }
}

Or you can use Invoke in order to execute a method after a delay

public void OnCollisionEnter2D(Collision2D col) //player collide with bonus
{
    if (col.gameObject.name == "Cube")
    {     
        Invoke(nameof(AfterDelay), 3f);
    }
}

public void AfterDelay()
{
    // Something happens after 3 seconds
}

For more options and detailed information checkout How make the script wait/sleep in a simple way in unity


If by start a timer you mean e.g. a countdown display then you should definitely go with a Coroutine like e.g.

public Text text;

private Coroutine timer;

public void OnCollisionEnter2D(Collision2D col) //player collide with bonus
{
    if (col.gameObject.name == "Cube")
    {    
        if(timer == null) timer = StartCoroutine (Timer(3f));
    }
}

public void OnCollisionExit2D(Collision2D col) //player left bonus before timer passed
{
    if (col.gameObject.name == "Cube")
    {    
        if(timer == null) StopCoroutine (timer);

        timer = null;
    }
}

private IEnumerator Timer(float durationInSeconds)
{
    var timeLeft = duration;
    while(timeLeft >= 0)
    {
        Text.text = timeLeft.ToString(F2);

        yield return null;
    }

    // Something that happens after the timer reached 0
    Debug.Log("Hello!");
}
derHugo
  • 83,094
  • 9
  • 75
  • 115
  • 1
    In the second case that your turn the OnCollisionEnter2D into a coroutine, You forgot to turn void to IEnumerator :) Note that `invoke` is not typesafe and will make your codebase dirty. The Unity documentation itself suggests using Coroutines instead of `Invoke`. – hk1ll3r Jul 07 '20 at 20:58
  • 1
    @HosseinShah thanks I typed it on the phone and forgot to make it `IEnumerator` :) – derHugo Jul 08 '20 at 05:28
1
  1. The Unity way of doing it would be a coroutine.
public void OnCollisionEnter2D(Collision2D col) //player collide with bonus
{
    if (col.gameObject.name == "Cube")
    {
        StartCoroutine(MyTimer());
    }
}

IEnumerator StartTimer(){
    yield return new WaitForSeconds(3f);
    // DO STUFF AFTER 3 SECONDS
}
  1. You could create a RunDelayed helper to simplify the syntax. My favorite by far. It makes the code look much cleaner. Read my blog post on this and how to make it accessible in all your monobehaviours (through either inheritance or extension methods).
public void OnCollisionEnter2D(Collision2D col) //player collide with bonus
{
    if (col.gameObject.name == "Cube")
    {
        RunDelayd(3f, () => {
            // DO STUFF HERE AFTER 3 SECONDS
        });
    }
}
protected IEnumerator DelayedCoroutine(float delay, System.Action a)
{
    yield return new WaitForSeconds(delay);
    a();
}

protected Coroutine RunDelayed(float delay, System.Action a)
{
    return StartCoroutine(DelayedCoroutine(delay, a));
}
  1. You could use C# tasks and background threads. In Unity I try to avoid them since they are not compatible with WebGL and you may face problems in players. I know Google's Firebase uses them, so for more complex async tasks, worth checking out. For your simple case I don't recommend them.
hk1ll3r
  • 811
  • 1
  • 6
  • 14
  • Note that the option 3 makes little sense. As there already are built-in ways for delaying something it would be a lot of implementation (and execution) overhead to run the delay in a thread just to dispatch an event after the delay passed back into the main thread. – derHugo Jul 08 '20 at 05:33