From 16f5fda45ed2a668758450eff052e0903d7ef3ae Mon Sep 17 00:00:00 2001 From: Clifton Palmer Date: Tue, 6 May 2025 14:37:15 +0300 Subject: [PATCH 1/1] Separated model movement into discrete states --- player/InputHandler.gd | 16 +++++++++-- player/Move.gd | 35 +++++++++++++++++++++++ player/Move.gd.uid | 1 + player/dash.gd | 11 ++++++++ player/dash.gd.uid | 1 + player/idle.gd | 7 +++++ player/idle.gd.uid | 1 + player/model.gd | 63 +++++++++++++++++++----------------------- player/player.gd | 15 ++++++++-- player/player.tscn | 14 +++++++++- player/walk.gd | 27 ++++++++++++++++++ player/walk.gd.uid | 1 + 12 files changed, 152 insertions(+), 40 deletions(-) create mode 100644 player/Move.gd create mode 100644 player/Move.gd.uid create mode 100644 player/dash.gd create mode 100644 player/dash.gd.uid create mode 100644 player/idle.gd create mode 100644 player/idle.gd.uid create mode 100644 player/walk.gd create mode 100644 player/walk.gd.uid diff --git a/player/InputHandler.gd b/player/InputHandler.gd index 109b804..d7f2fb4 100644 --- a/player/InputHandler.gd +++ b/player/InputHandler.gd @@ -3,12 +3,24 @@ class_name InputHandler func get_camera_input_direction() -> Vector2: - return Input.get_vector("camera-left", "camera-right", "camera-up", "camera-down") + return Input.get_vector( + "camera-left", "camera-right", "camera-up", "camera-down" + ) func get_player_input() -> InputPacket: var p: InputPacket = InputPacket.new() + + p.movement_direction = Input.get_vector( + "player-left", "player-right", "player-forward", "player-backward" + ) + if p.movement_direction != Vector2.ZERO: + p.actions.append("walk") + if Input.is_action_just_pressed("player-dash"): p.actions.append("dash") - p.movement_direction = Input.get_vector("player-left", "player-right", "player-forward", "player-backward") + + if p.actions.is_empty(): + p.actions.append("idle") + return p diff --git a/player/Move.gd b/player/Move.gd new file mode 100644 index 0000000..70fb73a --- /dev/null +++ b/player/Move.gd @@ -0,0 +1,35 @@ +extends Node +class_name Move + +### +# flags and variables here +var player: CharacterBody3D +var camera: Camera3D + +# enums are prioritized by order of list +static var moves_priority: Dictionary = { + "idle": 0, + "walk": 1, + "dash": 2 +} + +static func moves_priority_sort(a: String, b: String): + return moves_priority[a] > moves_priority[b] + +### + +func should_enter(input: InputPacket) -> String: + print_debug("Function should_enter must be implemented in its child class!") + return "" + + +func update(input: InputPacket, delta: float): + pass + + +func on_enter_state(): + pass + + +func on_exit_state(): + pass diff --git a/player/Move.gd.uid b/player/Move.gd.uid new file mode 100644 index 0000000..3a9d576 --- /dev/null +++ b/player/Move.gd.uid @@ -0,0 +1 @@ +uid://c886t1c86q0m6 diff --git a/player/dash.gd b/player/dash.gd new file mode 100644 index 0000000..c062734 --- /dev/null +++ b/player/dash.gd @@ -0,0 +1,11 @@ +extends Move +class_name Dash + + +func should_enter(input) -> String: + input.actions.sort_custom(moves_priority_sort) + return input.actions[0] + + +func update(input: InputPacket, delta: float): + player.move_and_slide() diff --git a/player/dash.gd.uid b/player/dash.gd.uid new file mode 100644 index 0000000..9c00fd9 --- /dev/null +++ b/player/dash.gd.uid @@ -0,0 +1 @@ +uid://bdiks0m7vsn5w diff --git a/player/idle.gd b/player/idle.gd new file mode 100644 index 0000000..0fa5569 --- /dev/null +++ b/player/idle.gd @@ -0,0 +1,7 @@ +extends Move +class_name Idle + + +func should_enter(input) -> String: + input.actions.sort_custom(moves_priority_sort) + return input.actions[0] diff --git a/player/idle.gd.uid b/player/idle.gd.uid new file mode 100644 index 0000000..f14865a --- /dev/null +++ b/player/idle.gd.uid @@ -0,0 +1 @@ +uid://bv5k167ugxmso diff --git a/player/model.gd b/player/model.gd index c2d8c78..05564a8 100644 --- a/player/model.gd +++ b/player/model.gd @@ -1,43 +1,36 @@ extends Node class_name PlayerModel +@onready var player: Player = $".." +@onready var camera: Camera3D = %camera -@export_group("Movement") -@export var walk_speed := 8.0 -@export var dash_length := 10.0 -@export var air_speed := 3.0 -@export var acceleration := 30.0 -@export var rotation_speed := 10.0 -@export var idle_timeout := 5.0 +@onready var moves: Dictionary = { + "idle": $Idle, + "walk": $Walk, + "dash": $Dash +} +var current_move: Move -var idle_time := 0.0 -var floor_normal := Vector3.ZERO -var ground_slope_input := 0.0 -@onready var _player: Player = $".." -@onready var _camera: Camera3D = %camera +### - -func get_velocity_by_input(input_pkt: InputPacket, delta: float) -> Vector3: - var new_velocity: Vector3 = _player.velocity +func _ready() -> void: + current_move = moves["idle"] - if _player.is_on_floor(): - # Get the XZ input direction based on player's input relative to the camera - var forward := _camera.global_basis.z - var right := _camera.global_basis.x - var move_direction := ( - forward * input_pkt.movement_direction.y + right * input_pkt.movement_direction.x - ).normalized() - move_direction.y = 0 - - # if we're not stuck, then it's okay to set the velocity - floor_normal = _player.get_floor_normal() - ground_slope_input = (PI / 2) - new_velocity.angle_to(floor_normal) - new_velocity = new_velocity.move_toward( - move_direction * (walk_speed + ground_slope_input * walk_speed), - acceleration * delta - ) - else: - new_velocity += _player.get_gravity() * air_speed * delta - - return new_velocity + # assign player object to each move + for move in moves.values(): + move.player = player + move.camera = camera + + +func update(input: InputPacket, delta: float): + var relevent_move = current_move.should_enter(input) + if not relevent_move.is_empty(): + switch_to(relevent_move) + current_move.update(input, delta) + + +func switch_to(state: String): + current_move.on_exit_state() + current_move = moves[state] + current_move.on_enter_state() diff --git a/player/player.gd b/player/player.gd index 6e32bcd..ea89487 100644 --- a/player/player.gd +++ b/player/player.gd @@ -2,11 +2,22 @@ extends CharacterBody3D class_name Player +@export_group("Movement") +@export var walk_speed := 8.0 +@export var dash_length := 10.0 +@export var air_speed := 3.0 +@export var acceleration := 30.0 +@export var rotation_speed := 10.0 +@export var idle_timeout := 5.0 + +var idle_time := 0.0 +var floor_normal := Vector3.ZERO +var ground_slope_input := 0.0 + @onready var _input: InputHandler = %Input @onready var _model: PlayerModel = %Model func _physics_process(delta: float) -> void: var input_pkt := _input.get_player_input() - velocity = _model.get_velocity_by_input(input_pkt, delta) - move_and_slide() + _model.update(input_pkt, delta) diff --git a/player/player.tscn b/player/player.tscn index 4814692..fb4bbe3 100644 --- a/player/player.tscn +++ b/player/player.tscn @@ -1,10 +1,13 @@ -[gd_scene load_steps=7 format=3 uid="uid://cchu1yltrhuk3"] +[gd_scene load_steps=10 format=3 uid="uid://cchu1yltrhuk3"] [ext_resource type="PackedScene" uid="uid://dvkx3t15l7mfb" path="res://skin/prototype_skin.tscn" id="1_4flbx"] [ext_resource type="Script" uid="uid://dcv34jq0jett0" path="res://player/player.gd" id="1_onrkg"] [ext_resource type="Script" uid="uid://bspr3vafk6wi2" path="res://player/InputHandler.gd" id="3_g1dw6"] [ext_resource type="Script" uid="uid://c5mn28v6ujngk" path="res://player/CameraHandler.gd" id="3_yw30f"] [ext_resource type="Script" uid="uid://bwox6frn7fmgt" path="res://player/model.gd" id="5_qjkh3"] +[ext_resource type="Script" uid="uid://bv5k167ugxmso" path="res://player/idle.gd" id="6_g6k8r"] +[ext_resource type="Script" uid="uid://cqurhmxam2nl0" path="res://player/walk.gd" id="7_rgyib"] +[ext_resource type="Script" uid="uid://bdiks0m7vsn5w" path="res://player/dash.gd" id="8_hg6s5"] [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_sh265"] @@ -39,3 +42,12 @@ script = ExtResource("3_g1dw6") [node name="Model" type="Node" parent="."] unique_name_in_owner = true script = ExtResource("5_qjkh3") + +[node name="Idle" type="Node" parent="Model"] +script = ExtResource("6_g6k8r") + +[node name="Walk" type="Node" parent="Model"] +script = ExtResource("7_rgyib") + +[node name="Dash" type="Node" parent="Model"] +script = ExtResource("8_hg6s5") diff --git a/player/walk.gd b/player/walk.gd new file mode 100644 index 0000000..5f536b3 --- /dev/null +++ b/player/walk.gd @@ -0,0 +1,27 @@ +extends Move +class_name Walk + + +func should_enter(input) -> String: + input.actions.sort_custom(moves_priority_sort) + return input.actions[0] + + +func update(input: InputPacket, delta: float): + # Get the XZ input direction based on player's input relative to the camera + var forward := camera.global_basis.z + var right := camera.global_basis.x + var move_direction := ( + forward * input.movement_direction.y + right * input.movement_direction.x + ).normalized() + move_direction.y = 0 + + # if we're not stuck, then it's okay to set the velocity + var floor_normal = player.get_floor_normal() + var ground_slope_input = (PI / 2) - player.velocity.angle_to(floor_normal) + player.velocity = player.velocity.move_toward( + move_direction * (player.walk_speed + ground_slope_input * player.walk_speed), + player.acceleration * delta + ) + + player.move_and_slide() diff --git a/player/walk.gd.uid b/player/walk.gd.uid new file mode 100644 index 0000000..7a68c1e --- /dev/null +++ b/player/walk.gd.uid @@ -0,0 +1 @@ +uid://cqurhmxam2nl0 -- 2.47.2