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. 正确使用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
相关产品推荐
相关产品推荐

