Merge pull request 'improve error messages and checking' (#8) from feature/improve-state-machine into develop

Reviewed-on: #8
This commit is contained in:
Chris Cromer 2022-04-16 15:58:20 -04:00
commit 97e38b4b51
3 changed files with 113 additions and 27 deletions

View File

@ -25,12 +25,12 @@ void State::_init()
void State::_state_enter(const String state, const Array args) void State::_state_enter(const String state, const Array args)
{ {
WARN_PRINT("State " + state + " is missing its _state_enter method!"); WARN_PRINT("State " + get_state_machine()->get_current_state() + " is missing its _state_enter method!");
} }
void State::_state_exit(const String state, const Array args) void State::_state_exit(const String state, const Array args)
{ {
WARN_PRINT("State " + state + " is missing its _state_exit method!"); WARN_PRINT("State " + get_state_machine()->get_current_state() + " is missing its _state_exit method!");
} }
void State::set_parent(Node *parent) void State::set_parent(Node *parent)

View File

@ -34,7 +34,15 @@ void StateMachine::_ready()
connect("tree_entered", this, "_on_StateMachine_tree_entered"); connect("tree_entered", this, "_on_StateMachine_tree_entered");
connect("tree_exiting", this, "_on_StateMachine_tree_exiting"); connect("tree_exiting", this, "_on_StateMachine_tree_exiting");
parent = get_parent(); parent = get_parent();
set_current_state(get_default_state()); add_states();
if (has(get_default_state()))
{
set_current_state(get_default_state());
}
else
{
WARN_PRINT("The selected default state " + get_default_state() + " doesn't exist!");
}
setup(); setup();
} }
@ -46,13 +54,13 @@ void StateMachine::setup()
{ {
if (children.size() > 0) if (children.size() > 0)
{ {
WARN_PRINT("State machine doesn't have a default state set, using first child!"); WARN_PRINT("The state machine doesn't have a default state set, using first child!");
auto child = Object::cast_to<Node>(children[0].operator Object*()); auto child = Object::cast_to<Node>(children[0].operator Object*());
set_current_state(child->get_name()); set_current_state(child->get_name());
} }
else else
{ {
ERR_PRINT("State machine doesn't have a default state set and has no child states!"); ERR_PRINT("The state machine doesn't have a default state set and has no child states!");
return; return;
} }
} }
@ -60,7 +68,6 @@ void StateMachine::setup()
for (uint8_t i = 0; i < children.size(); i++) for (uint8_t i = 0; i < children.size(); i++)
{ {
auto child = Object::cast_to<Node>(children[i].operator Object*()); auto child = Object::cast_to<Node>(children[i].operator Object*());
add_state(child->get_name(), child);
child->call("set_state_machine", this); child->call("set_state_machine", this);
@ -72,7 +79,24 @@ void StateMachine::setup()
} }
} }
this->call("_state_enter", get_current_state()); Node *state_node = Object::cast_to<Node>(this->states[get_current_state()]);
if (state_node->has_method("_state_enter"))
{
this->call("_state_enter", get_current_state());
}
else {
WARN_PRINT("The state " + get_current_state() + " doesn't have a _state_enter method!");
}
}
void StateMachine::add_states()
{
auto children = get_children();
for (uint8_t i = 0; i < children.size(); i++)
{
auto child = Object::cast_to<Node>(children[i].operator Object*());
add_state(child->get_name(), child);
}
} }
void StateMachine::add_state(const String state, Node *child) void StateMachine::add_state(const String state, Node *child)
@ -111,8 +135,31 @@ void StateMachine::change(const String state, const Array &args)
return this->restart(state, args); return this->restart(state, args);
} }
if (!has(state))
{
WARN_PRINT("The state " + state + " does not exist, called from state " + get_current_state() + "!");
return;
}
auto previous_state = get_current_state(); auto previous_state = get_current_state();
auto exiting = this->call("_state_exit", state, args);
Variant exiting;
Node *state_node = Object::cast_to<Node>(this->states[previous_state]);
if (state_node)
{
if (state_node->has_method("_state_exit"))
{
exiting = this->call("_state_exit", state, args);
}
else
{
WARN_PRINT("The state " + get_current_state() + " doesn't have a _state_exit method!");
}
}
else
{
ERR_PRINT("Could not get current state node for " + get_current_state() + "!");
}
if (get_current_state() != "") if (get_current_state() != "")
{ {
@ -132,7 +179,23 @@ void StateMachine::change(const String state, const Array &args)
auto child = Object::cast_to<Node>(states[get_current_state()].operator Object*()); auto child = Object::cast_to<Node>(states[get_current_state()].operator Object*());
this->add_child(child); this->add_child(child);
this->call("_state_enter", previous_state, args); state_node = Object::cast_to<Node>(this->states[get_current_state()]);
if (state_node)
{
if (state_node->has_method("_state_enter"))
{
this->call("_state_enter", previous_state, args);
}
else
{
WARN_PRINT("The state " + get_current_state() + " doesn't have a _state_enter method!");
}
}
else
{
ERR_PRINT("Could not get current state node for " + get_current_state() + "!");
}
this->emit_signal("state_entered", get_current_state()); this->emit_signal("state_entered", get_current_state());
if (debug) if (debug)
{ {
@ -143,11 +206,23 @@ void StateMachine::change(const String state, const Array &args)
Variant StateMachine::call(const String method, const Array &args) Variant StateMachine::call(const String method, const Array &args)
{ {
auto node = Object::cast_to<Node>(states[get_current_state()].operator Object*()); auto node = Object::cast_to<Node>(states[get_current_state()].operator Object*());
if (node != nullptr) if (node)
{ {
return node->call(method, args); if (node->has_method(method))
{
return node->call(method, args);
}
else
{
WARN_PRINT("The state " + get_current_state() + " doesn't contain the method " + method + "!");
return Variant();
}
}
else
{
ERR_PRINT("Could not get current state node for " + get_current_state() + "!");
return Variant();
} }
return Variant();
} }
Variant StateMachine::_call(const String method, const Array &args) Variant StateMachine::_call(const String method, const Array &args)
@ -196,7 +271,7 @@ void StateMachine::_on_StateMachine_tree_exiting()
for (uint8_t i = 0; i < keys.size(); i++) for (uint8_t i = 0; i < keys.size(); i++)
{ {
auto child = Object::cast_to<Node>(states[keys[i]].operator Object*()); auto child = Object::cast_to<Node>(states[keys[i]].operator Object*());
if (child != nullptr) if (child)
{ {
auto children = get_children(); auto children = get_children();
if (!children.has(child)) if (!children.has(child))
@ -204,5 +279,10 @@ void StateMachine::_on_StateMachine_tree_exiting()
this->add_child(child); this->add_child(child);
} }
} }
else
{
ERR_PRINT("Could not get child node!");
return;
}
} }
} }

View File

@ -43,6 +43,12 @@ namespace godot
*/ */
Dictionary states; Dictionary states;
/**
* @brief This adds all nodes of the states machine as states in the machine.
*
*/
void add_states();
/** /**
* @brief This adds a state to the list of states in the state machine. * @brief This adds a state to the list of states in the state machine.
* *
@ -51,6 +57,13 @@ namespace godot
*/ */
void add_state(const String state, Node *child); void add_state(const String state, Node *child);
/**
* @brief Set the current state object.
*
* @param[in] current_state The current state that is running.
*/
void set_current_state(const String current_state);
public: public:
/** /**
* @brief This method registers classes with Godot. * @brief This method registers classes with Godot.
@ -157,6 +170,13 @@ namespace godot
*/ */
String get_default_state(); String get_default_state();
/**
* @brief Get the current state object.
*
* @return String The current running state.
*/
String get_current_state();
/** /**
* @brief Set the debug object. * @brief Set the debug object.
* *
@ -172,20 +192,6 @@ namespace godot
*/ */
bool get_debug(); bool get_debug();
/**
* @brief Set the current state object.
*
* @param[in] current_state The current state that is running.
*/
void set_current_state(const String current_state);
/**
* @brief Get the current state object.
*
* @return String The current running state.
*/
String get_current_state();
/** /**
* @brief This method is called when the signal tree_entered is emitted. * @brief This method is called when the signal tree_entered is emitted.
* *