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

Godot 4.3中如何在不删除瓦片的前提下高亮鼠标悬停的瓦片?

问题描述

我正在使用Godot 4.3的新瓦片系统,想要实现鼠标悬停时高亮对应瓦片,但不删除或替换瓦片的底层数据。我尝试使用set_cell函数来操作瓦片:

void set_cell(int layer, Vector2i coords, int source_id = -1, Vector2i atlas_coords = Vector2i(-1, -1), int alternative_tile = 0)

但我的实现会删除瓦片而非仅高亮,相关代码如下:

extends TileMap

var highlighted_tile_position: Vector2i = Vector2i(-1, -1)
var highlight_tile_id:Vector2i = get_cell_atlas_coords(layer, Vector2i(0, 1))  # Ensure this is a valid and visible tile ID

func _process(delta: float):
    var mouse_pos = to_local(get_global_mouse_position())
    var tile_pos = local_to_map(mouse_pos)

    if tile_pos != highlighted_tile_position:
        # Reset the previously highlighted tile if valid
        if highlighted_tile_position != Vector2i(-1, -1) and get_cell_source_id(layer, highlighted_tile_position) != -1:
            set_cell(layer, highlighted_tile_position, get_cell_source_id(layer, highlighted_tile_position))  # Reset to its original ID

        # Highlight the new tile if valid
        if get_cell_source_id(layer, tile_pos) != -1:
            highlighted_tile_position = tile_pos
            set_cell(layer, tile_pos, 0, highlight_tile_id)  # Attempt to highlight new tile

问题似乎出在set_cell的参数使用上,导致瓦片被删除。我怀疑source_id、atlas_coords和alternative_tile参数设置有误。

请问:

  1. 如何正确设置这些参数,在不修改底层数据的前提下改变瓦片外观?
  2. 有没有更合适的临时修改瓦片悬停外观的方法?

解决方案

1. 正确使用set_cell参数实现临时高亮

你的问题核心是调用set_cell时没有完整保留原瓦片的所有参数,导致底层数据丢失。要临时替换瓦片外观同时保留原数据,需要:

  • 先保存原瓦片的完整参数:包括source_id、atlas_coords、alternative_tile
  • 恢复时把这些参数完整传入set_cell

修改后的代码示例:

extends TileMap

# 保存高亮瓦片的原始数据
var highlighted_tile_original: Dictionary = {
    "source_id": -1,
    "atlas_coords": Vector2i(-1, -1),
    "alternative_tile": 0
}
var highlighted_tile_position: Vector2i = Vector2i(-1, -1)
# 假设高亮瓦片在第0个瓦片集的(0,1)位置
var highlight_source_id: int = 0
var highlight_atlas_coords: Vector2i = Vector2i(0, 1)

func _process(delta: float):
    var mouse_pos = to_local(get_global_mouse_position())
    var tile_pos = local_to_map(mouse_pos)

    if tile_pos != highlighted_tile_position:
        # 恢复之前高亮的瓦片
        if highlighted_tile_position != Vector2i(-1, -1) and highlighted_tile_original["source_id"] != -1:
            set_cell(
                layer,
                highlighted_tile_position,
                highlighted_tile_original["source_id"],
                highlighted_tile_original["atlas_coords"],
                highlighted_tile_original["alternative_tile"]
            )
            # 重置原始数据
            highlighted_tile_original = {
                "source_id": -1,
                "atlas_coords": Vector2i(-1, -1),
                "alternative_tile": 0
            }

        # 高亮新瓦片
        if get_cell_source_id(layer, tile_pos) != -1:
            # 保存原瓦片的所有参数
            highlighted_tile_original["source_id"] = get_cell_source_id(layer, tile_pos)
            highlighted_tile_original["atlas_coords"] = get_cell_atlas_coords(layer, tile_pos)
            highlighted_tile_original["alternative_tile"] = get_cell_alternative_tile(layer, tile_pos)
            
            highlighted_tile_position = tile_pos
            # 设置高亮瓦片,注意传入正确的source_id和atlas_coords
            set_cell(layer, tile_pos, highlight_source_id, highlight_atlas_coords)

关键说明:

  • 调用set_cell时,必须传入原瓦片的全部三个核心参数(source_id、atlas_coords、alternative_tile)才能完整恢复原瓦片
  • 你的原代码恢复时只传了source_id,忽略了atlas_coords和alternative_tile,导致瓦片数据不完整,看起来像是被删除

2. 更合适的临时高亮方法:无侵入式实现

直接修改瓦片数据容易出错,更推荐两种不需要修改原始数据的方式:

方法一:通过_draw绘制高亮遮罩

不需要修改任何瓦片数据,直接在TileMap的绘制阶段叠加高亮效果:

extends TileMap

var highlighted_tile_position: Vector2i = Vector2i(-1, -1)

func _process(delta: float):
    var mouse_pos = to_local(get_global_mouse_position())
    var tile_pos = local_to_map(mouse_pos)
    # 只在瓦片存在时更新高亮位置
    if get_cell_source_id(layer, tile_pos) != -1:
        highlighted_tile_position = tile_pos
    else:
        highlighted_tile_position = Vector2i(-1, -1)
    # 触发重绘
    queue_redraw()

func _draw():
    if highlighted_tile_position != Vector2i(-1, -1):
        # 获取瓦片的世界矩形
        var tile_rect = get_cell_rect(layer, highlighted_tile_position)
        # 绘制半透明高亮矩形(可自定义颜色和透明度)
        draw_rect(tile_rect, Color(1, 1, 0, 0.3))
        # 也可以替换成高亮纹理
        # var highlight_texture = load("res://highlight_tile.png")
        # draw_texture(highlight_texture, tile_rect.position)

方法二:使用独立的高亮图层

在TileMap中添加一个专门的高亮图层(不存储实际地图数据),鼠标悬停时在该图层设置高亮瓦片,离开时清除:

extends TileMap

const HIGHLIGHT_LAYER: int = 1  # 假设第1层是高亮专用层
var highlighted_tile_position: Vector2i = Vector2i(-1, -1)
var highlight_source_id: int = 0
var highlight_atlas_coords: Vector2i = Vector2i(0, 1)

func _process(delta: float):
    var mouse_pos = to_local(get_global_mouse_position())
    var tile_pos = local_to_map(mouse_pos)

    if tile_pos != highlighted_tile_position:
        # 清除之前的高亮瓦片
        if highlighted_tile_position != Vector2i(-1, -1):
            set_cell(HIGHLIGHT_LAYER, highlighted_tile_position, -1)

        # 设置新的高亮(仅当底层瓦片存在时)
        if get_cell_source_id(0, tile_pos) != -1:  # 0是实际数据层
            highlighted_tile_position = tile_pos
            set_cell(HIGHLIGHT_LAYER, tile_pos, highlight_source_id, highlight_atlas_coords)
        else:
            highlighted_tile_position = Vector2i(-1, -1)

这种方式完全不修改原始数据层,逻辑更清晰,也避免了数据恢复的潜在问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 22:49:53