class_name Player extends CharacterBody2D @export_group("Grounded Movement") @export var walk_speed: float = 120.0 @export var acceleration: float = 120.0 @export var stopping_force: float = 320.0 @export var stop_threshold: float = 4.0 @export var turning_force: float = 450.0 @onready var state_chart: StateChart = %StateChart @onready var graphics: Node2D = %Graphics @onready var animation_player: AnimationPlayer = %AnimationPlayer @onready var front_arm_pivot: Node2D = %FrontArmPivot @onready var back_arm_pivot: Node2D = %BackArmPivot var input_dir: float = 0.0 var aim_back_arm: bool = false var _was_on_floor: bool = true var _highlighted_pickup: Pickup = null func _ready() -> void: state_chart.set_expression_property(&"player", self) func _physics_process(delta: float) -> void: _face_body_to_mouse() if is_on_floor(): state_chart.send_event(&"landed") else: state_chart.send_event(&"left_ground") var old_input_dir = input_dir input_dir = signf(Input.get_axis(&"move_left", &"move_right")) if input_dir != old_input_dir: state_chart.send_event(&"input_dir_changed") func _input(event: InputEvent) -> void: if event.is_action_pressed(&"aim"): state_chart.send_event(&"aim_pressed") elif event.is_action_released(&"aim"): state_chart.send_event(&"aim_released") func toss_held_object() -> void: pass func _face_body_to_mouse() -> void: if get_local_mouse_position().x < 0.0: graphics.scale.x = -1.0 else: graphics.scale.x = 1.0 func _face_arm_to_mouse(pivot: Node2D) -> void: var mouse_pos = graphics.get_local_mouse_position() var pivot_xform = pivot.get_relative_transform_to_parent(graphics) pivot.rotation = pivot_xform.origin.angle_to_point(mouse_pos) #region Movement States func _active_physics_process(delta: float) -> void: move_and_slide() #region Grounded States func _grounded_child_state_entered() -> void: state_chart.send_event(&"input_dir_changed") func _standing_entered() -> void: velocity.x = 0.0 func _walking_process(delta: float) -> void: velocity.x += acceleration * input_dir * delta velocity.x = clampf(velocity.x, -walk_speed, walk_speed) animation_player.speed_scale = inverse_lerp(0, walk_speed, velocity.x) * graphics.scale.x func _stopping_physics_process(delta: float) -> void: velocity.x -= stopping_force * signf(velocity.x) * delta if absf(velocity.x) <= stop_threshold: velocity.x = 0.0 state_chart.send_event(&"stopped") func _turning_physics_process(delta: float) -> void: velocity.x += turning_force * input_dir * delta if signf(velocity.x) != -input_dir: state_chart.send_event(&"turn_finished") func _aiming_physics_process(delta: float) -> void: _face_arm_to_mouse(front_arm_pivot) if aim_back_arm: _face_arm_to_mouse(back_arm_pivot) func _aiming_exited() -> void: front_arm_pivot.rotation = PI * 0.5 back_arm_pivot.rotation = PI * 0.5 #endregion #region Airborn States func _airborn_physics_process(delta: float) -> void: velocity += get_gravity() * delta #endregion #endregion #region Collision Signals func _on_pickup_area_entered(area: Area2D) -> void: if not _highlighted_pickup: _highlighted_pickup = area.get_parent() as Pickup _highlighted_pickup.highlight = true func _on_pickup_area_exited(area: Area2D) -> void: if _highlighted_pickup == (area.get_parent() as Pickup): _highlighted_pickup.highlight = false _highlighted_pickup = null #endregion