You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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是类级别的全局变量:

  1. 第一个立方体的协程运行时,会持续累加elapsedTime直到超过5秒,后续协程启动时,这个变量已经满足elapsedTime >= desirecDuration,导致while循环直接跳过,不会执行移动逻辑。
  2. 多个协程共享redStartPosition,后续立方体的起始位置会被前一个协程覆盖,即使循环执行,位置计算也会出错。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 19:56:13