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

Godot中KinematicBody2D站在RigidBody上无法跳跃的问题求助

问题原因分析
  1. Push函数调用时机错误:当前代码在move_and_slide()之前调用Push(),但get_slide_count()仅在move_and_slide()执行后才会返回有效碰撞次数,这会导致碰撞逻辑异常,包括站在刚体上时的地面检测失效。
  2. 站在刚体上时地面检测失效:即使infinite_inertia设为false,KinematicBody2D的is_on_floor()可能无法正确识别动态RigidBody为地面,或者因对刚体施加向下冲量导致刚体下沉,玩家失去地面接触。
解决方案

步骤1:修正Push函数调用时机

将Push()移到move_and_slide()之后,确保能获取到当前帧的碰撞数据:

func _physics_process(delta) -> void:
    # 处理输入、动画、跳跃逻辑
    if Input.is_action_pressed("right"):
        $Sprite.flip_h=false
        velocity.x += speed
        animation.play("Walk")
    elif Input.is_action_pressed("left"):
        $Sprite.flip_h=true
        velocity.x -= speed
        animation.play("Walk")
    else:
        animation.play("Idle")
    
    if Input.is_action_just_pressed("jump") and is_on_floor():
        velocity.y =- jumpforce
        animation.play("Idle")
    
    velocity.y += gravity
    velocity=move_and_slide(velocity,Vector2.UP, false, 4, PI/4, false)
    velocity.x= lerp(velocity.x,0,0.2)
    
    # 移动后再处理碰撞推动逻辑
    Push()

步骤2:优化地面检测(针对RigidBody)

如果调整调用时机后仍无法跳跃,需要手动检测是否站在RigidBody上,补充is_on_floor()的判断:

func is_on_valid_floor() -> bool:
    # 先调用原生的is_on_floor()
    if is_on_floor():
        return true
    # 手动检测是否与RigidBody发生地面方向的碰撞
    for index in get_slide_count():
        var collision = get_slide_collision(index)
        # 检查碰撞对象是否是RigidBody,且碰撞法线接近向上(角度小于45度)
        if collision.collider is RigidBody2D and collision.normal.angle_to(Vector2.UP) < PI/4:
            return true
    return false

然后将跳跃逻辑中的is_on_floor()替换为is_on_valid_floor():

if Input.is_action_just_pressed("jump") and is_on_valid_floor():
    velocity.y =- jumpforce
    animation.play("Idle")

步骤3:优化刚体推动逻辑(避免向下冲量导致下沉)

当玩家站在刚体上时,碰撞法线是向上的,此时施加向下的冲量会让刚体下沉,导致玩家失去地面接触。修改Push函数,只在水平方向碰撞时施加冲量:

func Push():
    for index in get_slide_count():
        var collision = get_slide_collision(index)
        if collision.collider.is_in_group("bodies"):
            # 只提取水平方向的法线分量,避免对垂直方向的碰撞施加冲量
            var horizontal_normal = Vector2(collision.normal.x, 0).normalized()
            if horizontal_normal.length_squared() > 0:
                collision.collider.apply_central_impulse(-horizontal_normal * push)
完整修正后代码
extends KinematicBody2D

onready var animation = $AnimationPlayer
export (int, 0, 200) var push = 30
var velocity :=Vector2.ZERO
var gravity := 30
var speed := 50
var jumpforce = 300

func _physics_process(delta) -> void:
    if Input.is_action_pressed("right"):
        $Sprite.flip_h=false
        velocity.x += speed
        animation.play("Walk")
    elif Input.is_action_pressed("left"):
        $Sprite.flip_h=true
        velocity.x -= speed
        animation.play("Walk")
    else:
        animation.play("Idle")
    
    if Input.is_action_just_pressed("jump") and is_on_valid_floor():
        velocity.y =- jumpforce
        animation.play("Idle")
    
    velocity.y += gravity
    velocity=move_and_slide(velocity,Vector2.UP, false, 4, PI/4, false)
    velocity.x= lerp(velocity.x,0,0.2)
    
    Push()

func Push():
    for index in get_slide_count():
        var collision = get_slide_collision(index)
        if collision.collider.is_in_group("bodies"):
            var horizontal_normal = Vector2(collision.normal.x, 0).normalized()
            if horizontal_normal.length_squared() > 0:
                collision.collider.apply_central_impulse(-horizontal_normal * push)

func is_on_valid_floor() -> bool:
    if is_on_floor():
        return true
    for index in get_slide_count():
        var collision = get_slide_collision(index)
        if collision.collider is RigidBody2D and collision.normal.angle_to(Vector2.UP) < PI/4:
            return true
    return false

内容的提问来源于stack exchange,提问作者nicktehboy meny

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 16:16:06