Godot街机角色三档地面状态跳跃及空中无输入运动实现问题
解决方案(Godot 3.x/4.x通用思路)
1. 修复跳跃时立即停下的问题:保留地面水平速度
你当前的核心问题是触发跳跃时重置了水平速度。要让角色带着地面速度起跳,只需在跳跃前记录当前水平速度,空中阶段保持该速度即可(符合“落地前保持运动状态”的需求)。
示例代码(以CharacterBody2D/KinematicBody2D为例):
# 定义核心变量 var is_on_floor: bool = false var current_horizontal_velocity: float = 0.0 var jump_impulse: float = -400.0 # 向上为负方向,可根据你的游戏调整 func _physics_process(delta: float): is_on_floor = is_on_floor() if is_on_floor: # 地面运动逻辑(你的已有代码) handle_ground_movement(delta) # 记录当前地面水平速度,用于起跳时继承 current_horizontal_velocity = velocity.x else: # 空中锁定水平输入,严格保持起跳前的速度 velocity.x = current_horizontal_velocity # 仅在地面响应跳跃输入 if is_on_floor and Input.is_action_just_pressed("jump"): velocity.y = jump_impulse # 不要在这里重置velocity.x!
2. 实现三种跳跃类型并区分地面速度
根据需求,三种跳跃的核心差异在于水平速度继承规则和垂直冲量大小,以下提供两种实现方案:
方案A:绑定独立输入(适合明确的三档跳跃触发)
给直上、小弧度、大弧度跳跃分别绑定不同的输入键(如jump_up/jump_small/jump_big):
# 定义三种跳跃参数 var jump_up_impulse: float = -350.0 var jump_small_impulse: float = -400.0 var jump_big_impulse: float = -500.0 var walk_speed: float = 150.0 var run_speed: float = 300.0 var direction: float = 0.0 func _physics_process(delta: float): direction = Input.get_axis("move_left", "move_right") is_on_floor = is_on_floor() if is_on_floor: handle_ground_movement(delta) current_horizontal_velocity = velocity.x # 直上跳跃:清零水平速度,垂直冲量最小 if Input.is_action_just_pressed("jump_up"): velocity.x = 0.0 velocity.y = jump_up_impulse current_horizontal_velocity = 0.0 # 小弧度跳跃:继承行走速度,垂直冲量中等 elif Input.is_action_just_pressed("jump_small"): velocity.x = walk_speed * direction velocity.y = jump_small_impulse current_horizontal_velocity = velocity.x # 大弧度跳跃:继承奔跑速度,垂直冲量最大 elif Input.is_action_just_pressed("jump_big"): velocity.x = run_speed * direction velocity.y = jump_big_impulse current_horizontal_velocity = velocity.x else: velocity.x = current_horizontal_velocity
方案B:长按充电区分(复古游戏常用逻辑)
通过按住跳跃键的时长触发不同跳跃类型,更符合复古游戏操作习惯:
var jump_charge_timer: float = 0.0 var is_charging_jump: bool = false var is_running: bool = false # 需在地面运动逻辑中更新 func _physics_process(delta: float): is_on_floor = is_on_floor() if is_on_floor: handle_ground_movement(delta) current_horizontal_velocity = velocity.x # 跳跃充电逻辑 if Input.is_action_pressed("jump"): is_charging_jump = true jump_charge_timer += delta jump_charge_timer = min(jump_charge_timer, 0.5) # 限制最大充电时长 elif Input.is_action_just_released("jump") and is_charging_jump: is_charging_jump = false # 根据充电时长切换跳跃类型 match true: jump_charge_timer < 0.1: # 直上跳跃 velocity.x = 0.0 velocity.y = -350.0 current_horizontal_velocity = 0.0 jump_charge_timer < 0.3: # 小弧度跳跃:继承当前地面速度 velocity.y = -400.0 current_horizontal_velocity = velocity.x jump_charge_timer >= 0.3: # 大弧度跳跃:强制使用奔跑速度+最大垂直冲量 velocity.x = run_speed * direction velocity.y = -500.0 current_horizontal_velocity = velocity.x jump_charge_timer = 0.0 else: velocity.x = current_horizontal_velocity
3. 行走转奔跑逻辑补全(细节优化)
针对“行走状态持续1秒后立即切换为奔跑”的需求,需注意仅在持续行走时计时,停下时重置计时器:
var walk_duration_timer: float = 0.0 var is_walking: bool = false func handle_ground_movement(delta: float): direction = Input.get_axis("move_left", "move_right") if direction != 0: is_walking = true walk_duration_timer += delta # 行走满1秒切换奔跑 if walk_duration_timer >= 1.0: is_running = true velocity.x = run_speed * direction else: is_running = false velocity.x = walk_speed * direction else: is_walking = false is_running = false walk_duration_timer = 0.0 velocity.x = 0.0
关键注意事项
- 所有运动逻辑必须放在
_physics_process中,避免物理帧和渲染帧不同步导致的抖动。 - 确保
current_horizontal_velocity在每次落地时更新,保证每次跳跃都继承最新的地面速度状态。 - Godot 4和3.x的核心逻辑一致,仅节点名称(如
CharacterBody2D替代KinematicBody2D)和部分方法细节有差异,可根据版本微调。
内容的提问来源于stack exchange,提问作者Ignis2401




