如何在特定情况下统一退出协程?

发布于 2025-01-17 08:11:35 字数 1036 浏览 5 评论 0原文

我在统一协程方面遇到一些问题。我希望我的玩家在到达门口时(发生碰撞时)在 3 秒后进入塔内,并且如果他在距离门不到 3 秒的时间内移动,则关闭门并且不加载新场景。我尝试了大部分的事情,但没有用。有人可以帮助我或给我一些提示吗?

这是我的代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Door : MonoBehaviour
{
[SerializeField] private Animator animator;
bool open = false;
// Start is called before the first frame update
void Start()
{
    animator = GetComponent<Animator>();
}

// Update is called once per frame
void Update()
{

}

public void OnTriggerStay2D(Collider2D collider)
{
    if (collider.gameObject.tag == "Player")
    {
        animator.SetBool("opening", true);
        StartCoroutine("LoadLevelTowerAfterDelay");
    }
    else
    {
        animator.SetBool("opening", false);
        StopCoroutine("LoadLevelTowerAfterDelay");
    }
}
IEnumerator LoadLevelTowerAfterDelay()
{

    if (GameManager.sharedInstance != null)
    {
        yield return new WaitForSeconds(3);
        GameManager.sharedInstance.LoadLevelTower();
    }
}

}

i have some problems with coroutines in unity. I want that my player when he gets to the door (when a collision occurs) to enter in the tower after 3 seconds, and if he moves within less than 3 seconds from the door to close the door and not load a new scene. I tried most of things but doesn't work. Can somebody help or give me some hint?

Here is my code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Door : MonoBehaviour
{
[SerializeField] private Animator animator;
bool open = false;
// Start is called before the first frame update
void Start()
{
    animator = GetComponent<Animator>();
}

// Update is called once per frame
void Update()
{

}

public void OnTriggerStay2D(Collider2D collider)
{
    if (collider.gameObject.tag == "Player")
    {
        animator.SetBool("opening", true);
        StartCoroutine("LoadLevelTowerAfterDelay");
    }
    else
    {
        animator.SetBool("opening", false);
        StopCoroutine("LoadLevelTowerAfterDelay");
    }
}
IEnumerator LoadLevelTowerAfterDelay()
{

    if (GameManager.sharedInstance != null)
    {
        yield return new WaitForSeconds(3);
        GameManager.sharedInstance.LoadLevelTower();
    }
}

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一人独醉 2025-01-24 08:11:35

只是为了完成,

您可以使用 yield break 从内部退出/完成协程,

一个例子是:

public IEnumerator MyCoroutine(){
   DoStuff();
   if(condition){
      yield break; 
   }
   yield return new WaitForSeconds(4);
   DoOtherStuff();
}

这样您就可以抢先结束协程,而不是等待 4 秒,并且不执行 DoOtherStuff();

Just for Completion

you can exit/finish the coroutine from within with yield break

an example would be:

public IEnumerator MyCoroutine(){
   DoStuff();
   if(condition){
      yield break; 
   }
   yield return new WaitForSeconds(4);
   DoOtherStuff();
}

this way you would preemptively end the coroutine, not wait 4 seconds and don't DoOtherStuff();

埋葬我深情 2025-01-24 08:11:35

OnTriggerStay2D 被调用每个物理更新帧

您绝对不想在每个物理帧启动一个新的协程!

您更想做的是使用 OnTriggerEnter2DOnTriggerExit2D ,例如

private void OnTriggerEnter2D(Collider2D collider)
{
    if (!collider.gameObject.CompareTag("Player")) return;
    
    animator.SetBool("opening", true);
    StartCoroutine(LoadLevelTowerAfterDelay());
}

private void OnTriggerExit2D(Collider2D collider)
{
    if (!collider.gameObject.CompareTag("Player")) return;
    
    animator.SetBool("opening", false);
    StopCoroutine(LoadLevelTowerAfterDelay());
}

一般来说这应该已经可以工作,但要保存,您可以存储启动的例程,如此处也提到

private Coroutine currentRoutine;

private void OnTriggerEnter2D(Collider2D collider)
{
    if (!collider.gameObject.CompareTag("Player")) return;
    
    // This should actually not happen
    if(currentRoutine != null)
    {
        Debug.LogError("Huh?!", this);
        return;
    }

    animator.SetBool("opening", true);
    currentRoutine = StartCoroutine(LoadLevelTowerAfterDelay());
}

private void OnTriggerExit2D(Collider2D collider)
{
    if (!collider.gameObject.CompareTag("Player")) return;
    
    // This should actually not happen
    if(currentRoutine == null)
    {
        Debug.LogError("Huh?!", this);
        return;
    }

    animator.SetBool("opening", false);
    StopCoroutine(currentRoutine);
    currentRoutine = null;
}

OnTriggerStay2D is called every physics update frame!

You definitely do NOT want to start a new coroutine every physics frame!

What you rather want to do is using OnTriggerEnter2D and OnTriggerExit2D like e.g.

private void OnTriggerEnter2D(Collider2D collider)
{
    if (!collider.gameObject.CompareTag("Player")) return;
    
    animator.SetBool("opening", true);
    StartCoroutine(LoadLevelTowerAfterDelay());
}

private void OnTriggerExit2D(Collider2D collider)
{
    if (!collider.gameObject.CompareTag("Player")) return;
    
    animator.SetBool("opening", false);
    StopCoroutine(LoadLevelTowerAfterDelay());
}

in general this should already work but to be save you could store the started routine as also mentioned here

private Coroutine currentRoutine;

private void OnTriggerEnter2D(Collider2D collider)
{
    if (!collider.gameObject.CompareTag("Player")) return;
    
    // This should actually not happen
    if(currentRoutine != null)
    {
        Debug.LogError("Huh?!", this);
        return;
    }

    animator.SetBool("opening", true);
    currentRoutine = StartCoroutine(LoadLevelTowerAfterDelay());
}

private void OnTriggerExit2D(Collider2D collider)
{
    if (!collider.gameObject.CompareTag("Player")) return;
    
    // This should actually not happen
    if(currentRoutine == null)
    {
        Debug.LogError("Huh?!", this);
        return;
    }

    animator.SetBool("opening", false);
    StopCoroutine(currentRoutine);
    currentRoutine = null;
}
书间行客 2025-01-24 08:11:35

一种选择是:如果发生某些事情让您想要取消操作,请在某处设置一个布尔值,并在协程中紧邻 LoadLevelTower() 行之前检查它。

另一种选择是保留对协程的引用(例如 Coroutine c = StartCoroutine("LoadLevelTowerAfterDelay");),然后如果发生某些事情让您想要中止它,请使用 StopCoroutine(c );。

我认为您更大的问题可能是您使用 OnTriggerStay2D 。在我看来,当玩家在对撞机内时,您每帧都会调用 StartCoroutine ,而当玩家以外的物体StopCoroutine > 在碰撞器内。也许您想使用 OnTriggerEnter2D 来检查玩家是否进入,并使用 OnTriggerExit2D 来检查玩家是否退出?

One option is: If something happens that makes you want to cancel the operation, set a boolean somewhere and check for it immediately before the LoadLevelTower() line in the coroutine.

Another option is to keep a reference to the coroutine (e.g. Coroutine c = StartCoroutine("LoadLevelTowerAfterDelay");), then if something happens that makes you want to abort it, use StopCoroutine(c);.

I think your larger problem might be in your use of OnTriggerStay2D though. To me it looks like you’re calling StartCoroutine every frame while a player is within the collider, and StopCoroutine every frame while something other than a player is within the collider. Probably you instead want to be using OnTriggerEnter2D to check for a player entering, and OnTriggerExit2D to check for a player exiting?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文