From ea3b68aef8887407bdae3f313ebbac7833ad9715 Mon Sep 17 00:00:00 2001 From: Sara Date: Wed, 31 Dec 2025 12:19:30 +0100 Subject: [PATCH] translated movement to state machine --- .dir-locals.el | 5 +- modules/authority/character.cpp | 27 ++++++++-- modules/authority/character.h | 1 + modules/authority/player_states.cpp | 57 ++++++++++++++++++++-- modules/authority/player_states.h | 7 +-- modules/authority/register_types.cpp | 3 ++ project/data/default_player_character.tres | 2 +- project/objects/player_character.tscn | 13 ++++- project/scenes/test_world.tscn | 2 - 9 files changed, 98 insertions(+), 19 deletions(-) diff --git a/.dir-locals.el b/.dir-locals.el index 40383772..b5fe46f9 100644 --- a/.dir-locals.el +++ b/.dir-locals.el @@ -1,2 +1,5 @@ ((c++-mode . ((mode . clang-format-on-save))) - (c-mode . ((mode . c++)))) + (c-mode . ((mode . c++))) + (nil . ((projectile-project-compilation-cmd . "just build") + (projectile-project-run-cmd . "engine/bin/godot.linuxbsd.editor.dev.x86_64.llvm --path project -e") + (projectile-project-test-cmd . "engine/bin/godot.linuxbsd.editor.dev.x86.llvm --path project")))) diff --git a/modules/authority/character.cpp b/modules/authority/character.cpp index 890dc836..0dfdb3b8 100644 --- a/modules/authority/character.cpp +++ b/modules/authority/character.cpp @@ -66,7 +66,7 @@ void CharacterState::_notification(int what) { } void CharacterState::switch_to_state(String value) { - if (this->state_active) { + if (!this->state_active) { print_error(vformat("Attempt to switch from inactive state %s to new state %s", get_path(), value)); return; } @@ -75,7 +75,7 @@ void CharacterState::switch_to_state(String value) { } void CharacterState::stack_state_dependent(String value) { - if (this->state_active) { + if (!this->state_active) { print_error(vformat("Attempt to stack dependent state %s from inactive state %s", value, get_path())); return; } @@ -87,8 +87,16 @@ void CharacterState::stack_state_dependent(String value) { } } +void CharacterState::notify_dependent_inactive(CharacterState *state) { + if (!this->state_active) { + print_error(vformat("Received notification that dependent state %s became inactive, while depending state %s was inactive", state->get_path(), get_path())); + return; + } + this->dependent_states.erase(state); +} + void CharacterState::stack_state_independent(String value) { - if (this->state_active) { + if (!this->state_active) { print_error(vformat("Attempt to stack state %s from inactive state %s", value, get_path())); return; } @@ -101,12 +109,15 @@ void CharacterState::stack_state_independent(String value) { } void CharacterState::set_state_active(bool active) { - if (this->state_active == active) { + if (this->state_active != active) { this->state_active = active; if (active) { state_entered(); } else { state_exited(); + if (this->depending_state && this->depending_state->state_active) { + this->depending_state->notify_dependent_inactive(this); + } this->depending_state = nullptr; for (CharacterState *state : this->dependent_states) { state->set_state_active(false); @@ -115,3 +126,11 @@ void CharacterState::set_state_active(bool active) { } } } + +bool CharacterState::get_state_active() const { + return this->state_active; +} + +Character *CharacterState::get_character() const { + return this->character; +} diff --git a/modules/authority/character.h b/modules/authority/character.h index c329f179..b523b0d1 100644 --- a/modules/authority/character.h +++ b/modules/authority/character.h @@ -44,6 +44,7 @@ protected: void _notification(int what); void switch_to_state(String state); void stack_state_dependent(String state); + void notify_dependent_inactive(CharacterState *dependent); void stack_state_independent(String state); virtual void state_entered() {} virtual void state_exited() {} diff --git a/modules/authority/player_states.cpp b/modules/authority/player_states.cpp index 0ee37561..593a790f 100644 --- a/modules/authority/player_states.cpp +++ b/modules/authority/player_states.cpp @@ -1,26 +1,75 @@ #include "player_states.h" +#include "core/input/input.h" +#include "core/math/basis.h" +#include "scene/3d/camera_3d.h" +#include "scene/main/viewport.h" void PlayerInputState::_bind_methods() {} -void PlayerInputState::process(double delta) {} +void PlayerInputState::unhandled_input(Ref const &what) { + bool const is_move_vertical{ what->is_action("move_forward") || what->is_action("move_backward") }; + bool const is_move_horizontal{ what->is_action("move_right") || what->is_action("move_left") }; + if (is_move_vertical || is_move_horizontal) { + stack_state_dependent("PlayerMovementState"); + get_viewport()->set_input_as_handled(); + } +} -void PlayerInputState::_notification(int what) { +void PlayerInputState::state_entered() { + set_process_unhandled_input(true); +} + +void PlayerInputState::state_exited() { + set_process_unhandled_input(false); +} + +void PlayerMovementState::_bind_methods() {} + +void PlayerMovementState::process(double delta) { + Basis const basis{ get_viewport()->get_camera_3d()->get_global_basis() }; + Vector2 backward{ basis.get_column(0).x, basis.get_column(0).z }; + if (backward.is_zero_approx()) { + backward = Vector2{ basis.get_column(1).x, basis.get_column(1).z }; + } + Vector2 const right{ basis.get_column(2).x, basis.get_column(2).z }; + get_character()->set_movement((backward.normalized() * this->movement.x + right.normalized() * this->movement.y)); +} + +void PlayerMovementState::_notification(int what) { if (Engine::get_singleton()->is_editor_hint()) { return; } switch (what) { default: return; + case NOTIFICATION_READY: + set_process_input(true); + return; case NOTIFICATION_PROCESS: process(get_process_delta_time()); return; } } -void PlayerInputState::state_entered() { +void PlayerMovementState::input(Ref const &what) { + bool const is_move_vertical{ what->is_action("move_forward") || what->is_action("move_backward") }; + bool const is_move_horizontal{ what->is_action("move_right") || what->is_action("move_left") }; + if (is_move_vertical || is_move_horizontal) { + this->movement = { + Input::get_singleton()->get_axis("move_left", "move_right"), + Input::get_singleton()->get_axis("move_forward", "move_backward") + }; + this->movement.normalize(); + } + if (this->get_state_active() && this->movement.is_zero_approx()) { + set_state_active(false); + } +} + +void PlayerMovementState::state_entered() { set_process(true); } -void PlayerInputState::state_exited() { +void PlayerMovementState::state_exited() { set_process(false); } diff --git a/modules/authority/player_states.h b/modules/authority/player_states.h index 426e68b7..733725be 100644 --- a/modules/authority/player_states.h +++ b/modules/authority/player_states.h @@ -5,16 +5,11 @@ class PlayerInputState : public CharacterState { GDCLASS(PlayerInputState, CharacterState); static void _bind_methods(); - void process(double delta); protected: - void _notification(int what); void unhandled_input(Ref const &event) override; void state_entered() override; void state_exited() override; - -public: - Vector2 input{}; }; class PlayerMovementState : public CharacterState { @@ -24,6 +19,8 @@ class PlayerMovementState : public CharacterState { void process(double delta); protected: + void _notification(int what); + void input(Ref const &event) override; void state_entered() override; void state_exited() override; diff --git a/modules/authority/register_types.cpp b/modules/authority/register_types.cpp index d0bc0944..d0dab1c2 100644 --- a/modules/authority/register_types.cpp +++ b/modules/authority/register_types.cpp @@ -1,6 +1,7 @@ #include "register_types.h" #include "authority/character.h" +#include "authority/player_states.h" #include "core/object/class_db.h" void initialize_authority_module(ModuleInitializationLevel p_level) { @@ -10,6 +11,8 @@ void initialize_authority_module(ModuleInitializationLevel p_level) { ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); } void uninitialize_authority_module(ModuleInitializationLevel p_level) { diff --git a/project/data/default_player_character.tres b/project/data/default_player_character.tres index bba096d2..3fb998bd 100644 --- a/project/data/default_player_character.tres +++ b/project/data/default_player_character.tres @@ -1,4 +1,4 @@ [gd_resource type="CharacterData" format=3 uid="uid://bmudhddb0vedg"] [resource] -speed = 1.0 +speed = 2.0 diff --git a/project/objects/player_character.tscn b/project/objects/player_character.tscn index 73cf8ee3..f6736957 100644 --- a/project/objects/player_character.tscn +++ b/project/objects/player_character.tscn @@ -1,10 +1,13 @@ [gd_scene format=3 uid="uid://dcqd0wo5y5a1g"] +[ext_resource type="CharacterData" uid="uid://bmudhddb0vedg" path="res://data/default_player_character.tres" id="1_jy05a"] + [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_vcg8s"] [sub_resource type="CylinderMesh" id="CylinderMesh_5kd2n"] -[node name="PlayerCharacter" type="PlayerCharacter" unique_id=1435471129] +[node name="PlayerCharacter" type="Character" unique_id=1694717421] +data = ExtResource("1_jy05a") [node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=511026275] shape = SubResource("CapsuleShape3D_vcg8s") @@ -13,4 +16,10 @@ shape = SubResource("CapsuleShape3D_vcg8s") mesh = SubResource("CylinderMesh_5kd2n") [node name="Camera3D" type="Camera3D" parent="." unique_id=932811285] -transform = Transform3D(1, 0, 0, 0, 0.90373915, 0.42808357, 0, -0.42808357, 0.90373915, 0, 2.1840205, 3.7269862) +transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 9.536743e-07, 18.920525, -0.37265897) +current = true + +[node name="PlayerInputState" type="PlayerInputState" parent="." unique_id=1290843255] +start_active = true + +[node name="PlayerMovementState" type="PlayerMovementState" parent="." unique_id=71639209] diff --git a/project/scenes/test_world.tscn b/project/scenes/test_world.tscn index e8bf9677..f974d9d4 100644 --- a/project/scenes/test_world.tscn +++ b/project/scenes/test_world.tscn @@ -1,7 +1,6 @@ [gd_scene format=3 uid="uid://cv0ub3llm3jew"] [ext_resource type="PackedScene" uid="uid://dcqd0wo5y5a1g" path="res://objects/player_character.tscn" id="1_kyfjp"] -[ext_resource type="CharacterData" uid="uid://bmudhddb0vedg" path="res://data/default_player_character.tres" id="2_amxg5"] [sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_kyfjp"] sky_horizon_color = Color(0.66224277, 0.6717428, 0.6867428, 1) @@ -27,7 +26,6 @@ shadow_enabled = true [node name="PlayerCharacter" parent="." unique_id=1435471129 instance=ExtResource("1_kyfjp")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) -data = ExtResource("2_amxg5") [node name="CSGCombiner3D" type="CSGCombiner3D" parent="." unique_id=885387983] use_collision = true