Godot 4.2.2:2D玩家角色无法识别地面接触问题求助
排查Godot 4.2.2中CharacterBody2D的is_on_floor()检测失效问题
你遇到的is_on_floor()始终返回false的问题,核心是代码违反了CharacterBody2D的物理移动规范,加上语法和逻辑错误导致的,具体问题和修复方案如下:
原代码问题分析
extends CharacterBody2D var dash = 300.0 var speed = 150.0 var jumpPower = -350.0 var jumpMax = 2 var jumpCount = 0 func _process(delta): moviment(delta) attack() print(is_on_floor()) move_and_slide() var gravity = ProjectSettings.get_setting("physics/2d/default_gravity") func _physics_process(delta): move_and_collide(Vector2(0, 1)) velocity.y += gravity * delta var motion = velocity * delta move_and_collide(motion) func moviment(delta) var direction = Input.get_action_strength("move_right") - Input.get_action_strength("move_left") if direction != 0: $Anim.play("Walk") if direction > 0: $Anim.flip_h = false velocity.x += speed * delta velocity.x = clamp(speed, 100.0, speed) elif direction < 0: $Anim.flip_h = true velocity.x -= speed * delta velocity.x = clamp(-speed, 100.0, -speed) else: velocity.x = 0 $Anim.play("Idle") jump() func jump(): if is_on_floor() and jumpCount != 0: jumpCount = 0 if jumpCount<jumpMax: if Input.is_action_just_pressed("move_up"): jumpCount += 1 $Anim.play("Jump") velocity.y = jumpPower
关键问题点
- 物理与帧逻辑混用:CharacterBody2D的移动、物理相关逻辑必须放在
_physics_process中,你在_process(帧更新)里调用move_and_slide,同时在_physics_process里调用move_and_collide,两种移动方法混用会彻底打乱物理状态,is_on_floor()完全依赖move_and_slide的碰撞结果,这样调用根本无法正确检测地面。 - 错误使用
move_and_collide:CharacterBody2D的标准移动方式是修改velocity后调用move_and_slide(),move_and_collide不会更新is_on_floor()所需的碰撞状态。 - 语法与缩进错误:
moviment(delta)函数定义缺少冒号,多处代码缩进错误(比如if direction !=0:的代码块未正确缩进),导致逻辑执行顺序混乱。 - 速度计算逻辑错误:
clamp(speed, 100.0, speed)写法无效,clamp参数顺序为clamp(值, 最小值, 最大值),应该直接用方向乘以速度控制水平移动。
修复后的代码
extends CharacterBody2D var dash = 300.0 var speed = 150.0 var jumpPower = -350.0 var jumpMax = 2 var jumpCount = 0 var gravity = ProjectSettings.get_setting("physics/2d/default_gravity") func _physics_process(delta): # 处理重力 velocity.y += gravity * delta # 处理移动和跳跃 moviment(delta) jump() # 执行移动,这一步会更新is_on_floor的状态 move_and_slide() # 打印检测结果 print(is_on_floor()) func moviment(delta): var direction = Input.get_action_strength("move_right") - Input.get_action_strength("move_left") if direction != 0: $Anim.play("Walk") # 直接用方向乘以速度设置水平速度 velocity.x = direction * speed $Anim.flip_h = direction < 0 else: velocity.x = 0 $Anim.play("Idle") func jump(): # 接触地面时重置跳跃次数 if is_on_floor(): jumpCount = 0 # 处理跳跃输入 if jumpCount < jumpMax and Input.is_action_just_pressed("move_up"): jumpCount += 1 $Anim.play("Jump") velocity.y = jumpPower
额外注意事项
- 确保角色和地面都添加了CollisionShape2D或CollisionPolygon2D,且碰撞层与掩码设置正确(角色和地面的碰撞层需能互相检测)。
jumpPower设为负数是正确的(Godot 2D中y轴向下为正),若场景坐标系有修改,需对应调整。
内容的提问来源于stack exchange,提问作者TomicMaster
相关产品推荐
相关产品推荐

