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

Update中ContainsKey返回true,同值在其他方法返回false的问题

问题原因及解决方案

核心问题:浮点数精度误差

你遇到的问题本质是浮点数的二进制表示精度限制导致的。Vector2作为Dictionary的键时,会使用其默认的Equals和GetHashCode方法进行比较,而浮点数计算(比如Mathf.Round(x/1.28f)*1.28f)很可能产生微小的精度偏差(例如理论上的-2.56f实际计算后可能变成-2.5600001f),导致两个看似相同的Vector2被判定为不相等。

Update中直接使用new Vector2(-2.56f, 6.4f)能找到键,是因为这个值和你添加到字典时的blockPos完全一致;但GetBlocksAtPosition中通过计算得到的newX/newY,哪怕只是有极小的精度差异,都会让ContainsKey返回false。

解决方案

方案1:改用整数网格索引作为键(推荐)

彻底规避浮点数精度问题,将坐标转换为整数形式的网格索引:

// 定义字典时改用整数索引作为键
private Dictionary<Tuple<int, int>, Dictionary<Block, SpriteRenderer>> BlocksDictionary;

// 初始化字典
void Awake()
{
    BlocksDictionary = new Dictionary<Tuple<int, int>, Dictionary<Block, SpriteRenderer>>();
}

// 修改GetBlocksAtPosition方法
public Dictionary<Block, SpriteRenderer> GetBlocksAtPosition(float x, float y, bool gridifyCoords = false)
{
    int xIndex = Mathf.RoundToInt(x / 1.28f);
    int yIndex = Mathf.RoundToInt(y / 1.28f);
    var key = Tuple.Create(xIndex, yIndex);

    if (BlocksDictionary.ContainsKey(key))
        return BlocksDictionary[key];
    else
    {
        print($"Blocks not found at grid index: {xIndex} - {yIndex}");
        return null;
    }
}

// 修改添加方块的代码
var gridIndex = Tuple.Create(Mathf.RoundToInt(blockPos.x / 1.28f), Mathf.RoundToInt(blockPos.y / 1.28f));
if (BlocksDictionary.ContainsKey(gridIndex))
{
    if (!BlocksDictionary[gridIndex].ContainsKey(blockSO))
        BlocksDictionary[gridIndex].Add(blockSO, spriteRenderer);
}
else
{
    var newBlockDict = new Dictionary<Block, SpriteRenderer>();
    newBlockDict.Add(blockSO, spriteRenderer);
    BlocksDictionary.Add(gridIndex, newBlockDict);
}

方案2:自定义Vector2相等比较器

创建一个支持精度容错的比较器,让Dictionary在判断键相等时忽略微小的浮点数差异:

// 自定义相等比较器
public class Vector2PrecisionComparer : IEqualityComparer<Vector2>
{
    private readonly float _tolerance;

    public Vector2PrecisionComparer(float tolerance = 1e-6f)
    {
        _tolerance = tolerance;
    }

    public bool Equals(Vector2 a, Vector2 b)
    {
        return Mathf.Abs(a.x - b.x) < _tolerance && Mathf.Abs(a.y - b.y) < _tolerance;
    }

    public int GetHashCode(Vector2 vec)
    {
        // 将浮点数按 tolerance 取整后计算哈希,减少冲突
        int xHash = Mathf.RoundToInt(vec.x / _tolerance).GetHashCode();
        int yHash = Mathf.RoundToInt(vec.y / _tolerance).GetHashCode();
        return xHash ^ (yHash << 2);
    }
}

// 初始化字典时传入比较器
BlocksDictionary = new Dictionary<Vector2, Dictionary<Block, SpriteRenderer>>(new Vector2PrecisionComparer());

方案3:统一键的生成逻辑

确保添加方块到字典时,和GetBlocksAtPosition使用完全相同的坐标计算逻辑,让两边生成的键完全一致:

// 定义统一的坐标转换方法
Vector2 GetGridifiedPos(Vector2 pos)
{
    return new Vector2(Mathf.Round(pos.x / 1.28f) * 1.28f, Mathf.Round(pos.y / 1.28f) * 1.28f);
}

// 修改添加方块的代码,使用统一方法生成键
var gridifiedPos = GetGridifiedPos(blockPos);
if (BlocksDictionary.ContainsKey(gridifiedPos))
{
    if (!BlocksDictionary[gridifiedPos].ContainsKey(blockSO))
        BlocksDictionary[gridifiedPos].Add(blockSO, spriteRenderer);
}
else
{
    var newBlockDict = new Dictionary<Block, SpriteRenderer>();
    newBlockDict.Add(blockSO, spriteRenderer);
    BlocksDictionary.Add(gridifiedPos, newBlockDict);
}

// 修改GetBlocksAtPosition方法,调用统一转换方法
public Dictionary<Block, SpriteRenderer> GetBlocksAtPosition(float x, float y, bool gridifyCoords = false)
{
    Vector2 blockCoords = new Vector2(x, y);
    if (gridifyCoords)
    {
        blockCoords = GetGridifiedPos(blockCoords);
    }

    if (BlocksDictionary.ContainsKey(blockCoords))
        return BlocksDictionary[blockCoords];
    else
    {
        print($"Blocks not found at: {blockCoords.x} - {blockCoords.y}");
        return null;
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 00:27:08