CoriEngine
Loading...
Searching...
No Matches
StateSystem/StateMachine.hpp
Go to the documentation of this file.
1#pragma once
2#include "EntityState.hpp"
4
5namespace Cori {
6 namespace World {
7 namespace Systems {
8 class StateMachine;
9 }
10
11 namespace Components {
12 namespace Entity {
23 public:
24 StateMachine() = default;
25
27 if (m_CurrentState) {
28 m_CurrentState->OnExit(m_Owner, typeid(nullptr));
29 }
30 }
31
32 StateMachine(const StateMachine&) = delete;
36
43 template<std::derived_from<EntityState> StateType, typename... Args>
44 void Register(Args&&... args) {
45 const std::type_index stateID(typeid(StateType));
46
47 if (m_States.contains(stateID)) {
48 CORI_CORE_WARN_TAGGED({ Logger::Tags::World::Self, Logger::Tags::World::Entity::Self, Logger::Tags::World::Entity::StateMachine }, "StateMachine for Entity - {}: State type '{}' already registered.", m_Owner.GetDebugData(), CORI_CLEAN_TYPE_NAME(*m_CurrentState));
49 return;
50 }
51
52 m_States[stateID] = std::make_unique<StateType>(std::forward<Args>(args)...);
53 CORI_CORE_TRACE_TAGGED({ Logger::Tags::World::Self, Logger::Tags::World::Entity::Self, Logger::Tags::World::Entity::StateMachine }, "StateMachine for Entity - {}: Registered state '{}'", m_Owner.GetDebugData(), CORI_CLEAN_TYPE_NAME(StateType));
54 }
55
60 template<std::derived_from<EntityState> StateType>
61 void SetState() {
62 const std::type_index nextStateID(typeid(StateType));
63
64 if (CORI_CORE_CHECK(m_States.contains(nextStateID), "StateMachine for Entity - {}: Attempted to change to unregistered state type '{}', register the State first!", m_Owner.GetDebugData(), CORI_CLEAN_TYPE_NAME(StateType))) { return; }
65
66 EntityState* nextStateRawPtr = m_States.at(nextStateID).get();
67
68 if (m_CurrentState == nextStateRawPtr) {
69 return;
70 }
71
72 if (m_CurrentState) {
73 CORI_CORE_TRACE_TAGGED({ Logger::Tags::World::Self, Logger::Tags::World::Entity::Self, Logger::Tags::World::Entity::StateMachine }, "StateMachine for Entity - {}: Exiting state '{}'", m_Owner.GetDebugData(), CORI_CLEAN_TYPE_NAME(*m_CurrentState));
74 m_CurrentState->OnExit(m_Owner, typeid(*nextStateRawPtr));
75 }
76
77 if (m_LastState) {
78 m_LastState = m_CurrentState;
79 } else {
80 m_LastState = nextStateRawPtr;
81 }
82
83 m_CurrentState = nextStateRawPtr;
84 CORI_CORE_TRACE_TAGGED({ Logger::Tags::World::Self, Logger::Tags::World::Entity::Self, Logger::Tags::World::Entity::StateMachine }, "StateMachine for Entity - {}: Entering state '{}'", m_Owner.GetDebugData(), CORI_CLEAN_TYPE_NAME(*m_CurrentState));
85 m_CurrentState->OnEnter(m_Owner, typeid(*m_LastState));
86 }
87
88 void OnTickUpdate(const float timeStep) {
89 if (m_CurrentState) {
90 m_CurrentState->OnTickUpdate(m_Owner, timeStep);
91 }
92 }
93
99 template<std::derived_from<EntityState> StateType>
100 bool IsInState() const {
101 if (!m_CurrentState) {
102 return false;
103 }
104
105 return typeid(StateType) == typeid(*m_CurrentState);
106 }
107
112 template<std::derived_from<EntityState> StateType>
114 if (!IsInState<StateType>()) {
115 return SetState<StateType>();
116 }
117 }
118
124 CORI_CORE_ASSERT(m_CurrentState, "Trying to retrieve current state, but current state is null. Always make sure you set some initial state before using fsm.")
125 return m_CurrentState;
126 }
127
133 CORI_CORE_ASSERT(m_LastState, "Trying to retrieve last state, but last state is null. Always make sure you set some initial state before using fsm.")
134 return m_LastState;
135 }
136
137 private:
139 World::Entity m_Owner;
140 EntityState* m_CurrentState{ nullptr };
141 EntityState* m_LastState{ nullptr };
142
143 std::unordered_map<std::type_index, std::unique_ptr<EntityState>> m_States;
144 };
145 }
146 }
147 }
148}
#define CORI_CLEAN_TYPE_NAME(tn)
#define CORI_CORE_CHECK(x,...)
Definition Logger.hpp:1042
#define CORI_CORE_ASSERT(x,...)
Definition Logger.hpp:1029
#define CORI_CORE_TRACE_TAGGED(...)
Definition Logger.hpp:1025
#define CORI_CORE_WARN_TAGGED(...)
Definition Logger.hpp:1038
void SetStateIfNotInState()
Sets an Entity to the state only if it is not currently in that state.
StateMachine & operator=(StateMachine &&)=delete
bool IsInState() const
Cheks if an Entity is in a specific state.
void SetState()
Changes the current state to the specified one.
EntityState * GetLastState() const
Gets the pointer to the last state. Can be used to get the type_info of the last state.
EntityState * GetCurrentState() const
Gets the pointer to the current state. Can be used to get the type_info of the current state.
StateMachine(const StateMachine &)=delete
StateMachine & operator=(const StateMachine &)=delete
void Register(Args &&... args)
Registers an EntityState with a StateMachine, you need to register a state before using it.
An abstract class designed to be used with StateMachine component.
Entities are the essential part of WorldSystem.
Definition Entity.hpp:25
Components designed to be used with entities.
Components that are used with the WorldSystem (ECS).
Anything connected to WorldSystem (ECS) is in this namespace.
Global engine namespace.
static constexpr char Self[]
Definition Logger.hpp:127
static constexpr char StateMachine[]
Definition Logger.hpp:130
static constexpr char Self[]
Definition Logger.hpp:119