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

2D史莱姆敌人跳跃异常:首次正常后续反向跳转问题求助

史莱姆2D敌方单位跳跃方向异常问题排查与修复

问题描述

  • 首次跳跃符合预期,朝向玩家方向;
  • 后续跳跃会莫名朝向与玩家位置相反的方向。

首次跳转正常,第二次跳转方向错误的NPC演示

跳跃代码片段

if is_on_floor():
        var player_pos = get_node("../Player").get_global_position()
        var self_pos = get_global_position()        
        var jump_distance = (player_pos - self_pos).normalized()
        var distance_to_player = player_pos.distance_to(self_pos)
        
        var horizontal_speed = min_speed + (distance_to_player / max_distance) * (max_speed - min_speed)
        horizontal_speed = min(max_speed, max(min_speed, horizontal_speed))
        
        velocity = jump_distance 
        velocity.x *= horizontal_speed * direction
        velocity.y = -jumpmove_height #-jump_height
    
        velocity = move_and_slide(velocity, Vector2.UP)
        
        $Position2D/SlimeSkin/AnimationPlayer.play("SlimePrototype Attack")
        $Jump_Cooldown.start()
    print("Do Jump")

完整代码

extends KinematicBody2D
var speed = 20

var min_speed = 0 #min_speed for jump horizontal speed
var max_speed = 250 #max_speed for jump horizontal speed
var max_distance = 300 #max distance for jump distance

var direction = 1

export var jumpmove_height : float
export var jump_time_to_peak : float
export var jump_time_to_descent : float

onready var jump_velocity : float = ((2.0 * jumpmove_height) / jump_time_to_peak) * -1.0
onready var jump_gravity : float = ((-2.0 * jumpmove_height) / (jump_time_to_peak * jump_time_to_peak)) * -1.0
onready var fall_gravity : float = ((-2.0 * jumpmove_height) / (jump_time_to_descent * jump_time_to_descent)) * -1.0

var velocity = Vector2.ZERO
var is_idle = true

func _ready():
    is_idle = true
    $Idle_Timer.start()
    pass

func get_gravity() -> float:
    return jump_gravity if velocity.y < 0.0 else fall_gravity

func _physics_process(delta):
    if velocity.x>0:
        $Position2D.scale.x=1
    elif velocity.x<0:
        $Position2D.scale.x=-1
    
    if is_on_wall() or not $Position2D/FloorRay.is_colliding() and is_on_floor():
        direction = direction * -1
    
    velocity.y += get_gravity() * delta
    if is_on_floor():
        velocity.x = 0
    velocity = move_and_slide(velocity, Vector2.UP)

    if is_idle:
        velocity.x = speed * direction
        if is_on_wall() or not $Position2D/FloorRay.is_colliding() and is_on_floor():
            direction = direction * -1
        velocity = move_and_slide(velocity, Vector2.UP)
        $Position2D/SlimeSkin/AnimationPlayer.play("SlimePrototype Idle")

func _on_Timer_timeout():
    if is_on_floor():
        var player_pos = get_node("../Player").get_global_position()
        var self_pos = get_global_position()        
        var jump_distance = (player_pos - self_pos).normalized()
        var distance_to_player = player_pos.distance_to(self_pos)
        
        var horizontal_speed = min_speed + (distance_to_player / max_distance) * (max_speed - min_speed)
        horizontal_speed = min(max_speed, max(min_speed, horizontal_speed))
        
        velocity = jump_distance 
        velocity.x *= horizontal_speed * direction
        velocity.y = -jumpmove_height #-jump_height
    
        velocity = move_and_slide(velocity, Vector2.UP)
        
        $Position2D/SlimeSkin/AnimationPlayer.play("SlimePrototype Attack")
        $Jump_Cooldown.start()
    print("Do Jump")

func _on_Idle_Timer_timeout():
    is_idle = false
    $Timer.start()
    $Position2D/SlimeSkin/AnimationPlayer.play("SlimePrototype Charge")
    print("IDLE TIMER TIMEOUT")
    pass # Replace with function body.

func _on_Jump_Cooldown_timeout():
    yield(get_tree().create_timer(0.5), "timeout")
    is_idle = true
    pass # Replace with function body.

问题原因

核心问题是**direction变量的错误复用**:

  1. direction原本是idle状态下史莱姆左右移动的转向标记,会在碰撞墙体或地板缺失时自动翻转;
  2. 跳跃逻辑中,jump_distance.x已经通过player_pos - self_pos计算出了朝向玩家的正确水平方向(正数为右,负数为左),但代码额外乘以了direction,导致首次跳跃后direction被翻转时,后续跳跃的水平方向被反向。

修复方案

直接修复方向计算

修改_on_Timer_timeout中的速度赋值代码,移除direction对水平速度的影响:

# 原代码
velocity.x *= horizontal_speed * direction
# 修改为
velocity.x *= horizontal_speed

可选优化:统一朝向控制

为避免direction变量混淆,跳跃时直接根据玩家位置设置 sprite 缩放,替代依赖velocity.x的判断:
在跳跃逻辑中添加:

# 在velocity赋值后添加
if jump_distance.x > 0:
    $Position2D.scale.x = 1
else:
    $Position2D.scale.x = -1

这样可以确保跳跃时的朝向完全由玩家位置决定,不受idle状态下direction变化的干扰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 11:23:10