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

Unity移植Love2D游戏:六边形邻居鼠标悬停高亮异常求助

解决Unity中六边形邻居高亮切换时共同邻居不显示的问题

我刚梳理完你的代码,立刻就发现了核心问题——你的高亮逻辑依赖颜色判断状态,但当两个六边形有共同邻居时,切换悬停操作会让这个邻居的状态陷入混乱:上一个六边形的取消高亮会把它改回原始色,而新六边形的高亮检测会误以为它已经被处理过,跳过了高亮步骤。

问题根源拆解

  1. 颜色判断的脆弱性:你通过tile.GetComponent<Renderer>().material.color == tile.data.Elements[tile.data.Element]来判断是否未被高亮,但颜色是浮点数类型,容易出现精度误差;更关键的是,它无法跟踪「多个悬停六边形同时需要高亮同一个邻居」的场景。
  2. 状态更新逻辑混乱:你在同一个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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:32:53