Unity中已保存的Coroutine变量无法重启问题求助
问题描述
为AI单位实现了多个对应不同任务的协程,希望通过保存最近使用的协程实现「暂停」与「继续」功能,但遇到报错:执行MoveToResourceStart()时将MoveToResource()协程保存为lastCoroutine并启动;触发StopAlly()后停止该协程、重置导航路径并让单位看向玩家;触发ContinueAlly()尝试重启lastCoroutine时,系统报错:Coroutine 'lastCoroutine' couldn't be started!
精简代码如下:
Coroutine lastCoroutine = null; protected void StopAlly(Transform player) { if (lastCoroutine != null) { StopCoroutine(lastCoroutine); agent.ResetPath(); } this.transform.LookAt(player.position); } protected void ContinueAlly() { if (lastCoroutine != null) StartCoroutine("lastCoroutine"); } protected void MoveToResourceStart() { if (lastCoroutine != null) StopCoroutine(lastCoroutine); lastCoroutine = StartCoroutine(MoveToResource()); } protected IEnumerator MoveToResource() { agent.SetDestination(resource.gameObject.transform.position); // 其他移动相关代码,运行正常 }
问题分析与解决方案
错误原因
- 协程对象无法重复启动:
lastCoroutine是Coroutine类型的对象,一旦通过StopCoroutine停止后,该对象就会失效,无法再次通过StartCoroutine启动。 - 字符串启动方式错误:
StartCoroutine("lastCoroutine")是通过方法名称字符串启动协程,但这里传入的是变量名而非协程方法的真实名称(正确应为"MoveToResource");即便传入正确名称,也只是启动一个全新的协程,无法恢复之前暂停的执行状态。
正确实现方式
Unity原生协程不支持直接暂停后恢复状态,因为协程本质是迭代器,停止后迭代器的执行状态会丢失,可通过以下两种思路实现需求:
思路1:用标记控制协程内部暂停/继续
不直接停止协程,而是在协程内部通过布尔标记控制执行流程,以此保留协程的中间状态:
Coroutine lastCoroutine = null; bool isCoroutinePaused = false; protected void StopAlly(Transform player) { isCoroutinePaused = true; agent.ResetPath(); this.transform.LookAt(player.position); } protected void ContinueAlly() { isCoroutinePaused = false; } protected void MoveToResourceStart() { if (lastCoroutine != null) { StopCoroutine(lastCoroutine); isCoroutinePaused = false; } lastCoroutine = StartCoroutine(MoveToResource()); } protected IEnumerator MoveToResource() { agent.SetDestination(resource.gameObject.transform.position); while (!agent.hasReachedDestination) { // 暂停时循环等待,不执行后续逻辑 while (isCoroutinePaused) { agent.isStopped = true; // 停止导航移动 yield return null; } agent.isStopped = false; // 恢复导航移动 // 其他移动相关逻辑 yield return null; } }
思路2:保存任务类型,重启对应协程
如果不需要恢复协程的中间状态,仅需重新执行同一个任务,可保存任务类型标识,重启时根据标识启动对应协程:
// 定义任务类型枚举 enum AllyTaskType { None, MoveToResource } AllyTaskType lastTaskType = AllyTaskType.None; Coroutine lastCoroutine = null; protected void StopAlly(Transform player) { if (lastCoroutine != null) { StopCoroutine(lastCoroutine); agent.ResetPath(); } this.transform.LookAt(player.position); } protected void ContinueAlly() { // 根据保存的任务类型启动对应协程 switch(lastTaskType) { case AllyTaskType.MoveToResource: lastCoroutine = StartCoroutine(MoveToResource()); break; // 可扩展其他任务类型的case } } protected void MoveToResourceStart() { if (lastCoroutine != null) StopCoroutine(lastCoroutine); lastTaskType = AllyTaskType.MoveToResource; lastCoroutine = StartCoroutine(MoveToResource()); } protected IEnumerator MoveToResource() { agent.SetDestination(resource.gameObject.transform.position); // 其他移动相关代码 while (!agent.hasReachedDestination) { yield return null; } lastTaskType = AllyTaskType.None; }
内容的提问来源于stack exchange,提问作者iimuli
相关产品推荐
相关产品推荐

