feat: added state interface and state machine
This commit is contained in:
parent
6f62842746
commit
e5f70b1eb6
5
src/state.cpp
Normal file
5
src/state.cpp
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
#include "state.hpp"
|
||||||
|
#include "state_machine.hpp"
|
||||||
|
|
||||||
|
namespace godot {
|
||||||
|
}
|
19
src/state.hpp
Normal file
19
src/state.hpp
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef STATE_HPP
|
||||||
|
#define STATE_HPP
|
||||||
|
|
||||||
|
#include "godot_cpp/core/defs.hpp"
|
||||||
|
#include <godot_cpp/classes/node.hpp>
|
||||||
|
|
||||||
|
namespace godot {
|
||||||
|
class StateMachine;
|
||||||
|
|
||||||
|
class IState {
|
||||||
|
friend class StateMachine;
|
||||||
|
public:
|
||||||
|
virtual void init(Node *target, StateMachine *machine) = 0;
|
||||||
|
virtual StringName get_next() const = 0;
|
||||||
|
_ALWAYS_INLINE_ Node *as_node() { return dynamic_cast<Node*>(this); }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // !STATE_HPP
|
63
src/state_machine.cpp
Normal file
63
src/state_machine.cpp
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
#include "state_machine.hpp"
|
||||||
|
#include "state.hpp"
|
||||||
|
#include "utils/godot_macros.h"
|
||||||
|
#include <godot_cpp/classes/scene_tree.hpp>
|
||||||
|
#include <godot_cpp/variant/string_name.hpp>
|
||||||
|
#include <godot_cpp/variant/utility_functions.hpp>
|
||||||
|
|
||||||
|
namespace godot {
|
||||||
|
void StateMachine::_bind_methods() {
|
||||||
|
#define CLASSNAME StateMachine
|
||||||
|
GDPROPERTY(initial_state, Variant::STRING_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StateMachine::_enter_tree() { GDGAMEONLY();
|
||||||
|
this->override_state(this->initial_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StateMachine::_exit_tree() { GDGAMEONLY();
|
||||||
|
for(KeyValue<StringName, IState*> kvp : available)
|
||||||
|
if(!kvp.value->as_node()->is_inside_tree())
|
||||||
|
kvp.value->as_node()->queue_free();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StateMachine::_process(double delta_time) { GDGAMEONLY();
|
||||||
|
UtilityFunctions::print(this->get_path(), " _process");
|
||||||
|
if(this->state)
|
||||||
|
this->override_state(this->state->get_next());
|
||||||
|
}
|
||||||
|
|
||||||
|
void StateMachine::override_state(StringName next) {
|
||||||
|
// don't change state if target is current
|
||||||
|
if(this->state != nullptr && next == this->state->as_node()->get_class())
|
||||||
|
return;
|
||||||
|
if(this->state)
|
||||||
|
this->remove_child(this->state->as_node());
|
||||||
|
if(next.is_empty()) {
|
||||||
|
this->state = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// instantiate new state if this type is not yet available
|
||||||
|
if(!this->available.has(next)) {
|
||||||
|
IState *instance = dynamic_cast<IState*>(Object::cast_to<Node>(ClassDB::instantiate(next)));
|
||||||
|
if(instance == nullptr) {
|
||||||
|
UtilityFunctions::push_error("Failure to instantiate state with class '", next, "'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->available.insert(next, instance);
|
||||||
|
instance->init(this->get_parent(), this);
|
||||||
|
instance->as_node()->set_process_mode(ProcessMode::PROCESS_MODE_INHERIT);
|
||||||
|
}
|
||||||
|
// set the new state and add it to the tree
|
||||||
|
this->state = this->available.get(next);
|
||||||
|
this->add_child(this->state->as_node());
|
||||||
|
}
|
||||||
|
|
||||||
|
void StateMachine::set_initial_state(StringName name) {
|
||||||
|
this->initial_state = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName StateMachine::get_initial_state() const {
|
||||||
|
return this->initial_state;
|
||||||
|
}
|
||||||
|
}
|
30
src/state_machine.hpp
Normal file
30
src/state_machine.hpp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef STATE_MACHINE_HPP
|
||||||
|
#define STATE_MACHINE_HPP
|
||||||
|
|
||||||
|
#include <godot_cpp/variant/string_name.hpp>
|
||||||
|
#include <godot_cpp/classes/node.hpp>
|
||||||
|
#include <godot_cpp/templates/hash_map.hpp>
|
||||||
|
|
||||||
|
namespace godot {
|
||||||
|
class IState;
|
||||||
|
|
||||||
|
class StateMachine : public Node {
|
||||||
|
GDCLASS(StateMachine, Node);
|
||||||
|
static void _bind_methods();
|
||||||
|
public:
|
||||||
|
virtual void _enter_tree() override;
|
||||||
|
virtual void _exit_tree() override;
|
||||||
|
virtual void _process(double delta_time) override;
|
||||||
|
|
||||||
|
void override_state(StringName new_state_class);
|
||||||
|
|
||||||
|
void set_initial_state(StringName name);
|
||||||
|
StringName get_initial_state() const;
|
||||||
|
private:
|
||||||
|
String initial_state{};
|
||||||
|
IState *state{nullptr};
|
||||||
|
HashMap<StringName, IState*> available{};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // !STATE_MACHINE_HPP
|
Loading…
Reference in a new issue