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

Unity中如何实现高精度2D网格移动系统

Unity 2D 垂直方向严格网格移动实现方案

针对高精度网格位移需求,核心是从输入、移动、结算全流程规避位置偏移,不要靠实时输入直接拖拽角色,所有位移以固定网格步长为单位,移动过程锁输入、结束强制对齐,彻底消除浮点误差。

核心实现逻辑

  • 固定网格步长:单格尺寸统一配置,每次垂直移动的距离严格等于单格边长,从根源避免位移偏差
  • 状态锁机制:只有角色完全静止、对齐网格点时才响应新的移动输入,移动过程中忽略其他操作指令
  • 强制对齐校验:每次移动结算时把坐标吸附到最近网格点,抵消浮点运算累计的位置误差
  • 移动接口统一:用刚体就全程走刚体移动API,不用物理就全程改transform,不要混写避免位置抖动

具体实现步骤

1. 基础组件配置

给移动角色挂载以下组件:

  • Rigidbody2D:重力缩放设为0,冻结Z轴旋转、X轴位移(仅做垂直移动时锁X轴,后续加水平移动再放开)
  • Collider2D(Box/Circle均可):碰撞体尺寸匹配角色大小,建议刚好占满单格空间
  • 若不需要物理碰撞,可省略刚体组件,直接操作Transform即可

2. 可直接复用的实现代码

using UnityEngine;

public class VerticalGridMover : MonoBehaviour
{
    [Header("移动配置")]
    [Tooltip("单个网格的边长,建议和Unity单位统一,默认1单位=1格")]
    public float gridSize = 1f;
    [Tooltip("格子间移动的速度")]
    public float moveSpeed = 6f;
    [Tooltip("障碍检测层,用来阻挡移动")]
    public LayerMask obstacleMask;

    private Rigidbody2D _rb;
    private bool _isMoving;
    private Vector2 _targetPosition;

    void Awake()
    {
        _rb = GetComponent<Rigidbody2D>();
        // 初始位置强制对齐网格,避免出生点偏移
        SnapToNearestGrid();
    }

    void Update()
    {
        // 非移动状态才检测输入
        if (!_isMoving)
        {
            // 用GetAxisRaw拿到离散的输入值,只会返回-1/0/1,无渐变延迟
            float verticalInput = Input.GetAxisRaw("Vertical");
            if (Mathf.Abs(verticalInput) > 0.01f)
            {
                Vector2 moveDir = new Vector2(0, Mathf.Sign(verticalInput));
                Vector2 nextPos = (Vector2)transform.position + moveDir * gridSize;
                
                // 检测目标格子是否有障碍,无遮挡才触发移动
                if (!Physics2D.OverlapBox(nextPos, Vector2.one * 0.9f, 0, obstacleMask))
                {
                    _targetPosition = nextPos;
                    _isMoving = true;
                }
            }
        }
    }

    void FixedUpdate()
    {
        if (!_isMoving) return;
        
        // 刚体移动保证碰撞检测正常
        _rb.MovePosition(Vector2.MoveTowards(
            _rb.position, 
            _targetPosition, 
            moveSpeed * Time.fixedDeltaTime
        ));

        // 到达目标点后结束移动,强制对齐位置消除浮点误差
        if (Vector2.Distance(_rb.position, _targetPosition) < 0.001f)
        {
            _rb.MovePosition(_targetPosition);
            _isMoving = false;
        }
    }

    // 坐标吸附到最近网格点的工具方法
    void SnapToNearestGrid()
    {
        float x = Mathf.Round(transform.position.x / gridSize) * gridSize;
        float y = Mathf.Round(transform.position.y / gridSize) * gridSize;
        transform.position = new Vector3(x, y, transform.position.z);
    }
}

3. 精度优化注意事项

  • 障碍检测的检测框尺寸设为单格的90%即可,不要用满格大小,避免相邻碰撞体边缘贴合导致的误判
  • 不要用Input.GetAxis做输入检测,它的输入值是渐变的,容易导致移动延迟、重复触发
  • 无论用什么方式移动,最后一步的位置强制吸附不能省,浮点运算的累计误差跑几十次移动就会出现明显的网格错位
  • 不用物理系统的话,把FixedUpdate里的刚体移动逻辑挪到Update里,直接改transform.position即可,吸附逻辑完全复用
  • 移动动画直接绑定_isMoving状态触发,不要靠速度值判定动画状态,避免浮点误差导致的动画闪切

后续如果要扩展水平移动,只需要补充水平输入的检测逻辑、放开刚体X轴位移限制即可,整套网格对齐、状态锁的逻辑不需要修改。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 01:30:36