Implemented the transition system

Transitions being a way to allow for automatic state change and allow
for a way to allow or forbbid a transition between two states
This commit is contained in:
Erris 2025-04-21 10:41:58 +02:00
parent 5077c09d38
commit 7f441153ab
4 changed files with 63 additions and 62 deletions

54
include/state-machine_pool.hpp Normal file → Executable file
View File

@ -1,7 +1,12 @@
#ifndef STATEMACHINE_POOL_HPP #ifndef STATEMACHINE_POOL_HPP
#define STATEMACHINE_POOL_HPP #define STATEMACHINE_POOL_HPP
#include "state.hpp"
#include "state_machine.hpp" #include "state_machine.hpp"
#include <functional>
#include <iostream>
#include <ostream>
#include <unordered_map>
template<typename StateOwnerType> template<typename StateOwnerType>
class StateMachinePool { class StateMachinePool {
@ -15,17 +20,47 @@ class StateMachinePool {
machines.erase(id); machines.erase(id);
} }
void AddTransition(Transition<StateOwnerType> &transition) {
std::string from = transition.from;
std::string to = transition.target_state;
std::function <bool (const StateOwnerType&)> condition;
transitions[from].push_back(transition);
}
void UpdateAll() { void UpdateAll() {
for (const auto &[id, machine] : machines) for (const auto &[id, machine] : machines) {
auto &owner = machine->GetOwner();
const std::string &current = machine->GetCurrentStateId();
auto it = transitions.find(current);
if (it != transitions.end() && auto_transition == true)
for (const auto &transition : it->second)
if (transition.condition(owner)) {
machine->ChangeState(transition.target_state);
break;
}
machine->Update(); machine->Update();
} }
}
void ChangeState(const std::string &id, const std::string &stateId) { void ChangeState(const std::string &id, const std::string &stateId) {
auto it = machines.find(id); auto it = machines.find(id);
const std::string current = it->second->GetCurrentStateId();
auto &owner = it->second->GetOwner();
if (it != machines.end()) bool allowed = true;
auto transitions_it = transitions.find(current);
if (strict_transition && (transitions_it != transitions.end())) {
for (const auto &transition : transitions_it->second)
if (!transition.condition(owner))
allowed = false;
}
if (it != machines.end() && allowed) {
it->second->ChangeState(stateId); it->second->ChangeState(stateId);
} }
}
void RevertState(const std::string &id) { void RevertState(const std::string &id) {
auto it = machines.find(id); auto it = machines.find(id);
@ -88,17 +123,19 @@ class StateMachinePool {
} }
void SetStrictTransitions(bool enabled) { void SetStrictTransitions(bool enabled) {
strict_transition = enabled; this->strict_transition = enabled;
}
for (auto &[_, machine] : machines) bool GetStrictTransitions() const {
machine->SetStrictTransitions(enabled); return strict_transition;
} }
void SetAutoTransitions(bool enabled) { void SetAutoTransitions(bool enabled) {
auto_transition = enabled; this->auto_transition = enabled;
}
for (const auto &[_, machine] : machines) bool GetAutoTransitions() const {
machine->SetAutoTransitions(enabled); return auto_transition;
} }
private: private:
@ -106,6 +143,7 @@ class StateMachinePool {
std::unordered_map<std::string, std::unique_ptr<StateMachine<StateOwnerType>>> machines; std::unordered_map<std::string, std::unique_ptr<StateMachine<StateOwnerType>>> machines;
bool auto_transition = false; bool auto_transition = false;
bool strict_transition = false; bool strict_transition = false;
std::unordered_map<std::string, std::vector<Transition<StateOwnerType>>> transitions;
}; };
#endif // STATEMACHINE_POOL_HPP #endif // STATEMACHINE_POOL_HPP

View File

@ -7,6 +7,7 @@
template <typename Type> template <typename Type>
struct Transition { struct Transition {
const std::string from;
const std::string target_state; const std::string target_state;
const std::function<bool (const Type&)> condition; const std::function<bool (const Type&)> condition;
}; };
@ -20,10 +21,6 @@ class State {
virtual void OnUpdate(OwnerType &owner) = 0; virtual void OnUpdate(OwnerType &owner) = 0;
virtual void OnExit(OwnerType &owner) = 0; virtual void OnExit(OwnerType &owner) = 0;
virtual void AddTransition(const std::string &to,
std::function<bool (const OwnerType&)> condition) = 0;
virtual std::vector<Transition<OwnerType>> GetTransitions() = 0;
virtual std::string Id() const = 0; virtual std::string Id() const = 0;
}; };
@ -32,20 +29,11 @@ class AState : public State<OwnerType> {
public: public:
AState(const std::string &id) : entity_id(id) {}; AState(const std::string &id) : entity_id(id) {};
void AddTransition(const std::string &to,
std::function<bool (const OwnerType&)> condition) override {
transitions.push_back({ to, condition });
}
std::vector<Transition<OwnerType>> GetTransitions() override {
return transitions;
}
std::string Id() const override { std::string Id() const override {
return entity_id; return entity_id;
} }
private: private:
std::vector<Transition<OwnerType>> transitions;
std::string entity_id; std::string entity_id;
}; };

View File

@ -3,10 +3,12 @@
#include <string> #include <string>
#include <memory> #include <memory>
#include <unordered_map>
#include <vector> #include <vector>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include "state.hpp"
#include "state_factory.hpp" #include "state_factory.hpp"
using json = nlohmann::json; using json = nlohmann::json;
@ -21,19 +23,6 @@ class StateMachine {
if (!new_state) if (!new_state)
return; return;
if (strict_transition && current_state) {
bool allowed = false;
for (const auto &transition : current_state->GetTransitions()) {
if (transition.target_state == id &&
(!transition.condition || transition.condition(owner))) {
allowed = true;
break;
}
}
if (!allowed)
return;
}
if (current_state) { if (current_state) {
current_state->OnExit(owner); current_state->OnExit(owner);
history.push_back(current_state->Id()); history.push_back(current_state->Id());
@ -68,12 +57,6 @@ class StateMachine {
if (!current_state) if (!current_state)
return; return;
for (const auto &transition : current_state->GetTransitions())
if (auto_transition && transition.condition(owner)) {
ChangeState(transition.target_state);
return;
}
current_state->OnUpdate(owner); current_state->OnUpdate(owner);
} }
@ -91,32 +74,18 @@ class StateMachine {
} }
const std::string GetCurrentStateId() const { const std::string GetCurrentStateId() const {
static const std::string nullState = "null"; static const std::string nullState = "nullstate";
return current_state ? current_state->Id() : nullState; return current_state ? current_state->Id() : nullState;
} }
void SetStrictTransitions(bool enabled) { T &GetOwner() {
this->strict_transition = enabled; return owner;
}
bool GetStrictTransitions() const {
return strict_transition;
}
void SetAutoTransitions(bool enabled) {
this->auto_transition = enabled;
}
bool GetAutoTransitions() const {
return auto_transition;
} }
private: private:
T &owner; T &owner;
const StateFactory<T> &factory; const StateFactory<T> &factory;
std::shared_ptr<State<T>> current_state; std::shared_ptr<State<T>> current_state;
bool strict_transition = false;
bool auto_transition = false;
std::vector<std::string> history; std::vector<std::string> history;
}; };

View File

@ -1,6 +1,7 @@
#ifndef STATE_SYSTEM_HPP #ifndef STATE_SYSTEM_HPP
#define STATE_SYSTEM_HPP #define STATE_SYSTEM_HPP
#include "state.hpp"
#include "state_machine.hpp" #include "state_machine.hpp"
#include "state-machine_pool.hpp" #include "state-machine_pool.hpp"
@ -16,11 +17,6 @@ class StateSystem {
GetPool<T>().UnregisterEntity(id); GetPool<T>().UnregisterEntity(id);
} }
template <typename T>
void UpdateAll() {
GetPool<T>().UpdateAll();
}
template <typename T> template <typename T>
void ChangeState(const std::string &id, const std::string &stateId) { void ChangeState(const std::string &id, const std::string &stateId) {
GetPool<T>().ChangeState(id, stateId); GetPool<T>().ChangeState(id, stateId);
@ -37,6 +33,16 @@ class StateSystem {
GetPool<T>().RegisterState(id, std::move(state)); GetPool<T>().RegisterState(id, std::move(state));
} }
template <typename T>
void AddTransition(Transition<T> &transition) {
GetPool<T>().AddTransition(transition);
}
template <typename T>
void UpdateAll() {
GetPool<T>().UpdateAll();
}
template <typename T> template <typename T>
json Serialize() const { json Serialize() const {
StateMachinePool<T> &pool = GetPool<T>(); StateMachinePool<T> &pool = GetPool<T>();