Godot 4.6.2中Koopa从壳状态恢复后速度异常问题
Koopa从壳状态恢复后无法移动的问题分析
问题描述
使用Godot 4.6.2重制原版《超级马里奥兄弟》时,踩击Koopa使其进入壳状态后,10秒后恢复正常状态,但Koopa无法移动,速度始终为0。
Koopa节点树
Koopa ├╴AnimatedSprite2D ├╴CollisionShape2D ├╴SmushedArea │ └╴SmushedCollision ├╴KillerArea │ └╴KillerCollision └╴ShelledTimer
核心代码
extends CharacterBody2D # editables @export var max_speed := 1600.0 @export_enum('Alive', 'Shelled', 'Dead') var state := 'Alive' @onready var prev_state := state @onready var direction := max_speed # inner nodes @onready var sprite := $AnimatedSprite2D @onready var collider := $CollisionShape2D @onready var smushed := $SmushedArea @onready var killer := $KillerArea @onready var shelled_timer := $ShelledTimer # player @onready var player := $'..'/Player @onready var smusher := $'..'/Player/SmusherArea @onready var killed := $'..'/Player/KilledArea @onready var camera := $'..'/Camera2D func _physics_process(delta: float) -> void: if not is_on_floor(): velocity += get_gravity() * delta if is_on_wall(): direction *= -1 velocity.x = direction * delta move_and_slide() func _process(delta: float) -> void: if velocity.x != 0: if abs(velocity.x) != velocity.x: sprite.flip_h = true if abs(velocity.x) == velocity.x: sprite.flip_h = false print(velocity.x) if state != prev_state: if state == 'Alive': killer.set_deferred('monitoring', true) smushed.set_deferred('monitoring', true) velocity.x = direction * delta sprite.play('walk') elif state == 'Shell': direction = 0 killer.set_deferred('monitoring', false) smushed.set_deferred('monitoring', false) player.velocity.y *= -0.7 velocity.y = -100 velocity.x = 0 sprite.play('shell') shelled_timer.start() if state == 'Shell' and shelled_timer.time_left < 3: sprite.play("wiggling") prev_state = state func _on_smushed_area_entered(area: Area2D) -> void: if area == smusher and\ (abs(player.velocity.y) == player.velocity.y) and player.velocity.y != 0: state = 'Shell' func _on_killer_area_entered(area: Area2D) -> void: if area == killed and player.is_alive: camera.follow_player = false player.is_alive = false await get_tree().create_timer(0.5).timeout player.collider.set_deferred('disabled', true) player.killed.set_deferred('monitoring', false) player.smusher.set_deferred('monitorable', false) player.velocity.y = player.jump_height await get_tree().create_timer(2.0).timeout player.queue_free() func _on_shelled_timer_timeout() -> void: state = 'Alive'
问题原因
核心问题是进入壳状态时将direction设为0,但恢复Alive状态时未重置direction的数值:
- 当Koopa被踩击进入
Shell状态时,代码中执行了direction = 0,直接将控制移动的方向速度值清零。 - 10秒后计时器触发
_on_shelled_timer_timeout()将状态设回Alive,此时_process函数的Alive分支仅尝试设置velocity.x = direction * delta,但direction仍为0,导致velocity.x始终为0,Koopa自然无法移动。
修复方案
方案1:恢复Alive状态时重置direction为初始速度
修改_process函数中state == 'Alive'的分支,添加direction重置逻辑:
if state == 'Alive': killer.set_deferred('monitoring', true) smushed.set_deferred('monitoring', true) # 重置direction为初始max_speed direction = max_speed velocity.x = direction sprite.play('walk')
方案2:保存进入壳前的方向,恢复时复用
- 先添加变量保存原始方向:
# 在变量定义区域添加 var original_direction := max_speed
- 修改
Shell状态分支,保存当前方向:
elif state == 'Shell': original_direction = direction # 保存进入壳前的移动方向 direction = 0 killer.set_deferred('monitoring', false) smushed.set_deferred('monitoring', false) player.velocity.y *= -0.7 velocity.y = -100 velocity.x = 0 sprite.play('shell') shelled_timer.start()
- 修改
Alive状态分支,恢复之前的方向:
if state == 'Alive': killer.set_deferred('monitoring', true) smushed.set_deferred('monitoring', true) direction = original_direction # 恢复进入壳前的方向 velocity.x = direction sprite.play('walk')
额外优化提示
_physics_process中的velocity.x = direction * delta存在逻辑错误:CharacterBody2D的velocity是每秒移动的像素数,不需要乘以delta(delta是帧间隔时间),否则移动速度会随帧率波动。正确写法应为:
velocity.x = direction
内容的提问来源于stack exchange,提问作者Mohammed H.
相关产品推荐
相关产品推荐

