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

Unity:使用Translate与IEnumerator移动GameObject抖动问题排查

问题:鸟巢移动抖动且定时延迟仅生效一次

我正在制作一款简单的投篮类游戏,玩法是将鸡蛋投入移动的鸟巢中。尝试通过Translate方法移动GameObject,结合随机大小和方向的向量,让鸟巢在两个固定位置间定时随机移动。但测试时鸟巢出现原地抖动,且延迟仅在游戏启动时生效。

推测问题可能与Update方法持续调用协程有关,但不清楚为何会引发抖动及修复方式。以下是功能代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MoveNest : MonoBehaviour
{
    public bool gameStarted = true;
    public float delay = 4;
    public float nestMoveSpeed = 1;
    public Vector3 nestMoveDirection = Vector3.zero;
    private int zBound = 8;

    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        if (gameStarted)
        {
            StartCoroutine("ChangeMoveDirection");
            transform.Translate(nestMoveDirection * Time.deltaTime * nestMoveSpeed);
        }
    }

    IEnumerator ChangeMoveDirection()
    {
        yield return new WaitForSeconds(delay);
        float minValue = 0;
        float maxValue = 0;

        if (transform.position.z >= zBound)
        {
            minValue = -10;
            maxValue = 0;

        }
        else if (transform.position.z <= -zBound)
        {
            minValue = 0;
            maxValue = 10;

        }
        else
        {
            minValue = -10;
            maxValue = 10;
        }
        nestMoveDirection = new Vector3(0, 0, Random.RandomRange(minValue, maxValue));

    }
}

问题原因

  1. 协程重复启动:Update方法每帧都会调用StartCoroutine("ChangeMoveDirection"),短时间内生成大量协程实例。当这些协程到达延迟时间后,会频繁修改nestMoveDirection,方向随机切换导致抖动。
  2. 方向向量未归一化:随机生成的-10到10的z轴向量大小不稳定,造成移动速度忽快忽慢,加剧抖动。
  3. 定时逻辑失效:大量协程堆积导致后续定时触发完全混乱,仅初始延迟生效。

修复方案

  • 仅启动一个协程实例,在内部循环执行方向变更逻辑,避免重复启动。
  • 对随机方向向量归一化,保证移动速度稳定。
  • 优化边界检测,强制限制鸟巢在指定范围内移动。

修复后的代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MoveNest : MonoBehaviour
{
    public bool gameStarted = true;
    public float delay = 4;
    public float nestMoveSpeed = 1;
    private Vector3 nestMoveDirection = Vector3.zero;
    private int zBound = 8;

    void Start()
    {
        // 游戏启动时仅启动一次循环协程
        if (gameStarted)
        {
            StartCoroutine(ChangeMoveDirectionLoop());
        }
    }

    void Update()
    {
        if (gameStarted)
        {
            transform.Translate(nestMoveDirection * Time.deltaTime * nestMoveSpeed);
            // 强制限制位置在边界内
            ClampPosition();
        }
    }

    // 循环执行方向变更的协程
    IEnumerator ChangeMoveDirectionLoop()
    {
        while (gameStarted)
        {
            yield return new WaitForSeconds(delay);
            
            float minValue = 0;
            float maxValue = 0;

            if (transform.position.z >= zBound)
            {
                minValue = -1f;
                maxValue = 0f;
            }
            else if (transform.position.z <= -zBound)
            {
                minValue = 0f;
                maxValue = 1f;
            }
            else
            {
                minValue = -1f;
                maxValue = 1f;
            }
            // 生成归一化的随机方向,保证速度稳定
            float randomZ = Random.Range(minValue, maxValue);
            nestMoveDirection = new Vector3(0, 0, randomZ).normalized;
        }
    }

    // 限制鸟巢位置在z轴边界内
    void ClampPosition()
    {
        Vector3 newPos = transform.position;
        newPos.z = Mathf.Clamp(newPos.z, -zBound, zBound);
        transform.position = newPos;
    }
}

关键修改点

  • 改用循环协程ChangeMoveDirectionLoop,仅在Start中启动一次,避免协程堆积。
  • 随机方向范围改为-1到1,归一化后保证移动速度始终与nestMoveSpeed一致。
  • 添加ClampPosition方法,强制限制鸟巢位置,防止超出边界。
  • 移除Update中的协程启动代码,避免每帧重复触发。

内容的提问来源于stack exchange,提问作者DTD

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 17:05:19