tunnel-strategy/src/state_machine.cpp
2024-03-22 15:33:16 +01:00

63 lines
2 KiB
C++

#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();
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;
}
}