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
相关产品推荐
相关产品推荐

