limbo hsm
This commit is contained in:
@@ -4,43 +4,41 @@ extends Node
|
||||
##
|
||||
## 只算速度写回 body.velocity,**不调 move_and_slide()** —— 推进由 Player 统一做。
|
||||
## 这样「算速度 → 推进 → 播动画」的顺序永远固定,不受节点树顺序影响。
|
||||
##
|
||||
## 「走多快、蹲不蹲、跑不跑」由 hsm/ 的 LimboHSM(LimboAI)决定:
|
||||
## 状态在 _enter 时写 target_speed / crouching / sprinting,
|
||||
## 本组件只负责把这份「意图」用物理方式变成速度。
|
||||
##
|
||||
## 设计基准:**小人国玩法,角色身高约 0.2 m**。速度不按「人类等比缩放」推导,
|
||||
## 直接按鼠类疾走的手感定标:走 ≈ 12 身长/秒、疾跑 ≈ 18 身长/秒、
|
||||
## 跳高 ≈ 1.15 身高。速度/加速度按手感单独调即可,不必成套换算;
|
||||
## 唯独 jump_velocity 与 gravity_scale 是**配对**的(反解公式见重力一节)。
|
||||
|
||||
## 跳跃输入缓冲(秒):按下跳跃后这段时间内若落地,自动补上一次起跳
|
||||
const JUMP_BUFFER_TIME: float = 0.1
|
||||
|
||||
@export_group("移动")
|
||||
## 【设计基准】以人类为参照做等比缩放:人 1.75 m,游戏惯例 walk 5.0 / sprint 8.5 m/s。
|
||||
## 本角色身高 0.15 m,系数 k = 0.15 / 1.75 ≈ 0.0857,下面所有线性量都是原值 × k。
|
||||
## 这样「每秒走过几个自身体长」和人类一致,动作比例看起来才对。
|
||||
##
|
||||
## 换尺寸时的公式:线性量(速度/加速度)× k';跳跃那两个数(gravity_scale 与 jump_velocity)用下面的反解公式重算。
|
||||
##
|
||||
## 常规移动速度(米/秒)—— 约 2.9 身长/秒,和人类走路同一比例
|
||||
@export var walk_speed: float = 0.4286
|
||||
## 疾跑速度(米/秒)—— 约 4.9 身长/秒
|
||||
@export var sprint_speed: float = 0.7286
|
||||
## 蹲行速度(米/秒)—— 默认是走速的一半。蹲下时按住 Shift 也不会疾跑。
|
||||
## 注意:改这个值要同步改 player_animator.gd 的 sneak_ref_speed,否则蹲走时脚步会打滑。
|
||||
@export var crouch_speed: float = 0.2143
|
||||
## 地面加速度(米/秒²)—— 约 0.11 秒加到全速,起步干脆
|
||||
@export var acceleration: float = 3.8571
|
||||
## 空中加速度(米/秒²)
|
||||
@export var air_acceleration: float = 1.0286
|
||||
## 起跳初速度(米/秒)—— 配下面的 gravity_scale 0.5(g = 4.9)时,
|
||||
## 跳跃高度 ≈ 0.230 m(约 1.53 身高)、滞空 ≈ 0.61 s。
|
||||
## 这两个数是**配对**的:改重力必须按「反解公式」重算它,否则跳跃高度按 1/g 暴涨。
|
||||
## 常规移动速度(米/秒)—— ≈ 12 身长/秒(0.2 m 身高),小鼠疾走的步频感
|
||||
@export var walk_speed: float = 2.419
|
||||
## 疾跑速度(米/秒)—— ≈ 18 身长/秒
|
||||
@export var sprint_speed: float = 3.624
|
||||
## 蹲行速度(米/秒)—— 走速的一半。蹲下时按住 Shift 也不疾跑(蹲伏优先)。
|
||||
@export var crouch_speed: float = 1.21
|
||||
## 地面加速度(米/秒²)—— 约 0.11 秒加到走速全速,起步干脆(鼠类的一窜一动)
|
||||
@export var acceleration: float = 22.0
|
||||
## 空中加速度(米/秒²)—— 约地面的 1/4:空中能修正方向,但不至于完全失控
|
||||
@export var air_acceleration: float = 5.9
|
||||
## 起跳初速度(米/秒)—— 配 gravity_scale 0.5(有效 g = 4.9)时,
|
||||
## 跳高 ≈ 0.23 m(约 1.15 身高)、滞空 ≈ 0.61 s。**与 gravity_scale 配对**,见下。
|
||||
@export var jump_velocity: float = 1.5
|
||||
|
||||
@export_group("重力")
|
||||
## 重力缩放系数。0.5 = 重力减半(有效 g = 4.9 m/s²)。
|
||||
## 重力缩放系数。0.5 = 有效重力 4.9 m/s²。
|
||||
##
|
||||
## 为什么不用 1.0(物理真实的 9.8):重力加速度本身和物体大小无关,但我们的速度是按身材
|
||||
## 等比缩过的,于是落体相对过快。更关键的是跳跃 —— 由 h = v²/2g 和 T = 2v/g 可得
|
||||
## h = g·T²/8:**固定重力下滞空翻倍、高度要涨 4 倍**。所以「想跳得久又不想跳太高」
|
||||
## 只能降重力。取 0.5 时:跳高 0.230 m(1.53 身高)、滞空 0.61 s;
|
||||
## 若维持 1.0,同样 0.23 m 的高度只有 0.43 s 滞空,落地明显仓促。
|
||||
## 小个子角色若用真实 9.8,同样的起跳速度滞空短一半、跳起来像被拍回去 ——
|
||||
## 降重力换滞空,跳跃才有「腾空感」。0.5 时:跳高 0.23 m、滞空 0.61 s。
|
||||
##
|
||||
## ⚠ 改这个值必须同步改 jump_velocity(跳跃高度 = v²/2g)。
|
||||
## ⚠ 与 jump_velocity **配对**:改一个必须按反解公式重算另一个(跳跃高度 = v²/2g)。
|
||||
## 反解公式 —— 定目标高度 h(米)与滞空 T(秒):
|
||||
## g = 8h / T² → gravity_scale = g / 9.8
|
||||
## jump_velocity = 4h / T
|
||||
@@ -49,8 +47,12 @@ const JUMP_BUFFER_TIME: float = 0.1
|
||||
## 那是全局的,会连带把拖拽/投掷的刚体一起变飘。
|
||||
@export_range(0.0, 2.0, 0.01) var gravity_scale: float = 0.5
|
||||
|
||||
## 本帧是否在疾跑 / 是否按住蹲键。
|
||||
## Player 读这两个值转交给 PlayerAnimator 切片段,crouching 还用来压低摄像机。
|
||||
## 当前目标水平速度(米/秒)—— 由 HSM 状态在 _enter 时写入,step() 朝它加减速。
|
||||
## Idle / Crouch 写 0(自然减速到停),Walk / Sprint / Sneak 写各自速度。
|
||||
var target_speed: float = 0.0
|
||||
|
||||
## 是否蹲着 / 是否疾跑 —— 由 HSM 状态写入的**事实镜像**,本组件不再自己读输入推断:
|
||||
## crouching 给 Look 压低摄像机,两者都给 DebugPanel 显示。
|
||||
var sprinting: bool = false
|
||||
var crouching: bool = false
|
||||
|
||||
@@ -73,6 +75,23 @@ func _unhandled_input(event: InputEvent) -> void:
|
||||
_jump_buffer = JUMP_BUFFER_TIME
|
||||
|
||||
|
||||
## 本帧是否按着方向键。HSM 状态(Idle/Walk 等的转换判定)与 step() 共用这个口径。
|
||||
func has_move_input() -> bool:
|
||||
return Input.get_vector("move_left", "move_right", "move_back", "move_forward") \
|
||||
.length_squared() > 0.000001
|
||||
|
||||
|
||||
## 由 HSM 地面状态每帧调用:跳跃缓冲还有效且脚下有地板,就当场起跳并返回 true。
|
||||
## 起跳「动作」放在状态判定处执行(而不是 step() 里),
|
||||
## 状态机同一帧就能拿到 vy > 0 这个事实、转进 Jump,动画不迟到一帧。
|
||||
func try_jump() -> bool:
|
||||
if _jump_buffer > 0.0 and _body != null and _body.is_on_floor():
|
||||
_body.velocity.y = jump_velocity
|
||||
_jump_buffer = 0.0
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
## 每物理帧由 Player 调用一次,必须排在 move_and_slide() 之前。
|
||||
## 只写 _body.velocity,不做位移推进。
|
||||
func step(delta: float) -> void:
|
||||
@@ -87,12 +106,9 @@ func step(delta: float) -> void:
|
||||
# gravity_scale 每帧现读,方便运行中拖着试手感(1.0 = 物理真实的 9.8)
|
||||
_body.velocity.y -= _gravity * gravity_scale * delta
|
||||
|
||||
# --- 跳跃(读取输入缓冲)---
|
||||
# --- 跳跃缓冲倒计时(执行挪到 try_jump(),由 HSM 地面状态调用)---
|
||||
if _jump_buffer > 0.0:
|
||||
_jump_buffer -= delta
|
||||
if _body.is_on_floor():
|
||||
_body.velocity.y = jump_velocity
|
||||
_jump_buffer = 0.0
|
||||
|
||||
# --- 相对视线方向的水平输入 ---
|
||||
# 只用 rig 的 basis(只有 yaw),低头看地时前进方向不会跟着往下扎。
|
||||
@@ -103,16 +119,7 @@ func step(delta: float) -> void:
|
||||
if wish.length_squared() > 0.000001:
|
||||
wish = wish.normalized()
|
||||
|
||||
# 只有真正按了方向键才允许疾跑(避免原地"疾跑"触发跑动动画)
|
||||
var wants_sprint := Input.is_action_pressed("sprint") and input_dir.length_squared() > 0.000001
|
||||
crouching = Input.is_action_pressed("crouch")
|
||||
# 蹲伏优先于疾跑:蹲着时按住 Shift 不算疾跑,速度取蹲行速度。
|
||||
sprinting = wants_sprint and not crouching
|
||||
var target_speed := walk_speed
|
||||
if crouching:
|
||||
target_speed = crouch_speed
|
||||
elif sprinting:
|
||||
target_speed = sprint_speed
|
||||
# 目标速度来自 HSM 状态(target_speed),不在本组件里按蹲键/Shift 分档。
|
||||
var accel := acceleration if _body.is_on_floor() else air_acceleration
|
||||
|
||||
var horizontal := Vector2(_body.velocity.x, _body.velocity.z)
|
||||
|
||||
Reference in New Issue
Block a user