gmp(M02): extract local player movement

Work-Package: M02-GMP-MOVEMENT-001
Agent: sindo-main-codex
Tests: local movement and player input regressions; asset-free scene; renderer dry-run; coordinate, streaming, documentation and coordination gates
Fidelity: preserves current sandbox speed, acceleration, sprint and camera-relative flight behavior; build-12340 parity remains unverified
This commit is contained in:
2026-07-14 22:59:33 +04:00
parent 14dead194b
commit 435e1c95d2
9 changed files with 601 additions and 56 deletions
@@ -9,6 +9,7 @@ const ADT_TILE_COORDINATE_SCRIPT := preload("res://src/domain/coordinates/adt_ti
const ADT_TILE_LOCAL_POSITION_SCRIPT := preload("res://src/domain/coordinates/adt_tile_local_position.gd")
const PLAYER_INPUT_SOURCE_SCRIPT := preload("res://src/gameplay/input/player_input_source.gd")
const PLAYER_INPUT_ACTIONS_SCRIPT := preload("res://src/gameplay/input/player_input_actions.gd")
const LOCAL_PLAYER_MOVEMENT_CONTROLLER_SCRIPT := preload("res://src/gameplay/movement/local_player_movement_controller.gd")
const CHUNK_SIZE := COORDINATE_MAPPER_SCRIPT.ADT_CHUNK_SIZE_YARDS
const UNIT_SIZE := CHUNK_SIZE / 8.0
@@ -54,14 +55,21 @@ var _active_animation := ""
var _captured := false
var _yaw := 0.0
var _pitch := deg_to_rad(-18.0)
var _horizontal_velocity := Vector3.ZERO
var _flight_enabled := false
var _adt_cache: Dictionary = {}
var _player_input_source: PlayerInputSource
var _local_movement_controller: LocalPlayerMovementController
func _ready() -> void:
_player_input_source = PLAYER_INPUT_SOURCE_SCRIPT.new()
_local_movement_controller = LOCAL_PLAYER_MOVEMENT_CONTROLLER_SCRIPT.new(
run_speed,
backward_speed,
strafe_speed,
flight_vertical_speed,
acceleration,
sprint_multiplier
)
_camera_pivot = get_node_or_null(camera_pivot_path) as Node3D
_camera = get_node_or_null(camera_path) as Camera3D
_visual = get_node_or_null(visual_path) as Node3D
@@ -99,8 +107,7 @@ func _unhandled_input(event: InputEvent) -> void:
_captured = false
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED if _captured else Input.MOUSE_MODE_VISIBLE
elif event.is_action_pressed(PLAYER_INPUT_ACTIONS_SCRIPT.DEBUG_TOGGLE_FLIGHT) and not event.is_echo():
_flight_enabled = not _flight_enabled
_horizontal_velocity = Vector3.ZERO
_local_movement_controller.toggle_sandbox_flight()
if _captured and event is InputEventMouseMotion:
_yaw -= event.relative.x * mouse_sensitivity
@@ -111,54 +118,26 @@ func _unhandled_input(event: InputEvent) -> void:
func _physics_process(delta: float) -> void:
var move_intent := _player_input_source.sample_move_intent()
var target_velocity := Vector3.ZERO
if move_intent.has_translation():
target_velocity = _movement_vector(move_intent)
if _flight_enabled:
target_velocity.y += move_intent.vertical_axis * flight_vertical_speed * _debug_speed_multiplier(move_intent)
var godot_world_movement_basis := global_basis
if _local_movement_controller.is_flight_enabled and _camera_pivot:
godot_world_movement_basis = _camera_pivot.global_basis
global_position += _local_movement_controller.advance(move_intent, godot_world_movement_basis, delta)
_horizontal_velocity = _horizontal_velocity.move_toward(target_velocity, acceleration * delta)
global_position += _horizontal_velocity * delta
if not _flight_enabled:
if not _local_movement_controller.is_flight_enabled:
var ground := _sample_ground_height(global_position)
if is_finite(ground):
var target_y := ground + ground_offset
global_position.y = lerpf(global_position.y, target_y, clampf(ground_snap_speed * delta, 0.0, 1.0))
var horizontal_motion := Vector2(_horizontal_velocity.x, _horizontal_velocity.z)
var movement_velocity := _local_movement_controller.godot_world_velocity_units_per_second
var horizontal_motion := Vector2(movement_velocity.x, movement_velocity.z)
if _visual and horizontal_motion.length_squared() > 0.01:
_visual.global_rotation.y = atan2(-_horizontal_velocity.x, -_horizontal_velocity.z)
_visual.global_rotation.y = atan2(-movement_velocity.x, -movement_velocity.z)
_update_character_animation(horizontal_motion.length_squared() > 0.04)
_apply_camera_transform()
func _movement_vector(move_intent: MoveIntent) -> Vector3:
var forward := -global_basis.z
var right := global_basis.x
if _flight_enabled and _camera_pivot:
forward = -_camera_pivot.global_basis.z
right = _camera_pivot.global_basis.x
else:
forward.y = 0.0
right.y = 0.0
forward = forward.normalized()
right = right.normalized()
var speed_z := run_speed if move_intent.forward_axis > 0.0 else backward_speed
var speed_x := strafe_speed
return (
forward * move_intent.forward_axis * speed_z
+ right * move_intent.strafe_axis * speed_x
) * _debug_speed_multiplier(move_intent)
func _debug_speed_multiplier(move_intent: MoveIntent) -> float:
return sprint_multiplier if move_intent.is_sprint_requested else 1.0
func _load_character_visual() -> void:
if character_model_path.is_empty() or _visual == null:
return