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:
parent
5077c09d38
commit
7f441153ab
54
include/state-machine_pool.hpp
Normal file → Executable file
54
include/state-machine_pool.hpp
Normal file → Executable 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,16 +20,46 @@ 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 ¤t = 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) {
|
||||||
@ -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
|
||||||
|
|||||||
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -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>();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user