如何在Unity中同步Spawner主协程与FloorModule子协程?
Unity3D 地板模块协程同步问题
我正在开发Unity3D项目,需要实现地板逐步展开效果。已编写FloorModule.cs脚本,通过协程逐步生成地砖;要求每个地板模块完成展开后再启动下一个,因此创建了Spawner.cs脚本,但无法实现主循环(Spawner.cs)与预制体子循环(FloorModule.cs)的协程同步。同时使用References.cs类修改变量值。
原脚本代码
FloorModule.cs
public class FloorModule : MonoBehaviour { public float zSpacer = 0f; public int instPrefabCount; public Transform spawnPoint; public int lenght = 15; public int width = 5; public GameObject floorTiles; void Start() { spawnPoint = GetComponent<Transform>(); StartCoroutine(FwFloorDelay(spawnPoint)); } public IEnumerator FwFloorDelay(Transform origin) { for (int l = 0; l < lenght; l++) { float xAngle = 90; float yPos = 0; float zPos = 0 + l; for (int w = 0; w < width; w++) { int xSelection = Random.Range(0, 6); GameObject xFloor = Instantiate(floorTiles, origin); TileStatusNames(xFloor, l, w); // defining positiona and angles float xPos = w + (zSpacer * w); xFloor.transform.localEulerAngles = new Vector3(xAngle, 0, 0); xFloor.transform.localPosition = new Vector3(xPos, yPos, zPos); yield return new WaitForSeconds(.05f); } } } }
Spawner.cs
public class Spawner : MonoBehaviour { public GameObject FloorModPrefab; public References[] referenceScript; void Start() { StartCoroutine(SpawnModules()); } IEnumerator SpawnModules() { for (int i = 0; i < referenceScript.Length; i++) { referenceScript[i].instance = Instantiate(FloorModPrefab, referenceScript[i].ref_spawnPoint.position, referenceScript[i].ref_spawnPoint.rotation); referenceScript[i].ref_instFloorModCount = i + 1; referenceScript[i].Setup(); yield return new WaitForSeconds(5f); } } }
References.cs
[Serializable] public class References { FloorModule prefabObjScript; public GameObject instance; public int ref_instFloorModCount; public Transform ref_spawnPoint; public int ref_Width = 5; public int ref_Lenght = 15; public void Setup() { // Get references to the components. prefabObjScript = instance.GetComponent<FloorModule>(); // Set the player numbers to be consistent across the scripts. prefabObjScript.instPrefabCount = ref_instFloorModCount; prefabObjScript.spawnPoint = ref_spawnPoint; prefabObjScript.width = ref_Width; prefabObjScript.lenght = ref_Lenght; } }
解决方法
核心问题是Spawner的协程无法精准等待FloorModule内部的展开逻辑完成,以下是修改方案:
1. 修改FloorModule.cs
取消自动启动协程,改为外部控制启动时机,并提供可被外部等待的协程入口:
public class FloorModule : MonoBehaviour { public float zSpacer = 0f; public int instPrefabCount; public Transform spawnPoint; public int length = 15; // 修正拼写错误 public int width = 5; public GameObject floorTiles; // 移除自动启动协程的Start方法,改为外部调用 // void Start() { ... } // 对外提供的展开入口,返回协程供外部等待 public IEnumerator StartFloorExpansion() { spawnPoint = GetComponent<Transform>(); yield return StartCoroutine(FwFloorDelay(spawnPoint)); } public IEnumerator FwFloorDelay(Transform origin) { for (int l = 0; l < length; l++) { float xAngle = 90; float yPos = 0; float zPos = 0 + l; for (int w = 0; w < width; w++) { int xSelection = Random.Range(0, 6); GameObject xFloor = Instantiate(floorTiles, origin); TileStatusNames(xFloor, l, w); float xPos = w + (zSpacer * w); xFloor.transform.localEulerAngles = new Vector3(xAngle, 0, 0); xFloor.transform.localPosition = new Vector3(xPos, yPos, zPos); yield return new WaitForSeconds(.05f); } } } // 补全缺失的TileStatusNames方法(根据你的逻辑实现) private void TileStatusNames(GameObject tile, int l, int w) { // 你的状态命名逻辑 } }
2. 修改References.cs
公开FloorModule引用,并提供启动展开的方法:
[Serializable] public class References { public FloorModule prefabObjScript; // 改为公开,方便外部获取 public GameObject instance; public int ref_instFloorModCount; public Transform ref_spawnPoint; public int ref_Width = 5; public int ref_Length = 15; // 修正拼写错误 public void Setup() { prefabObjScript = instance.GetComponent<FloorModule>(); prefabObjScript.instPrefabCount = ref_instFloorModCount; prefabObjScript.spawnPoint = ref_spawnPoint; prefabObjScript.width = ref_Width; prefabObjScript.length = ref_Length; } // 提供启动模块展开的方法,返回协程供Spawner等待 public IEnumerator StartModuleExpansion() { yield return prefabObjScript.StartFloorExpansion(); } }
3. 修改Spawner.cs
替换固定等待时间,改为等待当前模块展开协程完成:
public class Spawner : MonoBehaviour { public GameObject FloorModPrefab; public References[] referenceScript; void Start() { StartCoroutine(SpawnModules()); } IEnumerator SpawnModules() { for (int i = 0; i < referenceScript.Length; i++) { referenceScript[i].instance = Instantiate(FloorModPrefab, referenceScript[i].ref_spawnPoint.position, referenceScript[i].ref_spawnPoint.rotation); referenceScript[i].ref_instFloorModCount = i + 1; referenceScript[i].Setup(); // 等待当前模块完全展开后,再生成下一个模块 yield return StartCoroutine(referenceScript[i].StartModuleExpansion()); } } }
关键说明
- 取消FloorModule自动启动协程,改为由Spawner控制启动时机,确保模块生成后才开始展开
- 通过
yield return StartCoroutine(...)让Spawner的主协程等待每个模块的展开协程完成,实现精准同步 - 修正了原代码中的拼写错误(
lenght改为length),避免潜在逻辑bug
内容的提问来源于stack exchange,提问作者RSRY
相关产品推荐
相关产品推荐

