Unity中Coroutine仅对首个渲染对象生效问题求助
问题:Unity协程仅对第一个生成的红色立方体生效,后续立方体无法移动
在制作节奏谱时,遇到以下问题:Coroutine仅让第一个渲染的红色立方体移动到目标位置(5,5),但节奏谱中的其他立方体仅被渲染却无法移动。尝试添加while循环但未解决问题,相关代码如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; public class BeatMapConductor : MonoBehaviour { private CSVReader beatmap; private MusicConductor music; private Vector3 redEndPosition = new Vector2(5,5); private Vector3 redStartPosition; private float desirecDuration = 5f; private float elapsedTime; private int i; private Queue<UnityEngine.GameObject> queue; private UnityEngine.GameObject[] array; // initializes variables before game starts void Awake() { beatmap = GetComponent<CSVReader>(); music = GetComponent<MusicConductor>(); } // Start is called before the first frame update void Start() { i = 0; } // Update is called once per frame void Update() { int roundedBeat = (int)Math.Round(music.songPositionInBeats, 0); if(i < beatmap.myPlayerList.player.Length && roundedBeat == beatmap.myPlayerList.player[i].beat){ //rendering a new cube // Create a new cube primitive to set the color on GameObject redCube = GameObject.CreatePrimitive(PrimitiveType.Cube); // Get the Renderer component from the new cube var cubeRenderer = redCube.GetComponent<Renderer>(); // Call SetColor using the shader property name "_Color" and setting the color to red cubeRenderer.material.SetColor("_Color", Color.red); i++; StartCoroutine(Movement(redCube)); } } IEnumerator Movement(GameObject cube){ // to move the game object redStartPosition = cube.transform.position; while(elapsedTime < desirecDuration){ elapsedTime += Time.deltaTime; float percentageComplete = elapsedTime / desirecDuration; cube.transform.position = Vector2.Lerp(redStartPosition, redEndPosition, percentageComplete); } yield return null; } }
问题根源
elapsedTime和redStartPosition是类级别的全局变量:
- 第一个立方体的协程运行时,会持续累加
elapsedTime直到超过5秒,后续协程启动时,这个变量已经满足elapsedTime >= desirecDuration,导致while循环直接跳过,不会执行移动逻辑。 - 多个协程共享
redStartPosition,后续立方体的起始位置会被前一个协程覆盖,即使循环执行,位置计算也会出错。 yield return null放在循环外部,协程会一次性跑完整个循环(没有等待帧更新),即使第一个立方体也不会有平滑移动效果。
修复方案
将elapsedTime和redStartPosition改为协程方法内的局部变量,同时把yield return null移到循环内部,保证每帧更新位置:
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; public class BeatMapConductor : MonoBehaviour { private CSVReader beatmap; private MusicConductor music; private Vector3 redEndPosition = new Vector2(5,5); private float desirecDuration = 5f; private int i; private Queue<UnityEngine.GameObject> queue; private UnityEngine.GameObject[] array; void Awake() { beatmap = GetComponent<CSVReader>(); music = GetComponent<MusicConductor>(); } void Start() { i = 0; } void Update() { int roundedBeat = (int)Math.Round(music.songPositionInBeats, 0); if(i < beatmap.myPlayerList.player.Length && roundedBeat == beatmap.myPlayerList.player[i].beat){ GameObject redCube = GameObject.CreatePrimitive(PrimitiveType.Cube); var cubeRenderer = redCube.GetComponent<Renderer>(); cubeRenderer.material.SetColor("_Color", Color.red); i++; StartCoroutine(Movement(redCube)); } } IEnumerator Movement(GameObject cube){ // 局部变量,每个协程独立拥有,避免状态干扰 Vector3 redStartPosition = cube.transform.position; float elapsedTime = 0f; while(elapsedTime < desirecDuration){ elapsedTime += Time.deltaTime; float percentageComplete = elapsedTime / desirecDuration; cube.transform.position = Vector2.Lerp(redStartPosition, redEndPosition, percentageComplete); // 每帧更新后等待下一帧,实现平滑移动 yield return null; } } }
关键修改点
- 把
elapsedTime和redStartPosition从类级别变量改为协程内的局部变量,每个立方体的移动逻辑独立运行,互不干扰。 - 将
yield return null移至while循环内部,确保协程每帧都执行位置更新,实现平滑移动效果。
内容的提问来源于stack exchange,提问作者sarahelo
相关产品推荐
相关产品推荐

