Unity C#脚本中协程yield return后代码不执行问题排查
问题原因与解决方案
核心问题
你在Explode()方法里先销毁了手榴弹对象,再启动协程——而Unity的协程是依附于MonoBehaviour所在的GameObject运行的,一旦对象被销毁,依附于它的所有协程都会直接终止,自然不会执行yield return之后的代码。
你的测试脚本能正常工作,是因为相机对象从始至终都存在,协程的运行载体没有被销毁。
修复方案
方案一:使用全局管理器托管协程(推荐)
创建一个全局持久化的GameManager,让它来处理延迟销毁逻辑,避免协程随手榴弹对象被销毁:
- 新建
GameManager脚本:
public class GameManager : MonoBehaviour { public static GameManager Instance; void Awake() { // 单例模式确保全局唯一且不被销毁 if (Instance == null) { Instance = this; DontDestroyOnLoad(gameObject); } else { Destroy(gameObject); } } // 全局调用的延迟销毁方法 public IEnumerator DelayDestroyObjects(Collider[] colliders, float delay) { yield return new WaitForSeconds(delay); foreach (var collider in colliders) { // 可根据需求添加过滤逻辑,比如只销毁特定标签/受损的物体 Destroy(collider.gameObject); } Debug.Log("Objects destroyed"); } }
将这个脚本挂载到一个空对象上(命名为GameManager),确保场景加载时它存在。
- 修改手榴弹脚本的
Explode()方法:
private void Explode() { // 爆炸效果、获取碰撞体、施加爆炸力的逻辑保留 // 让GameManager启动协程,再销毁手榴弹 GameManager.Instance.StartCoroutine(GameManager.Instance.DelayDestroyObjects(colliders, destroyDelayTime)); Destroy(gameObject); Debug.Log("Grenade destroyed"); }
方案二:延迟销毁手榴弹对象
不立刻销毁手榴弹,先禁用它的显示和碰撞,等协程执行完毕后再销毁:
修改手榴弹脚本的Explode()和协程方法:
private void Explode() { // 爆炸效果、获取碰撞体、施加爆炸力的逻辑保留 // 禁用手榴弹的渲染和碰撞,让它从视野中消失但不销毁 Renderer renderer = GetComponent<Renderer>(); if (renderer != null) renderer.enabled = false; Collider collider = GetComponent<Collider>(); if (collider != null) collider.enabled = false; // 启动协程 StartCoroutine(DelayObjectDestroy(colliders, destroyDelayTime)); } IEnumerator DelayObjectDestroy(Collider[] colliders, float delay) { Debug.Log("DelayObjectDestroy called"); yield return new WaitForSeconds(delay); Debug.Log("Objects destroyed"); // 销毁目标物体 foreach (var collider in colliders) { Destroy(collider.gameObject); } // 最后销毁手榴弹本身 Destroy(gameObject); }
内容的提问来源于stack exchange,提问作者SwillMith16
相关产品推荐
相关产品推荐

