From 7c4c75d193e85af8d248c1f5d50f1daf69d33d87 Mon Sep 17 00:00:00 2001 From: Sara Date: Sat, 19 Jul 2025 20:06:42 +0200 Subject: [PATCH] feat: defined state and state machine concepts --- modules/wave_survival/register_types.cpp | 4 ++ modules/wave_survival/state.cpp | 16 +++++++ modules/wave_survival/state.h | 26 +++++++++++ modules/wave_survival/state_machine.cpp | 55 ++++++++++++++++++++++++ modules/wave_survival/state_machine.h | 23 ++++++++++ 5 files changed, 124 insertions(+) create mode 100644 modules/wave_survival/state.cpp create mode 100644 modules/wave_survival/state.h create mode 100644 modules/wave_survival/state_machine.cpp create mode 100644 modules/wave_survival/state_machine.h diff --git a/modules/wave_survival/register_types.cpp b/modules/wave_survival/register_types.cpp index 119988ef..0421b7e9 100644 --- a/modules/wave_survival/register_types.cpp +++ b/modules/wave_survival/register_types.cpp @@ -6,6 +6,8 @@ #include "wave_survival/player_body.h" #include "wave_survival/player_camera.h" #include "wave_survival/player_input.h" +#include "wave_survival/state.h" +#include "wave_survival/state_machine.h" #include "wave_survival/weapon_base.h" #include "wave_survival/weapon_inventory.h" #include "wave_survival/weapons/rifle.h" @@ -22,6 +24,8 @@ void initialize_wave_survival_module(ModuleInitializationLevel p_level) { GDREGISTER_CLASS(WeaponInventory); GDREGISTER_CLASS(HitscanMuzzle); GDREGISTER_CLASS(HealthStatus); + GDREGISTER_CLASS(StateMachine); + GDREGISTER_CLASS(State); } void uninitialize_wave_survival_module(ModuleInitializationLevel p_level) { diff --git a/modules/wave_survival/state.cpp b/modules/wave_survival/state.cpp new file mode 100644 index 00000000..93be0acd --- /dev/null +++ b/modules/wave_survival/state.cpp @@ -0,0 +1,16 @@ +#include "state.h" + +void State::_bind_methods() { +} + +String State::get_next_state() const { + return this->get_class(); +} + +void State::set_state_machine(StateMachine *machine) { + this->state_machine = machine; +} + +StateMachine *State::get_state_machine() const { + return this->state_machine; +} diff --git a/modules/wave_survival/state.h b/modules/wave_survival/state.h new file mode 100644 index 00000000..7792b106 --- /dev/null +++ b/modules/wave_survival/state.h @@ -0,0 +1,26 @@ +#ifndef STATE_H +#define STATE_H + +#include "core/object/class_db.h" +#include "core/object/object.h" +class StateMachine; +class Node; + +class State : public Object { + GDCLASS(State, Object); + static void _bind_methods(); + +public: + virtual void set_target(Node *target) {} + virtual void enter_state() {} + virtual void exit_state() {} + virtual void process(double delta) {} + virtual String get_next_state() const; + void set_state_machine(StateMachine *machine); + StateMachine *get_state_machine() const; + +private: + StateMachine *state_machine{ nullptr }; +}; + +#endif // !STATE_H diff --git a/modules/wave_survival/state_machine.cpp b/modules/wave_survival/state_machine.cpp new file mode 100644 index 00000000..82747718 --- /dev/null +++ b/modules/wave_survival/state_machine.cpp @@ -0,0 +1,55 @@ +#include "state_machine.h" +#include "state.h" + +void StateMachine::_bind_methods() {} + +void StateMachine::add_state(State *state) { + state->set_state_machine(this); + state->set_target(this->get_parent()); + this->states.insert(state->get_class(), state); + if (this->current_state == nullptr) { + this->switch_to_state(state); + } +} + +void StateMachine::switch_to_state(State *state) { + if (this->current_state) { + this->current_state->exit_state(); + } + this->current_state = state; + if (this->current_state) { + this->current_state->enter_state(); + } else { + print_error("StateMachine::switch_to_state: New state is nullptr, StateMachine will now stop working"); + } +} + +void StateMachine::ready() { +} + +void StateMachine::process(double delta) { + if (this->current_state) { + this->current_state->process(delta); + String new_state{ this->current_state->get_next_state() }; + if (new_state != this->current_state->get_class()) { + this->switch_to_state(this->states[new_state]); + } + } +} + +void StateMachine::_notification(int what) { + if (Engine::get_singleton()->is_editor_hint()) { + return; + } + switch (what) { + default: + return; + case NOTIFICATION_READY: + set_process(true); + ready(); + return; + case NOTIFICATION_PROCESS: + process(get_process_delta_time()); + return; + } +} diff --git a/modules/wave_survival/state_machine.h b/modules/wave_survival/state_machine.h new file mode 100644 index 00000000..81f961be --- /dev/null +++ b/modules/wave_survival/state_machine.h @@ -0,0 +1,23 @@ +#ifndef STATE_MACHINE_H +#define STATE_MACHINE_H + +#include "scene/main/node.h" +class State; + +class StateMachine : public Node { + GDCLASS(StateMachine, Node); + static void _bind_methods(); + void add_state(State *state); + void switch_to_state(State *state); + void ready(); + void process(double delta); + +protected: + void _notification(int what); + +private: + State *current_state{ nullptr }; + HashMap states{}; +}; + +#endif // !STATE_MACHINE_H