如何在特定条件下统一退出协程?
How to exit from coroutine in unity in specific condition?
我在统一协程方面遇到了一些问题。我希望我的播放器在到达门时(发生碰撞时)在 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();
}
}
}
一个选项是:如果发生某些事情让您想取消操作,请在某处设置一个布尔值并在协程的 LoadLevelTower()
行之前立即检查它。
另一种选择是保留对协程的引用(例如Coroutine c = StartCoroutine("LoadLevelTowerAfterDelay");
),然后如果发生某些事情让您想中止它,请使用StopCoroutine(c);
.
我认为您更大的问题可能在于您对 OnTriggerStay2D
的使用。对我来说,当玩家在对撞机内时,您似乎每帧都在调用 StartCoroutine
,而当 玩家 以外的其他东西在对撞机内时,您每帧都在调用 StopCoroutine
对撞机。可能您反而想使用 OnTriggerEnter2D
来检查玩家是否进入,并使用 OnTriggerExit2D
来检查玩家是否退出?
OnTriggerStay2D
被调用 每个物理更新帧 !
您肯定不想在每个物理帧启动一个新协程!
您更想做的是使用 OnTriggerEnter2D
和 OnTriggerExit2D
,例如
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;
}
我在统一协程方面遇到了一些问题。我希望我的播放器在到达门时(发生碰撞时)在 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();
}
}
}
一个选项是:如果发生某些事情让您想取消操作,请在某处设置一个布尔值并在协程的 LoadLevelTower()
行之前立即检查它。
另一种选择是保留对协程的引用(例如Coroutine c = StartCoroutine("LoadLevelTowerAfterDelay");
),然后如果发生某些事情让您想中止它,请使用StopCoroutine(c);
.
我认为您更大的问题可能在于您对 OnTriggerStay2D
的使用。对我来说,当玩家在对撞机内时,您似乎每帧都在调用 StartCoroutine
,而当 玩家 以外的其他东西在对撞机内时,您每帧都在调用 StopCoroutine
对撞机。可能您反而想使用 OnTriggerEnter2D
来检查玩家是否进入,并使用 OnTriggerExit2D
来检查玩家是否退出?
OnTriggerStay2D
被调用 每个物理更新帧 !
您肯定不想在每个物理帧启动一个新协程!
您更想做的是使用 OnTriggerEnter2D
和 OnTriggerExit2D
,例如
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;
}