translated movement to state machine

This commit is contained in:
Sara Gerretsen 2025-12-31 12:19:30 +01:00
parent c3ff41e1e6
commit ea3b68aef8
9 changed files with 98 additions and 19 deletions

View file

@ -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;
}

View file

@ -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() {}

View file

@ -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<InputEvent> 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<InputEvent> 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);
}

View file

@ -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<InputEvent> 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<InputEvent> const &event) override;
void state_entered() override;
void state_exited() override;

View file

@ -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<CharacterData>();
ClassDB::register_class<Character>();
ClassDB::register_class<CharacterState>();
ClassDB::register_class<PlayerInputState>();
ClassDB::register_class<PlayerMovementState>();
}
void uninitialize_authority_module(ModuleInitializationLevel p_level) {