generated from Sigmarik/cpp-template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
scene_component.h
211 lines (173 loc) · 5.41 KB
/
scene_component.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
/**
* @file scene_component.h
* @author Kudryashov Ilya ([email protected])
* @brief Scene component module
* @version 0.1
* @date 2023-12-29
*
* @copyright Copyright (c) 2023
*
*/
#pragma once
#include <concepts>
#include <memory>
#include <string>
#include <unordered_map>
#include "events.h"
#include "graphics/objects/scene.h"
#include "hash/guid.h"
#include "memory/relative_ptr.hpp"
#include "physics/level_geometry.h"
#include "subcomponent.hpp"
struct Scene;
struct SceneComponent {
friend struct Scene;
//! TODO: Replace with multievents to allow for multiple senders.
using Channel = Event<const std::string&>;
using OutputChannel = Channel;
using InputChannel = Channel::Multilistener;
enum class EndPlayReason {
Destroyed,
Crashed,
Quit,
};
SceneComponent();
SceneComponent(const SceneComponent&) = delete;
SceneComponent& operator=(const SceneComponent&) = delete;
SceneComponent(SceneComponent&&) = delete;
SceneComponent& operator=(SceneComponent&&) = delete;
virtual ~SceneComponent() = default;
virtual void phys_tick(double delta_time) {}
virtual void draw_tick(double delta_time, double subtick_time = 0.0) {}
/**
* @brief Request a destroyed event of the component that is triggered when
* the component gets destroyed
*
* @return Event<EndPlayReason>&
*/
Event<EndPlayReason>& get_destroyed_event() { return destroyed_event_; }
GUID get_guid() const { return guid_; }
/**
* @brief Check if the component is bound to a scene and alive
*
* @return true
* @return false
*/
bool is_valid() const;
/**
* @brief Get the owning scene of the component
*
* @warning Should only be called on `valid` components
*
* @return Scene&
*/
Scene& get_scene() const;
bool has_scene() const { return scene_ != nullptr; }
/**
* @brief Destroy the component and remove it from the scene
*
* @param[in] reason
*/
void destroy(EndPlayReason reason = EndPlayReason::Destroyed);
OutputChannel* get_output(const std::string& name);
InputChannel* get_input(const std::string& name);
/**
* @brief Capture component state for restoration
*
* @warning Implementation of this method is entirely optional, component
* may choose not to capture its current state
*/
virtual void capture() {}
/**
* @brief Reset component to its previously captured state
*
* @warning Implementation of this method is entirely optional, component
* may choose not to reset itself
*/
virtual void reset() {}
protected:
Event<Scene&>& get_spawned_event() { return spawned_event_; }
/**
* @brief A function that is called when the component gets added to a scene
*
* @param[in] scene owning scene
*/
virtual void begin_play(Scene& scene);
/**
* @brief A function that is called when the component gets removed from the
* scene
*
* @param[in] reason removal reason
*/
virtual void end_play(EndPlayReason reason) {}
/**
* @brief Subscribe the component to physics tick events
*
* @see `begin_play` method
*
* @warning Should be called after parent initialization in `begin_play`
*/
void receive_phys_ticks();
/**
* @brief Subscribe the component to graphics tick events
*
* @see `begin_play` method
*
* @warning Should be called after parent initialization in `begin_play`
*/
void receive_draw_ticks();
/**
* @brief Register an abstract output channel of the component
*
* @warning `output` must refer to a class member
*
* @param[in] name name of the channel
* @param[in] output output channel member
*/
void register_output(const std::string& name, OutputChannel& output);
/**
* @brief Register abstract input channel listener of the component
*
* @warning `input` must refer to a class member
*
* @param[in] name name of the channel
* @param[in] input channel listener member
*/
void register_input(const std::string& name, InputChannel& input);
/**
* @brief Construct a child object
*
* @tparam T child type
* @tparam Ts child constructions arguments
* @param[in] args
* @return Subcomponent<T> child
*/
template <class T, class... Ts>
requires std::derived_from<T, SceneComponent>
Subcomponent<T> new_child(Ts&&... args);
/**
* @brief Attach a child to the component
*
* @param[in] child child component
*/
void attach(Subcomponent<SceneComponent> child);
private:
GUID guid_;
Scene* scene_ = nullptr;
bool alive_ = false;
TickEvent::Listener phys_ticker_{};
SubtickEvent::Listener draw_ticker_{};
Event<Scene&> spawned_event_{};
Event<EndPlayReason> destroyed_event_{};
Event<Scene&>::Listener parent_spawned_listener_{};
Event<EndPlayReason>::Listener parent_destroyed_listener_{};
std::unordered_map<std::string, RelativePtr<OutputChannel>> outputs_{};
std::unordered_map<std::string, RelativePtr<InputChannel>> inputs_{};
};
template <class T, class... Ts>
requires std::derived_from<T, SceneComponent>
inline Subcomponent<T> SceneComponent::new_child(Ts&&... args) {
Subcomponent<T> child(args...);
attach(child);
return child;
}