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

立方体精准移动脚本需求:解决移动抖动与位置精度问题

精准立方体侧翻移动解决方案

嘿,我太懂你这种被浮点误差和抖动搞崩的心情了——本来要完美嵌入孔洞,结果位置飘到2.000231,完全卡不上,真的抓狂!针对你的需求,我给你一套无抖动、位置绝对精准的侧翻移动方案,核心是抛弃模糊的平移,改用基于网格对齐的侧翻旋转逻辑,彻底解决漂移问题。

为什么你的旧脚本会出问题?

大概率是这两个原因:

  • 直接用Transform.Translate或者修改position时,没有做整数网格对齐,浮点运算的累积误差导致位置偏移;
  • 如果用了物理引擎(Rigidbody),哪怕是微小的碰撞反馈或者物理更新,都会让位置产生抖动和偏差。

核心解决方案思路

  1. 固定网格步长:假设你的立方体边长为2(对应你需要的嵌入尺寸),所有移动后的位置必须是stepSize的整数倍(比如0, 2, 4...),从根源杜绝浮点漂移;
  2. 侧翻式旋转移动:不是平移,而是让立方体绕着与地面接触的边缘旋转90度,既符合真实物理感,又能精准落地到下一个网格点;
  3. 禁用不必要的物理干扰:如果用Rigidbody,设为Kinematic;或者干脆不用物理,纯Transform操作,避免引擎带来的抖动。

完整实现脚本

using UnityEngine;

public class PreciseCubeRoll : MonoBehaviour
{
    // 立方体的边长,也就是每次移动的步长
    public float stepSize = 2f;
    // 侧翻的速度,控制旋转快慢
    public float rollSpeed = 5f;

    private bool isRolling = false;
    private Vector3 targetPosition;
    private Quaternion targetRotation;

    void Update()
    {
        if (isRolling)
        {
            // 平滑旋转到目标角度,移动到目标位置
            transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, rollSpeed * Time.deltaTime);
            transform.position = Vector3.Lerp(transform.position, targetPosition, rollSpeed * Time.deltaTime);

            // 判断是否完成侧翻
            if (Quaternion.Angle(transform.rotation, targetRotation) < 0.1f && Vector3.Distance(transform.position, targetPosition) < 0.01f)
            {
                // 强制对齐到精准网格位置,彻底消除微小误差
                transform.position = new Vector3(
                    Mathf.Round(transform.position.x / stepSize) * stepSize,
                    Mathf.Round(transform.position.y / stepSize) * stepSize,
                    Mathf.Round(transform.position.z / stepSize) * stepSize
                );
                transform.rotation = targetRotation;
                isRolling = false;
            }
            return;
        }

        // 处理输入:W向前,S向后,A向左,D向右
        if (Input.GetKeyDown(KeyCode.W))
        {
            InitiateRoll(Vector3.forward);
        }
        else if (Input.GetKeyDown(KeyCode.S))
        {
            InitiateRoll(Vector3.back);
        }
        else if (Input.GetKeyDown(KeyCode.A))
        {
            InitiateRoll(Vector3.left);
        }
        else if (Input.GetKeyDown(KeyCode.D))
        {
            InitiateRoll(Vector3.right);
        }
    }

    void InitiateRoll(Vector3 direction)
    {
        // 计算旋转轴:绕着垂直于移动方向的边缘旋转
        Vector3 rotationAxis = Vector3.Cross(direction, Vector3.up);
        // 计算目标旋转角度:当前角度 + 90度绕旋转轴
        targetRotation = transform.rotation * Quaternion.AngleAxis(90f, rotationAxis);
        // 计算目标位置:当前位置 + 移动方向 × 步长(因为侧翻后会移动一个边长的距离)
        targetPosition = transform.position + direction * stepSize;

        // 强制目标位置对齐到网格
        targetPosition = new Vector3(
            Mathf.Round(targetPosition.x / stepSize) * stepSize,
            Mathf.Round(targetPosition.y / stepSize) * stepSize,
            Mathf.Round(targetPosition.z / stepSize) * stepSize
        );

        isRolling = true;
    }
}

关键细节说明

  1. 网格对齐处理:每次计算目标位置时,都会用Mathf.Round(targetPosition.x / stepSize) * stepSize把位置强制对齐到stepSize的整数倍,哪怕旋转过程中有微小误差,最后也会修正到精准位置;
  2. 侧翻旋转逻辑:用Lerp到目标旋转的方式替代直接旋转,既保证平滑动画,又能精准控制最终姿态;
  3. 状态锁死:isRolling变量确保一次侧翻完成前不会响应新的输入,避免多次触发导致的抖动和位置混乱。

使用注意事项

  • 确保你的立方体Pivot点在中心,这样旋转和位置计算才会准确;
  • 如果你的立方体边长不是2,修改stepSize变量为对应的值即可;
  • 如果不需要平滑动画,可以把rollSpeed设为一个很大的值,或者直接跳过Lerp,直接设置position和rotation(这样瞬间移动到位,绝对无抖动)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:49:25