如何使用Godot 3D网格对齐拖拽卡牌,避免重叠与超出游戏板边界
网格吸附+边界校验实现方案
核心实现逻辑为:将刚体游戏板的表面划分为与卡牌尺寸匹配的固定网格,每次射线检测到放置位置后,先将坐标对齐到最近的网格格子中心,再依次校验坐标是否在游戏板边界内、对应网格是否已被占用,全部符合条件再生成卡牌,即可解决重叠和超出边界的问题。
第一步:定义网格与边界全局参数
在脚本顶部新增以下变量,数值根据你项目中卡牌、游戏板的实际尺寸调整即可:
# 网格格子尺寸,对应单张卡牌的长宽(3D场景下游戏板平面一般为XZ轴) var grid_cell_width = 5.0 var grid_cell_height = 3.0 # 游戏板坐标边界,可在编辑器中选中游戏板节点查看其尺寸范围后填写 var board_min_x = -20.0 var board_max_x = 20.0 var board_min_z = -10.0 var board_max_z = 10.0 # 存储已被占用的网格,key为网格坐标拼接的字符串,value为对应卡牌实例 var occupied_grid = {}
第二步:新增网格对齐工具函数
# 将射线检测到的世界坐标转换为最近的网格中心坐标 func snap_to_grid(world_pos: Vector3) -> Vector3: var grid_x = round(world_pos.x / grid_cell_width) var grid_z = round(world_pos.z / grid_cell_height) var snapped_x = grid_x * grid_cell_width var snapped_z = grid_z * grid_cell_height return Vector3(snapped_x, world_pos.y, snapped_z)
第三步:修改place()函数,新增校验逻辑
func place(): var rayOrigin = Vector3() var rayEnd = Vector3() var cardbase = preload("res://Cards/CardBase.tscn") var card = preload("res://Cards/3dcard.tscn") var cardscript = preload("res://Cards/3dcard.gd") var camera = get_tree().get_root().find_node("Camera", true, false) if Input.is_action_just_released("leftclick") && cardinhand == 1 : var space_state = get_world().direct_space_state var mouse_position = get_viewport().get_mouse_position() rayOrigin = camera.project_ray_origin(mouse_position) rayEnd = rayOrigin + camera.project_ray_normal(mouse_position) * 2000000000 var intersection = space_state.intersect_ray(rayOrigin, rayEnd) if not intersection.empty(): # 校验点击对象是否为游戏板,避免点到其他物体也生成卡牌 if intersection.collider.name != "替换为你游戏板节点的实际名称": return # 坐标对齐网格 var target_pos = snap_to_grid(intersection.position) # 校验坐标是否在游戏板边界内 if target_pos.x < board_min_x or target_pos.x > board_max_x or target_pos.z < board_min_z or target_pos.z > board_max_z: return # 校验当前网格是否已被占用 var grid_key = str(round(target_pos.x/grid_cell_width)) + "," + str(round(target_pos.z/grid_cell_height)) if grid_key in occupied_grid: return # 所有校验通过后生成卡牌 board = 1 var addcard = card.instance() addcard.Cardname = cardnm add_child(addcard) # 轻微抬升Y轴避免卡牌与游戏板穿模 addcard.translation = Vector3(target_pos.x, intersection.position.y + 0.01, target_pos.z) # 标记当前网格为已占用 occupied_grid[grid_key] = addcard cardinhand = 0
补充说明
如果后续需要实现卡牌移除功能,只需删除occupied_grid中对应的key即可释放对应网格,不影响后续卡牌放置。
内容的提问来源于stack exchange,提问作者TheBlackHorse
相关产品推荐
相关产品推荐

