A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
StateManager.hh
1#pragma once
2
3#include "game/field/obj/ObjectBase.hh"
4
5#include <type_traits>
6
7namespace Field {
8
9template <typename T>
11 using StateEnterFunc = void (T::*)();
12 using StateCalcFunc = void (T::*)();
13
14 u16 id;
15 StateEnterFunc onEnter;
16 StateCalcFunc onCalc;
17};
18
19template <typename T>
21public:
22 StateManager(T *obj);
23
24 virtual ~StateManager() {
25 delete[] m_entryIds.data();
26 }
27
28protected:
29 void calc() {
30 if (m_nextStateId >= 0) {
31 m_currentStateId = m_nextStateId;
32 m_nextStateId = -1;
33 m_currentFrame = 0;
34
35 auto enterFunc = m_entries[m_entryIds[m_currentStateId]].onEnter;
36 (m_obj->*enterFunc)();
37 } else {
38 ++m_currentFrame;
39 }
40
41 auto calcFunc = m_entries[m_entryIds[m_currentStateId]].onCalc;
42 (m_obj->*calcFunc)();
43 }
44
45 u16 m_currentStateId;
46 s32 m_nextStateId;
47 u32 m_currentFrame;
48 std::span<u16> m_entryIds;
49 std::span<const StateManagerEntry<T>> m_entries;
50 T *m_obj;
51};
52
54template <typename T>
56 : m_currentStateId(0), m_nextStateId(-1), m_currentFrame(0), m_obj(obj) {
57 // Concepts don't work here due to CRTP causing incomplete class type use.
58 STATIC_ASSERT((std::is_base_of_v<ObjectBase, T>));
59 STATIC_ASSERT((std::is_same_v<decltype(T::STATE_ENTRIES),
60 const std::array<StateManagerEntry<T>, T::STATE_ENTRIES.size()>>));
61
62 m_entryIds = std::span(new u16[T::STATE_ENTRIES.size()], T::STATE_ENTRIES.size());
63
64 // The base game initializes all entries to 0xffff, possibly to avoid an uninitialized value
65 for (auto &id : m_entryIds) {
66 id = 0xffff;
67 }
68
69 for (size_t i = 0; i < m_entryIds.size(); ++i) {
70 m_entryIds[T::STATE_ENTRIES[i].id] = i;
71 }
72
73 m_entries = std::span<const StateManagerEntry<T>>(T::STATE_ENTRIES);
74}
75
76} // namespace Field
StateManager(T *obj)
Defined outside of the class declaration so that typename T will be a complete type.
Pertains to collision.