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

Dictionary.ContainsKey处理Transform.Forward与硬编码Vector3的差异问题

回合制游戏网格投射物移动匹配问题排查

问题背景

我正在搭建回合制游戏的网格系统,网格用Dictionary<Vector3, Node>存储,Node类管理单位占用状态等逻辑。敌方单位会根据玩家位置生成投射物,投射物实例化后固定沿transform.forward方向移动:下一个目标Node可用就移动,否则销毁并攻击玩家。

判断移动可行性的代码

挂载在投射物的“Linear Movement”组件中:

grid = GridManager.instance.grid; // 从单例缓存网格引用

// 其他代码

public bool NextNodeIsWalkable { get
{
    if (!grid.ContainsKey(moveTarget)) return false;
    return grid[moveTarget].isWalkable;
} }

问题核心:moveTarget计算逻辑

private Vector3 moveTarget { get
     {
            return Vector3.right * transform.position.x + Vector3.forward * transform.position.z + moveDirection;
     } }

moveDirection在OnEnable中被赋值为moveDirection = transform.forward。

异常现象

  • 投射物沿垂直方向(Z轴)移动时,逻辑完全正常;
  • 沿水平方向(X轴)移动时,偶尔会出现grid.ContainsKey(moveTarget)返回false(实际对应Node存在),导致投射物错误爆炸;
  • 交换玩家与敌人位置,反转投射物水平移动方向后,有时ContainsKey又能正常匹配;
  • 将moveDirection改为硬编码的轴向向量(如Vector3.right),无论哪种情况都能正常匹配,即便此时transform.forward的数值和硬编码值看起来完全一致。

问题根源:浮点数精度误差导致的键匹配失败

  1. transform.forward的浮点偏差:
    Unity中transform.forward是通过Transform旋转计算得到的向量,即便视觉上是严格的轴向(比如X轴方向的(1,0,0)),实际计算时可能因为浮点数精度问题,出现(1.0000001, 0, 0)或(0.9999999, 0, 0)这类微小偏差。

  2. Vector3作为字典键的严格匹配逻辑:
    Dictionary<Vector3, Node>中,Vector3的相等判断是逐浮点值严格匹配的。当moveDirection带有精度偏差时,计算出的moveTarget会和网格中存储的Node坐标(比如(2,0,1))产生微小差异,导致ContainsKey无法找到对应键。

  3. 垂直移动无问题的原因:
    垂直移动时,transform.forward对应Z轴方向,旋转计算时Z轴的精度偏差更容易被抵消,或者网格Z轴坐标都是整数,叠加后偏差未影响最终的整数坐标匹配;而水平方向的X轴旋转计算更容易出现浮点偏差。

  4. 硬编码向量正常的原因:
    Unity内置的Vector3.right/Vector3.forward等是精确的轴向向量(比如Vector3.right就是严格的(1,0,0)),没有浮点偏差,因此计算出的moveTarget和网格键完全一致,不会匹配失败。

解决方案

方案1:对moveTarget进行取整处理

因为网格是整数单元格,计算目标位置后将坐标四舍五入到整数:

private Vector3 moveTarget { get
{
    Vector3 rawTarget = Vector3.right * transform.position.x + Vector3.forward * transform.position.z + moveDirection;
    // 仅保留整数坐标,匹配网格的Node位置
    return new Vector3(Mathf.Round(rawTarget.x), rawTarget.y, Mathf.Round(rawTarget.z));
} }

方案2:初始化时将moveDirection转为精确轴向向量

在OnEnable中,把transform.forward转换为无偏差的轴向向量:

void OnEnable()
{
    // 取整后归一化,得到精确的轴向方向
    Vector3 roundedForward = new Vector3(
        Mathf.Round(transform.forward.x),
        0, // 忽略Y轴,适配2D网格
        Mathf.Round(transform.forward.z)
    );
    moveDirection = Vector3.Normalize(roundedForward);
}

方案3:改用整数类型作为网格键

推荐将Dictionary<Vector3, Node>改为Dictionary<Vector2Int, Node>(忽略Y轴,适配2D网格),彻底规避浮点精度问题:

  • 存储网格时,用Vector2Int记录Node的坐标;
  • 计算目标位置时,将投射物的transform.position转为Vector2Int,再加上方向对应的Vector2Int(如Vector2Int.right)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 15:30:50