碰撞后如何启动计时器?

How can I start a timer after collision?

我想在我的游戏中创建一个奖励对象。当玩家拿起它时,计时器应该开始。

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

public void StartTimer(){

}

这里有很多解决方案!取决于您的需求。根据您的情况,最喜欢的可能是

您可以使用 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
}

可以直接将碰撞消息本身转成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
    }
}

或者您可以使用 Invoke 以便在延迟后执行方法

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
}

有关更多选项和详细信息,请查看


如果您说的启动计时器是指例如倒计时显示,那么你绝对应该使用协程,例如

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!");
}
  1. Unity 的实现方式是协程。
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. 您可以创建一个 RunDelayed 助手来简化语法。到目前为止我最喜欢的。它使代码看起来更清晰。阅读 my blog post 这方面的内容以及如何使其在所有单一行为中都可访问(通过继承或扩展方法)。
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. 您可以使用 C# 任务和后台线程。在 Unity 中,我尽量避免使用它们,因为它们与 WebGL 不兼容,并且您可能会在播放器中遇到问题。我知道 Google 的 Firebase 使用它们,因此对于更复杂的异步任务,值得一试。对于您的简单情况,我不推荐它们。