Compare commits

...
3 Commits
3 changed files with 65 additions and 29 deletions
+5 -9
View File
@@ -65,12 +65,16 @@ func _build_player() -> void:
shape.shape.height = 1.8 shape.shape.height = 1.8
player.add_child(shape) player.add_child(shape)
var mover_script = preload("res://movement/player_movement_controller.gd")
if mover_script:
player.set_script(mover_script)
# State machine # State machine
var sm := Node.new() var sm := Node.new()
sm.name = "MovementStateMachine" sm.name = "MovementStateMachine"
player.add_child(sm) player.add_child(sm)
var sm_script = load("res://movement/movement_state_machine.gd") var sm_script = preload("res://movement/movement_state_machine.gd")
if sm_script: if sm_script:
sm.set_script(sm_script) sm.set_script(sm_script)
@@ -91,14 +95,6 @@ func _build_player() -> void:
if st_script: if st_script:
st.set_script(st_script) st.set_script(st_script)
# Movement controller
var mover_script = load("res://movement/player_movement_controller.gd")
if mover_script:
player.set_script(mover_script)
# set_script does not auto-call _ready(); do it manually
if player.has_method("_ready"):
player._ready()
# Camera # Camera
var camera := Camera3D.new() var camera := Camera3D.new()
camera.name = "Camera3D" camera.name = "Camera3D"
+48 -20
View File
@@ -12,39 +12,67 @@ signal chain_updated(count: int, bonus: float)
var machine: MovementStateMachine var machine: MovementStateMachine
var jump_buffered: bool = false var jump_buffered: bool = false
var _ready_ran: bool = false
var _machine: MovementStateMachine = null
# ── Helpers ───────────────────────────────────────────────────────────────────
func _ensure_machine() -> MovementStateMachine:
if typeof(_machine) != TYPE_NIL and is_instance_valid(_machine):
return _machine as MovementStateMachine
var candidates := [
get_node("MovementStateMachine") if has_node("MovementStateMachine") else null,
_machine if is_instance_valid(_machine) and _machine.has_method("register_chain_mechanic") else null,
]
for c in candidates:
if c and (c is MovementStateMachine or (c.has_method("switch_to") and c.has_method("register_chain_mechanic"))):
_machine = c
return _machine
return null
# ── Input references ───────────────────────────────────────────────────────── # ── Input references ─────────────────────────────────────────────────────────
func _unhandled_input(event: InputEvent) -> void: func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("ui_accept"): if event.is_action_pressed("ui_accept"):
# Space / jump # Space / jump
pass pass
_machine.input_jump_just_pressed = Input.is_action_just_pressed("jump") var node := _ensure_machine()
_machine.input_jump_pressed = Input.is_action_pressed("jump") if not node:
_machine.input_sprint = Input.is_action_pressed("sprint") return
_machine.input_crouch = Input.is_action_pressed("crouch") node.input_jump_just_pressed = Input.is_action_just_pressed("jump")
_machine.input_dash = Input.is_action_just_pressed("dash") node.input_jump_pressed = Input.is_action_pressed("jump")
node.input_sprint = Input.is_action_pressed("sprint")
node.input_crouch = Input.is_action_pressed("crouch")
node.input_dash = Input.is_action_just_pressed("dash")
var input_v := Input.get_vector("move_left", "move_right", "move_forward", "move_back") var input_v := Input.get_vector("move_left", "move_right", "move_forward", "move_back")
_machine.input_dir = input_v node.input_dir = input_v
@onready var _machine = get_node("MovementStateMachine") @onready var _machine = get_node("MovementStateMachine")
func _ready() -> void: func _ready() -> void:
_machine.player = self if _ready_ran:
_machine.params = params return
# Mirror signal up _ready_ran = true
_machine.movement_event.connect(func(ev, data): var node := _ensure_machine()
if ev == "chain_updated": if node:
chain_updated.emit(data.count, data.bonus) var sm := node
) sm.player = self
sm.params = params
# Mirror signal up
sm.movement_event.connect(func(ev, data):
if ev == "chain_updated":
chain_updated.emit(data.count, data.bonus)
)
func _process(_delta: float) -> void: func _process(_delta: float) -> void:
_machine.input_jump_just_pressed = Input.is_action_just_pressed("jump") and not _machine.input_jump_pressed var node := _ensure_machine()
_machine.input_jump_pressed = Input.is_action_pressed("jump") if not node:
_machine.input_sprint = Input.is_action_pressed("sprint") return
_machine.input_crouch = Input.is_action_pressed("crouch") # Keep one consistent source of truth for inputs
_machine.input_dash = Input.is_action_just_pressed("dash") and not _machine.input_dash node.input_jump_just_pressed = Input.is_action_just_pressed("jump") and not node.input_jump_pressed
var input_v := Input.get_vector("move_left", "move_right", "move_forward", "move_back") node.input_jump_pressed = Input.is_action_pressed("jump")
_machine.input_dir = input_v node.input_sprint = Input.is_action_pressed("sprint")
node.input_crouch = Input.is_action_pressed("crouch")
node.input_dash = Input.is_action_just_pressed("dash") and not node.input_dash
node.input_dir = Input.get_vector("move_left", "move_right", "move_forward", "move_back")
+12
View File
@@ -0,0 +1,12 @@
extends Node
class_name MovementRunner
## Run: godot --headless --path . --script movement/tests/test_fsm_runner.gd
## This file exists only as the runnable verifier entrypoint documented by the skill.
func _ready() -> void:
var script_path := "res://movement/tests/test_fsm_runner.gd"
var runner = load(script_path).new()
if runner and runner.has_method("run_all"):
runner.run_all()
get_tree().quit(0)