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

Godot 4.3:实现TileMap玩家按住方向键持续移动功能

需求与现有代码

我之前用Flash做游戏,现在因为Flash过时转用Godot。已经实现了玩家控制角色在TileMap上移动,但想要实现按住方向键时,角色沿对应方向持续移动,直到进入与不可行走瓷砖相邻的可行走瓷砖为止。以下是我目前的代码:

extends Sprite2D

class_name PacMan

@export var move_speed: float = 1

@onready var tile_map: TileMap = $"../TileMap"
@onready var sprite_2d: Sprite2D = $Sprite2D
@onready var animation_player: AnimationPlayer = $Sprite2D/AnimationPlayer

var is_moving = false

func _physics_process(delta: float) -> void:
    if is_moving == false:
        return
    if global_position == sprite_2d.global_position:
        is_moving = false
        return
    sprite_2d.global_position = sprite_2d.global_position.move_toward(global_position, move_speed)

func _ready() -> void:
    animation_player.play("chomping")

func _process(delta: float) -> void:
    if is_moving:
        return
    if Input.is_action_pressed("up"):
        rotation_degrees = 90
        move(Vector2.UP)
        is_moving = true
    elif Input.is_action_pressed("down"):
        rotation_degrees = 270
        move(Vector2.DOWN)
        is_moving = true
    elif Input.is_action_pressed("left"):
        rotation_degrees = 0
        move(Vector2.LEFT)
        is_moving = true
    elif Input.is_action_pressed("right"):
        rotation_degrees = 180
        move(Vector2.RIGHT)
        is_moving = true

func move(direction: Vector2):
    var current_tile: Vector2i = tile_map.local_to_map(global_position)
    var target_tile: Vector2i = Vector2i(
        current_tile.x + direction.x,
        current_tile.y + direction.y,
    )
    var tile_data: TileData = tile_map.get_cell_tile_data(0, target_tile)
    if tile_data.get_custom_data("walk_tiles") == false:
        return
    #Player movement
    is_moving = true
    global_position = tile_map.map_to_local(target_tile)
    sprite_2d.global_position = tile_map.map_to_local(current_tile)
实现思路与代码修改

核心逻辑是:角色到达一个瓷砖后,自动检测当前按住方向的下一个瓷砖是否可行走,可行走就继续移动,不可行走则停止。具体修改如下:

1. 添加方向记录变量

新增变量保存当前按住的方向,避免每次移动都重新检测输入:

var is_moving = false
var current_move_direction: Vector2 = Vector2.ZERO # 新增

2. 持续更新按住的方向

修改_process函数,不管角色是否在移动,都实时更新当前按住的方向:

func _process(delta: float) -> void:
    current_move_direction = Vector2.ZERO
    if Input.is_action_pressed("up"):
        current_move_direction = Vector2.UP
        rotation_degrees = 90
    elif Input.is_action_pressed("down"):
        current_move_direction = Vector2.DOWN
        rotation_degrees = 270
    elif Input.is_action_pressed("left"):
        current_move_direction = Vector2.LEFT
        rotation_degrees = 0
    elif Input.is_action_pressed("right"):
        current_move_direction = Vector2.RIGHT
        rotation_degrees = 180

3. 到达瓷砖后自动续接移动

修改_physics_process函数,处理移动逻辑的同时,在角色到达目标瓷砖后自动检查下一个可行走瓷砖:

func _physics_process(delta: float) -> void:
    if is_moving:
        # 用距离判断避免浮点精度问题
        if sprite_2d.global_position.distance_to(global_position) < 0.1:
            sprite_2d.global_position = global_position
            is_moving = false
            # 到达后检查是否可以继续移动
            if current_move_direction != Vector2.ZERO:
                try_continue_move(current_move_direction)
        else:
            # 乘delta保证不同帧率下速度一致
            sprite_2d.global_position = sprite_2d.global_position.move_toward(global_position, move_speed * delta)
    else:
        # 未移动时,有方向键按下就触发移动
        if current_move_direction != Vector2.ZERO:
            try_continue_move(current_move_direction)

4. 封装移动检查逻辑

新增函数统一处理瓷砖可行性检查和移动触发:

func try_continue_move(direction: Vector2):
    var current_tile: Vector2i = tile_map.local_to_map(sprite_2d.global_position)
    var target_tile: Vector2i = current_tile + direction
    var tile_data: TileData = tile_map.get_cell_tile_data(0, target_tile)
    # 检查目标瓷砖是否存在且可行走
    if tile_data != null and tile_data.get_custom_data("walk_tiles") == true:
        is_moving = true
        global_position = tile_map.map_to_local(target_tile)

5. 移除原move函数

原move函数的逻辑已被try_continue_move替代,可直接删除。

修改后的完整代码
extends Sprite2D

class_name PacMan

@export var move_speed: float = 200 # 建议调大,配合delta使用更合理

@onready var tile_map: TileMap = $"../TileMap"
@onready var sprite_2d: Sprite2D = $Sprite2D
@onready var animation_player: AnimationPlayer = $Sprite2D/AnimationPlayer

var is_moving = false
var current_move_direction: Vector2 = Vector2.ZERO

func _physics_process(delta: float) -> void:
    if is_moving:
        if sprite_2d.global_position.distance_to(global_position) < 0.1:
            sprite_2d.global_position = global_position
            is_moving = false
            if current_move_direction != Vector2.ZERO:
                try_continue_move(current_move_direction)
        else:
            sprite_2d.global_position = sprite_2d.global_position.move_toward(global_position, move_speed * delta)
    else:
        if current_move_direction != Vector2.ZERO:
            try_continue_move(current_move_direction)

func _ready() -> void:
    animation_player.play("chomping")

func _process(delta: float) -> void:
    current_move_direction = Vector2.ZERO
    if Input.is_action_pressed("up"):
        current_move_direction = Vector2.UP
        rotation_degrees = 90
    elif Input.is_action_pressed("down"):
        current_move_direction = Vector2.DOWN
        rotation_degrees = 270
    elif Input.is_action_pressed("left"):
        current_move_direction = Vector2.LEFT
        rotation_degrees = 0
    elif Input.is_action_pressed("right"):
        current_move_direction = Vector2.RIGHT
        rotation_degrees = 180

func try_continue_move(direction: Vector2):
    var current_tile: Vector2i = tile_map.local_to_map(sprite_2d.global_position)
    var target_tile: Vector2i = current_tile + direction
    var tile_data: TileData = tile_map.get_cell_tile_data(0, target_tile)
    if tile_data != null and tile_data.get_custom_data("walk_tiles") == true:
        is_moving = true
        global_position = tile_map.map_to_local(target_tile)

关键说明

  • 用distance_to替代直接相等判断,避免浮点精度导致的移动停止异常。
  • 移动速度乘以delta,保证在不同帧率下移动速度一致。
  • 持续记录方向键状态,角色到达瓷砖后自动触发下一次移动检查,实现按住方向键持续移动的效果。
  • 松开方向键时,current_move_direction重置为ZERO,角色到达当前瓷砖后自动停止。

内容的提问来源于stack exchange,提问作者SPONGEBOB RED YT channel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 04:02:31