Unity移植Love2D游戏:六边形邻居鼠标悬停高亮异常求助
解决Unity中六边形邻居高亮切换时共同邻居不显示的问题
我刚梳理完你的代码,立刻就发现了核心问题——你的高亮逻辑依赖颜色判断状态,但当两个六边形有共同邻居时,切换悬停操作会让这个邻居的状态陷入混乱:上一个六边形的取消高亮会把它改回原始色,而新六边形的高亮检测会误以为它已经被处理过,跳过了高亮步骤。
问题根源拆解
- 颜色判断的脆弱性:你通过
tile.GetComponent<Renderer>().material.color == tile.data.Elements[tile.data.Element]来判断是否未被高亮,但颜色是浮点数类型,容易出现精度误差;更关键的是,它无法跟踪「多个悬停六边形同时需要高亮同一个邻居」的场景。 - 状态更新逻辑混乱:你在同一个
foreach循环里同时处理所有六边形的悬停状态,当从A切换到B时,A的取消高亮和B的高亮操作可能在同一帧里交叉执行,导致共同邻居被取消后,新的高亮没及时触发。
修复方案:用计数器跟踪高亮状态
最可靠的方式是给每个Tile添加一个计数器,记录当前有多少个悬停的六边形把它标记为需要高亮。这样就能精准控制邻居的高亮/取消状态,不会出现漏高亮的情况。
步骤1:给Tile类添加状态变量
在你的Tile脚本里新增计数器和缓存Renderer组件(避免频繁调用GetComponent):
public int highlightCount = 0; private Renderer _tileRenderer; void Awake() { _tileRenderer = GetComponent<Renderer>(); }
步骤2:重写highlightNeighbors函数
把依赖颜色判断的逻辑替换为计数器控制:
void highlightNeighbors(bool on, Hex hex) { foreach(Tile tile in hex.neighbours) { if (on) { // 高亮:增加计数,仅当第一次被标记时修改颜色 tile.highlightCount++; if(tile.highlightCount == 1) { Color originalColor = tile.data.Elements[tile.data.Element]; // 注意:Color用0-1范围的浮点数,所以把20转成20/255f tile._tileRenderer.material.color = originalColor + new Color(20/255f, 20/255f, 20/255f, 0); } } else { // 取消高亮:减少计数,仅当没有任何高亮需求时恢复原始色 tile.highlightCount--; if(tile.highlightCount < 0) tile.highlightCount = 0; if(tile.highlightCount == 0) { tile._tileRenderer.material.color = tile.data.Elements[tile.data.Element]; } } } }
步骤3:优化悬停状态判断逻辑
把原来混乱的循环拆分为「先处理旧悬停、再处理新悬停」的顺序,避免状态冲突:
// 先找到之前悬停的六边形 Hex previousHovered = null; foreach(KeyValuePair<GameObject,Hex> entry in HexData) { if(entry.Value.hovering && entry.Key != hovering) { previousHovered = entry.Value; break; } } // 取消旧悬停六边形的邻居高亮 if(previousHovered != null) { highlightNeighbors(false, previousHovered); previousHovered.neighborsHighlighted = false; previousHovered.hovering = false; } // 处理当前悬停的六边形 if(hovering != null && HexData.ContainsKey(hovering)) { Hex currentHex = HexData[hovering]; if(!currentHex.neighborsHighlighted) { highlightNeighbors(true, currentHex); currentHex.neighborsHighlighted = true; currentHex.hovering = true; } } // 处理无任何六边形被悬停的情况 if(hovering == null) { foreach(KeyValuePair<GameObject,Hex> entry in HexData) { if(entry.Value.neighborsHighlighted) { highlightNeighbors(false, entry.Value); entry.Value.neighborsHighlighted = false; entry.Value.hovering = false; } } }
额外优化建议
- 缓存所有Tile的原始颜色:在Awake里把
tile.data.Elements[tile.data.Element]存到Tile的变量里,避免重复查找; - 减少Material属性修改:只有当计数器变化到阈值时才修改颜色,降低渲染开销;
- 用
MaterialPropertyBlock代替直接修改material:如果有大量六边形,这能减少材质实例化,提升性能。
这样修改后,不管你切换多少个有共同邻居的六边形,共同邻居的计数器都会准确跟踪高亮需求,只要还有一个六边形悬停需要它高亮,它就会保持高亮状态。
内容的提问来源于stack exchange,提问作者Ducktor
相关产品推荐
相关产品推荐

