最近在学习做一个Boss根据状态随机释放技能的2D游戏,遇到个奇怪问题想不通,记录一下心得...
来看这个例子
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test : MonoBehaviour
{
enum State {ONE, TWO}
State state;
void Start() {state = State.ONE;}
IEnumerator MyCoroutine()
{
if (state == State.ONE) {
state = State.TWO;
} else if (state == State.TWO) {
state = State.ONE;
}
Debug.Log("Coroutine started");
yield return new WaitForSeconds(10);
Debug.Log("Coroutine ended after waiting for 10 seconds");
}
void Update()
{
switch (state) {
case State.ONE:
{
Debug.Log("-> in case ONE");
StartCoroutine(MyCoroutine());
break;
}
case State.TWO:
{
Debug.Log("-> in case TWO");
StartCoroutine(MyCoroutine());
break;
}
}
}
}
😀预期是通过协程等待10秒后再进入下一个状态。
😓实际结果却是:

协程无法暂停Update()的运行,导致Switch()一直进入,协程狂开!
寻求高人解惑

所以,
Unity的Update()
方法是在主线程上运行的,而协程是在单独的线程上运行的,因此协程无法暂停主线程的运行。
当您在Update()
方法中启动协程时,实际上是向Unity的协程调度器添加了一个新的协程任务。这个协程任务将在下一帧开始执行,并且可能在Update()
方法之后完成。
真要这么做有啥办法?

using UnityEngine;
using System.Threading;
public class CoroutineExample : MonoBehaviour
{
private EventWaitHandle waitHandle;
void Start()
{
waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
StartCoroutine(MyCoroutine());
}
IEnumerator MyCoroutine()
{
Debug.Log("Coroutine started");
waitHandle.WaitOne();
Debug.Log("Coroutine resumed after waiting for event");
yield return null;
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
waitHandle.Set();
}
}
}
上面的例子中,我们创建了一个EventWaitHandle
对象来实现协程暂停和恢复执行。
在MyCoroutine()
方法中,我们使用WaitOne()
方法来暂停协程,直到EventWaitHandle
对象收到信号。在Update()
方法中,我们检查用户是否按下空格键,如果是,我们向EventWaitHandle
对象发送信号以恢复协程的执行。
另一种
using UnityEngine;
using System.Threading;
public class CoroutineExample : MonoBehaviour
{
private Semaphore semaphore;
void Start()
{
semaphore = new Semaphore(0, 1);
StartCoroutine(MyCoroutine());
}
IEnumerator MyCoroutine()
{
Debug.Log("Coroutine started");
semaphore.WaitOne();
Debug.Log("Coroutine resumed after waiting for semaphore");
yield return null;
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
semaphore.Release();
}
}
}
在这个例子中,我们使用Semaphore
对象来实现协程暂停和恢复执行。在MyCoroutine()
方法中,我们使用WaitOne()
方法来暂停协程,直到Semaphore
对象释放了一个信号。在Update()
方法中,我们检查用户是否按下空格键,如果是,我们向Semaphore
对象释放一个信号以恢复协程的执行。
请注意,在使用WaitHandle
或Semaphore
时,您需要小心确保您在正确的线程上调用WaitOne()
和Release()
方法。在Unity中,您可以使用MonoBehaviour.StartCoroutine()
方法在Unity的协程调度器线程上运行协程,然后在主线程上发送信号来暂停和恢复协程的执行。
🍻🍻🍻🍻🍻🍻🍻🍻🍻🍻🍻🍻🍻
Comments | NOTHING