limbo hsm
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
extends LimboHSM
|
||||
## 空中子机(挂在 HSM/Airborne 上)。
|
||||
##
|
||||
## Jump(上升段)→ Fall(越过顶点开始下落)。进入时按当前竖直速度挑初始子状态:
|
||||
## 起跳进来 vy > 0 → Jump;踏空掉进来 vy ≈ 0 → Fall(vy ≤ 0 一律算 Fall)。
|
||||
|
||||
@onready var jump: LimboState = $Jump
|
||||
@onready var fall: LimboState = $Fall
|
||||
|
||||
|
||||
func _setup() -> void:
|
||||
add_transition(jump, fall, &"falling")
|
||||
|
||||
|
||||
func _enter() -> void:
|
||||
var player := get_agent() as Player
|
||||
set_initial_state(fall if player == null or player.velocity.y <= 0.0 else jump)
|
||||
@@ -0,0 +1 @@
|
||||
uid://43psuo6pb4wq
|
||||
@@ -0,0 +1,18 @@
|
||||
extends PlayerGroundState
|
||||
## 原地蹲:目标速度 0,播 crouch(蹲着不动)。
|
||||
## 蹲着走是 Sneak —— 两者只差「有没有方向输入」,转换事件同为 move_start/stop。
|
||||
|
||||
func _enter() -> void:
|
||||
var player := get_agent() as Player
|
||||
player.motor.target_speed = 0.0
|
||||
player.motor.sprinting = false
|
||||
player.motor.crouching = true
|
||||
player.animation_player.play_state(PlayerAnimator.AnimState.CROUCH)
|
||||
|
||||
|
||||
func _think(_delta: float) -> void:
|
||||
var player := get_agent() as Player
|
||||
if not Input.is_action_pressed("crouch"):
|
||||
dispatch(&"crouch_end")
|
||||
elif player.motor.has_move_input():
|
||||
dispatch(&"move_start")
|
||||
@@ -0,0 +1 @@
|
||||
uid://bb8dvx7nwuiwo
|
||||
@@ -0,0 +1,14 @@
|
||||
extends LimboState
|
||||
## 下落段:播 fall。落地(is_on_floor 且不再上升)转回地面,由 Grounded._enter
|
||||
## 按当下输入挑子状态(走/跑/蹲着落地不会闪站立)。
|
||||
|
||||
func _enter() -> void:
|
||||
(get_agent() as Player).animation_player.play_state(PlayerAnimator.AnimState.FALL)
|
||||
|
||||
|
||||
func _update(_delta: float) -> void:
|
||||
var player := get_agent() as Player
|
||||
if player == null:
|
||||
return
|
||||
if player.is_on_floor() and player.velocity.y <= 0.0:
|
||||
dispatch(&"landed")
|
||||
@@ -0,0 +1 @@
|
||||
uid://yadts2ydgfs6
|
||||
@@ -0,0 +1,32 @@
|
||||
class_name PlayerGroundState
|
||||
extends LimboState
|
||||
## 地面叶子状态的公共基类(Idle / Walk / Sprint / Crouch / Sneak 共用)。
|
||||
##
|
||||
## 每帧先统一判定「环境事实」,之后才轮到 _think() 里各状态自己的输入转换:
|
||||
## 1. 跳跃缓冲成立(try_jump 当场起跳)→ 转空中(vy > 0 → Jump);
|
||||
## 2. 脚下没地板(踏空)→ 转空中(Fall)。
|
||||
## 这两层判定放在**叶子**而不是父机:父机 _update 先于子状态执行,
|
||||
## 若在父机里 dispatch,转换后父机本轮还会继续调(已被退出的)旧子状态,
|
||||
## 存在「旧状态在已退出的机器里再次 dispatch」的顺序陷阱;叶子自己判、
|
||||
## dispatch 后立即 return,则没有这个窗口。
|
||||
##
|
||||
## is_on_floor() 反映的是上一帧 move_and_slide() 的结果 ——
|
||||
## 与推进的更新节奏一致,不引入额外的检测延迟。
|
||||
|
||||
func _update(delta: float) -> void:
|
||||
var player := get_agent() as Player
|
||||
if player == null:
|
||||
return
|
||||
if player.motor.try_jump():
|
||||
dispatch(&"airborne")
|
||||
return
|
||||
if not player.is_on_floor():
|
||||
dispatch(&"airborne")
|
||||
return
|
||||
_think(delta)
|
||||
|
||||
|
||||
## 各状态自己的输入转换。要不要 dispatch 事件、往哪转,由具体状态决定
|
||||
## (转换表注册在 grounded.gd 的 _setup 里)。
|
||||
func _think(_delta: float) -> void:
|
||||
pass
|
||||
@@ -0,0 +1 @@
|
||||
uid://dss42q7c4kqui
|
||||
@@ -0,0 +1,45 @@
|
||||
extends LimboHSM
|
||||
## 地面子机(挂在 HSM/Grounded 上)。
|
||||
##
|
||||
## 五个叶子状态:
|
||||
## Idle 站立不动 Walk 步行 Sprint 疾跑 Crouch 原地蹲 Sneak 蹲走
|
||||
## 叶子各自的输入转换见 ground_state.gd 及各状态脚本;本机只注册转换表,
|
||||
## 并在 _enter(首次激活 / 每次落地)时按「当下输入」挑初始子状态 ——
|
||||
## 不然按着方向键落地会先闪一帧站立。
|
||||
|
||||
@onready var idle: LimboState = $Idle
|
||||
@onready var walk: LimboState = $Walk
|
||||
@onready var sprint: LimboState = $Sprint
|
||||
@onready var crouch: LimboState = $Crouch
|
||||
@onready var sneak: LimboState = $Sneak
|
||||
|
||||
|
||||
func _setup() -> void:
|
||||
# 事件口径:move_start/stop 有无方向输入,sprint_start/stop 疾跑键,
|
||||
# crouch_start/end 蹲键。蹲伏优先于疾跑(蹲下时按 Shift 不算疾跑)。
|
||||
add_transition(idle, walk, &"move_start")
|
||||
add_transition(idle, crouch, &"crouch_start")
|
||||
add_transition(walk, idle, &"move_stop")
|
||||
add_transition(walk, sprint, &"sprint_start")
|
||||
add_transition(walk, sneak, &"crouch_start")
|
||||
add_transition(sprint, walk, &"sprint_stop")
|
||||
add_transition(sprint, idle, &"move_stop")
|
||||
add_transition(sprint, sneak, &"crouch_start")
|
||||
add_transition(crouch, sneak, &"move_start")
|
||||
add_transition(crouch, idle, &"crouch_end")
|
||||
add_transition(sneak, crouch, &"move_stop")
|
||||
add_transition(sneak, walk, &"crouch_end")
|
||||
|
||||
|
||||
func _enter() -> void:
|
||||
var player := get_agent() as Player
|
||||
if player == null:
|
||||
set_initial_state(idle)
|
||||
return
|
||||
var moving := player.motor.has_move_input()
|
||||
if Input.is_action_pressed("crouch"):
|
||||
set_initial_state(sneak if moving else crouch)
|
||||
elif moving:
|
||||
set_initial_state(sprint if Input.is_action_pressed("sprint") else walk)
|
||||
else:
|
||||
set_initial_state(idle)
|
||||
@@ -0,0 +1 @@
|
||||
uid://2bnkxlycmqqu
|
||||
@@ -0,0 +1,17 @@
|
||||
extends PlayerGroundState
|
||||
## 站立:目标速度 0,播 idle。
|
||||
|
||||
func _enter() -> void:
|
||||
var player := get_agent() as Player
|
||||
player.motor.target_speed = 0.0
|
||||
player.motor.sprinting = false
|
||||
player.motor.crouching = false
|
||||
player.animation_player.play_state(PlayerAnimator.AnimState.IDLE)
|
||||
|
||||
|
||||
func _think(_delta: float) -> void:
|
||||
# 蹲键优先 —— 同帧又蹲又走时先蹲下,下一帧 Crouch 再转 Sneak,不会漏蹲。
|
||||
if Input.is_action_pressed("crouch"):
|
||||
dispatch(&"crouch_start")
|
||||
elif (get_agent() as Player).motor.has_move_input():
|
||||
dispatch(&"move_start")
|
||||
@@ -0,0 +1 @@
|
||||
uid://2isemrs6ov3
|
||||
@@ -0,0 +1,20 @@
|
||||
extends LimboState
|
||||
## 上升段:播 jump。越过顶点(vy ≤ 0)转 Fall。
|
||||
## 水平目标速度保持离地前的值 —— 空中加速度本来就小(air_acceleration),
|
||||
## 不由本状态改写。
|
||||
|
||||
func _enter() -> void:
|
||||
(get_agent() as Player).animation_player.play_state(PlayerAnimator.AnimState.JUMP)
|
||||
|
||||
|
||||
func _update(_delta: float) -> void:
|
||||
var player := get_agent() as Player
|
||||
if player == null:
|
||||
return
|
||||
# 落地判定带 vy ≤ 0 门槛:起跳那一帧 is_on_floor() 还是 true
|
||||
# (要等 move_and_slide() 之后才翻假),没有门槛会当帧弹回地面状态。
|
||||
if player.is_on_floor() and player.velocity.y <= 0.0:
|
||||
dispatch(&"landed")
|
||||
return
|
||||
if player.velocity.y <= 0.0:
|
||||
dispatch(&"falling")
|
||||
@@ -0,0 +1 @@
|
||||
uid://cvfcvo7k1i5jr
|
||||
@@ -0,0 +1,16 @@
|
||||
extends LimboHSM
|
||||
## 玩家状态机根(挂在 Player/HSM 节点上,update_mode = MANUAL)。
|
||||
##
|
||||
## 只管最粗的一层:「身体在地上还是空中」。细分状态在两个子机里:
|
||||
## Grounded 地面 grounded.gd —— Idle / Walk / Sprint / Crouch / Sneak
|
||||
## Airborne 空中 airborne.gd —— Jump / Fall
|
||||
## 推进由 Player._physics_process 显式调 update(delta)(管线第一位)。
|
||||
|
||||
@onready var grounded: LimboHSM = $Grounded
|
||||
@onready var airborne: LimboHSM = $Airborne
|
||||
|
||||
|
||||
func _setup() -> void:
|
||||
# 起跳或踏空 → 空中;落地 → 回地面。事件的发起在各叶子状态里。
|
||||
add_transition(grounded, airborne, &"airborne")
|
||||
add_transition(airborne, grounded, &"landed")
|
||||
@@ -0,0 +1 @@
|
||||
uid://cgjaw5xbg7gdj
|
||||
@@ -0,0 +1,19 @@
|
||||
extends PlayerGroundState
|
||||
## 蹲走(潜行):目标速度 = crouch_speed,播 sneak。
|
||||
## 蹲伏优先于疾跑:蹲着按 Shift 也只是潜行。
|
||||
|
||||
|
||||
func _enter() -> void:
|
||||
var player := get_agent() as Player
|
||||
player.motor.target_speed = player.motor.crouch_speed
|
||||
player.motor.sprinting = false
|
||||
player.motor.crouching = true
|
||||
player.animation_player.play_state(PlayerAnimator.AnimState.SNEAK, player.motor.crouch_speed)
|
||||
|
||||
|
||||
func _think(_delta: float) -> void:
|
||||
var player := get_agent() as Player
|
||||
if not Input.is_action_pressed("crouch"):
|
||||
dispatch(&"crouch_end")
|
||||
elif not player.motor.has_move_input():
|
||||
dispatch(&"move_stop")
|
||||
@@ -0,0 +1 @@
|
||||
uid://b4okw70vrah42
|
||||
@@ -0,0 +1,19 @@
|
||||
extends PlayerGroundState
|
||||
## 疾跑:目标速度 = sprint_speed,播 run。只在按着方向键时成立(Sprint 由 Walk 进入)。
|
||||
|
||||
func _enter() -> void:
|
||||
var player := get_agent() as Player
|
||||
player.motor.target_speed = player.motor.sprint_speed
|
||||
player.motor.sprinting = true
|
||||
player.motor.crouching = false
|
||||
player.animation_player.play_state(PlayerAnimator.AnimState.RUN, player.motor.sprint_speed)
|
||||
|
||||
|
||||
func _think(_delta: float) -> void:
|
||||
var player := get_agent() as Player
|
||||
if Input.is_action_pressed("crouch"):
|
||||
dispatch(&"crouch_start")
|
||||
elif not player.motor.has_move_input():
|
||||
dispatch(&"move_stop")
|
||||
elif not Input.is_action_pressed("sprint"):
|
||||
dispatch(&"sprint_stop")
|
||||
@@ -0,0 +1 @@
|
||||
uid://cklw8uq6xahe
|
||||
@@ -0,0 +1,19 @@
|
||||
extends PlayerGroundState
|
||||
## 步行:目标速度 = walk_speed,播 walk。
|
||||
|
||||
func _enter() -> void:
|
||||
var player := get_agent() as Player
|
||||
player.motor.target_speed = player.motor.walk_speed
|
||||
player.motor.sprinting = false
|
||||
player.motor.crouching = false
|
||||
player.animation_player.play_state(PlayerAnimator.AnimState.WALK, player.motor.walk_speed)
|
||||
|
||||
|
||||
func _think(_delta: float) -> void:
|
||||
var player := get_agent() as Player
|
||||
if Input.is_action_pressed("crouch"):
|
||||
dispatch(&"crouch_start")
|
||||
elif not player.motor.has_move_input():
|
||||
dispatch(&"move_stop")
|
||||
elif Input.is_action_pressed("sprint"):
|
||||
dispatch(&"sprint_start")
|
||||
@@ -0,0 +1 @@
|
||||
uid://6pa3038100o4
|
||||
Reference in New Issue
Block a user