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

如何实现等距点触游戏中CharacterBody2D仅向有效Tile移动并防穿越虚空?

等距点触游戏中限制角色仅在有效Tile上移动的实现方案

我正在学习搭建一款等距点触(Point-and-Click)游戏,目前已经实现了CharacterBody2D向用户点击位置移动的功能,场景中还放置了带有Tile的Tilemap。现在想请教如何编写代码,让玩家仅在点击有效Tile时才触发移动,同时避免角色穿越虚空区域?

以下是我当前的玩家移动脚本:

extends CharacterBody2D

@export var speed = 400

var target

func _ready():
    target = global_position

func _input(event):
    if event is InputEventMouseButton and event.pressed:
        target = get_global_mouse_position()
        print(event)

func _physics_process(delta):
    velocity = global_position.direction_to(target) * speed
    if global_position.distance_to(target) > 10:
        move_and_collide(velocity * delta)

相关截图:
游戏窗口
场景导航
Tilemap检查器


实现方案

核心思路

通过将鼠标点击坐标转换为Tilemap网格坐标,验证该位置是否存在有效Tile,同时配合Tilemap的碰撞配置,实现仅在有效地面点击时移动、防止角色穿越虚空的效果。

步骤1:配置Tilemap碰撞

先确认Tilemap的碰撞设置正确:

  • 在Tile集编辑器中,给可行走的Tile添加碰撞形状(参考你提供的Tilemap检查器截图,确保已关联碰撞)。
  • 调整Tilemap的Collision Layer,并让玩家CharacterBody2D的Collision Mask与之匹配,确保虚空区域能阻挡角色移动。

步骤2:修改玩家脚本

更新脚本,加入Tile有效性检查逻辑:

extends CharacterBody2D

@export var speed = 400
# 在编辑器中拖入场景中的Tilemap
@export var ground_tilemap: TileMap2D

var target

func _ready():
    target = global_position

func _input(event):
    if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
        # 把鼠标全局坐标转成Tilemap本地坐标
        var local_pos = ground_tilemap.global_to_local(get_global_mouse_position())
        # 获取对应网格坐标
        var tile_coords = ground_tilemap.local_to_map(local_pos)
        
        # 检查该网格是否有有效Tile(-1代表无Tile)
        if ground_tilemap.get_cell_source_id(tile_coords) != -1:
            # 把网格坐标转成全局坐标,调整到Tile中心(适配等距Tile锚点)
            var tile_global_pos = ground_tilemap.map_to_global(tile_coords)
            target = tile_global_pos + ground_tilemap.tile_set.get_tile_size() / 2
            print("点击有效Tile,设置移动目标:", target)
        else:
            print("点击虚空区域,不触发移动")

func _physics_process(delta):
    var direction = global_position.direction_to(target)
    velocity = direction * speed
    
    # 距离目标足够近时停止移动
    if global_position.distance_to(target) > 10:
        move_and_collide(velocity * delta)
    else:
        velocity = Vector2.ZERO

补充说明

  • 若需要更细致的行走权限控制,可以给Tile添加自定义属性(比如is_walkable),通过ground_tilemap.get_cell_metadata(tile_coords, "is_walkable")来判断。
  • 等距Tile的锚点如果不是中心,需要调整target的偏移量,确保角色落在Tile的正确位置。
  • 只要Tilemap碰撞配置正确,move_and_collide会自动处理角色与虚空区域的碰撞,防止穿越。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 09:40:19