feat: implement movement state machine ground/air states and initialize weapon manager system

This commit is contained in:
DottsGit
2026-06-10 22:37:17 -04:00
parent 3dc7fda622
commit 3c512870f2
3 changed files with 51 additions and 12 deletions
+8 -2
View File
@@ -140,8 +140,14 @@ func update(delta: float) -> void:
# Fallback to wall run # Fallback to wall run
var wall_n := machine.detect_wall_horizontal() var wall_n := machine.detect_wall_horizontal()
if wall_n != Vector3.ZERO: if wall_n != Vector3.ZERO:
machine.switch_to("wall_run") var w_look_dir := -player.global_transform.basis.z
return var h_look := Vector3(w_look_dir.x, 0.0, w_look_dir.z).normalized()
# Require looking mostly along the wall (angle > 41 degrees from normal)
# and inputting mostly along the wall (angle > 31 degrees from normal, allows W+A/D diagonally into wall)
if absf(h_look.dot(wall_n)) < 0.75 and absf(wish_dir.dot(wall_n)) < 0.85:
machine.switch_to("wall_run")
return
# ── Dash ────────────────────────────────────────────────────────────── # ── Dash ──────────────────────────────────────────────────────────────
if machine.input_dash: if machine.input_dash:
+8 -2
View File
@@ -204,8 +204,14 @@ func update(delta: float) -> void:
var wall_n := machine.detect_wall_horizontal() var wall_n := machine.detect_wall_horizontal()
if wall_n != Vector3.ZERO: if wall_n != Vector3.ZERO:
if not player.is_on_floor(): if not player.is_on_floor():
machine.switch_to("wall_run") var w_look_dir := -player.global_transform.basis.z
return var h_look := Vector3(w_look_dir.x, 0.0, w_look_dir.z).normalized()
# Require looking mostly along the wall (angle > 41 degrees from normal)
# and inputting mostly along the wall (angle > 31 degrees from normal, allows W+A/D diagonally into wall)
if absf(h_look.dot(wall_n)) < 0.75 and absf(wish_dir.dot(wall_n)) < 0.85:
machine.switch_to("wall_run")
return
# ── Dash ────────────────────────────────────────────────────────────── # ── Dash ──────────────────────────────────────────────────────────────
if machine.input_dash: if machine.input_dash:
+35 -8
View File
@@ -56,6 +56,10 @@ func _setup_viewmodel_viewport() -> void:
add_child(dir_light) add_child(dir_light)
var _bob_timer: float = 0.0 var _bob_timer: float = 0.0
var _current_slide_tilt_z: float = 0.0
var _current_slide_tilt_x: float = 0.0
var _current_slide_offset_x: float = 0.0
var _current_slide_offset_y: float = 0.0
var _recoil_pitch: float = 0.0 var _recoil_pitch: float = 0.0
var _recoil_yaw: float = 0.0 var _recoil_yaw: float = 0.0
var _target_drift_offset: Vector3 = Vector3.ZERO var _target_drift_offset: Vector3 = Vector3.ZERO
@@ -80,15 +84,32 @@ func _process(_delta: float) -> void:
var over_speed_factor = clampf((hspeed - 11.0) / 19.0, 0.0, 1.0) # maxes out at 30 m/s var over_speed_factor = clampf((hspeed - 11.0) / 19.0, 0.0, 1.0) # maxes out at 30 m/s
target_fov = lerpf(72.0, 80.0, over_speed_factor) target_fov = lerpf(72.0, 80.0, over_speed_factor)
# Weapon Viewmodel Bobbing and Drift # Weapon Viewmodel Bobbing, Drift, and Slide Tilt
if player.is_on_floor() and hspeed > 1.0: var is_sliding = player.has_method("get_node") and player.get_node_or_null("MovementStateMachine") and player.get_node("MovementStateMachine").current_state == "slide"
# Scale bobbing frequency by walk speed (assuming base walk speed is ~10-11)
_bob_timer += _delta * 12.0 * (hspeed / 11.0) if is_sliding:
var bob_y = sin(_bob_timer) * 0.015
var bob_x = cos(_bob_timer * 0.5) * 0.01
vm_camera.translate_object_local(Vector3(bob_x, bob_y, 0))
else:
_bob_timer = 0.0 _bob_timer = 0.0
# Target tilt when sliding (inwards towards center, pitched slightly down)
# Assuming weapon is on right side (standard FPS), tilting left (positive Z rotation)
_current_slide_tilt_z = lerpf(_current_slide_tilt_z, deg_to_rad(15.0), 12.0 * _delta)
_current_slide_tilt_x = lerpf(_current_slide_tilt_x, 0.0, 12.0 * _delta)
# Move closer to center (negative X) and slightly down (negative Y)
_current_slide_offset_x = lerpf(_current_slide_offset_x, -0.15, 12.0 * _delta)
_current_slide_offset_y = lerpf(_current_slide_offset_y, -0.1, 12.0 * _delta)
else:
_current_slide_tilt_z = lerpf(_current_slide_tilt_z, 0.0, 10.0 * _delta)
_current_slide_tilt_x = lerpf(_current_slide_tilt_x, 0.0, 10.0 * _delta)
_current_slide_offset_x = lerpf(_current_slide_offset_x, 0.0, 10.0 * _delta)
_current_slide_offset_y = lerpf(_current_slide_offset_y, 0.0, 10.0 * _delta)
if player.is_on_floor() and hspeed > 1.0:
# Scale bobbing frequency by walk speed
_bob_timer += _delta * 12.0 * (hspeed / 11.0)
var bob_y = sin(_bob_timer) * 0.015
var bob_x = cos(_bob_timer * 0.5) * 0.01
vm_camera.translate_object_local(Vector3(bob_x, bob_y, 0))
else:
_bob_timer = 0.0
if not player.is_on_floor(): if not player.is_on_floor():
# Airborne Drift # Airborne Drift
@@ -107,6 +128,12 @@ func _process(_delta: float) -> void:
vm_camera.translate_object_local(_current_drift_offset) vm_camera.translate_object_local(_current_drift_offset)
vm_camera.rotate_object_local(Vector3.UP, deg_to_rad(-_current_drift_offset.x * 30.0)) vm_camera.rotate_object_local(Vector3.UP, deg_to_rad(-_current_drift_offset.x * 30.0))
vm_camera.rotate_object_local(Vector3.RIGHT, deg_to_rad(_current_drift_offset.y * 30.0)) vm_camera.rotate_object_local(Vector3.RIGHT, deg_to_rad(_current_drift_offset.y * 30.0))
# Apply slide tilt and offset
if absf(_current_slide_tilt_z) > 0.001 or absf(_current_slide_offset_x) > 0.001:
vm_camera.translate_object_local(Vector3(_current_slide_offset_x, _current_slide_offset_y, 0))
vm_camera.rotate_object_local(Vector3.FORWARD, _current_slide_tilt_z)
vm_camera.rotate_object_local(Vector3.RIGHT, _current_slide_tilt_x)
# Visual Recoil # Visual Recoil
_recoil_pitch = lerpf(_recoil_pitch, 0.0, 15.0 * _delta) _recoil_pitch = lerpf(_recoil_pitch, 0.0, 15.0 * _delta)