summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt4
-rw-r--r--src/algorithms.h12
-rw-r--r--src/components/sprite_renderable.cpp27
-rw-r--r--src/components/sprite_renderable.h25
-rw-r--r--src/components/transformable.cpp47
-rw-r--r--src/components/transformable.h27
-rw-r--r--src/entity_manager.cpp38
-rw-r--r--src/entity_manager.h169
-rw-r--r--src/main.cpp25
-rw-r--r--src/system.h11
-rw-r--r--src/systems/rendering.cpp21
-rw-r--r--src/systems/rendering.h16
12 files changed, 270 insertions, 152 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 5dfce6f..2bfde77 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -49,6 +49,10 @@ add_executable(Aromatherapy
49 src/main.cpp 49 src/main.cpp
50 src/renderer.cpp 50 src/renderer.cpp
51 src/muxer.cpp 51 src/muxer.cpp
52 src/entity_manager.cpp
53 src/components/sprite_renderable.cpp
54 src/components/transformable.cpp
55 src/systems/rendering.cpp
52) 56)
53target_link_libraries(Aromatherapy ${ALL_LIBS}) 57target_link_libraries(Aromatherapy ${ALL_LIBS})
54install(TARGETS Aromatherapy RUNTIME DESTINATION ${BIN_DIR}) 58install(TARGETS Aromatherapy RUNTIME DESTINATION ${BIN_DIR})
diff --git a/src/algorithms.h b/src/algorithms.h new file mode 100644 index 0000000..80e3e27 --- /dev/null +++ b/src/algorithms.h
@@ -0,0 +1,12 @@
1#ifndef ALGORITHMS_H_1DDC517E
2#define ALGORITHMS_H_1DDC517E
3
4template< typename ContainerT, typename PredicateT >
5void erase_if( ContainerT& items, const PredicateT& predicate ) {
6 for( auto it = items.begin(); it != items.end(); ) {
7 if( predicate(*it) ) it = items.erase(it);
8 else ++it;
9 }
10};
11
12#endif /* end of include guard: ALGORITHMS_H_1DDC517E */
diff --git a/src/components/sprite_renderable.cpp b/src/components/sprite_renderable.cpp new file mode 100644 index 0000000..4c61111 --- /dev/null +++ b/src/components/sprite_renderable.cpp
@@ -0,0 +1,27 @@
1#include "sprite_renderable.h"
2
3SpriteRenderableComponent::SpriteRenderableComponent(const char* filename, int frame_width, int frame_height, int frames_across)
4 : texture(filename), frame_width(frame_width), frame_height(frame_height), frames_across(frames_across)
5{
6
7}
8
9int SpriteRenderableComponent::getFrame() const
10{
11 return frame;
12}
13
14void SpriteRenderableComponent::setFrame(int frame)
15{
16 this->frame = frame;
17}
18
19const Texture& SpriteRenderableComponent::getTexture() const
20{
21 return texture;
22}
23
24Rectangle SpriteRenderableComponent::getFrameRect() const
25{
26 return {frame_width * (frame % frames_across), frame_height * (frame / frames_across), frame_width, frame_height};
27}
diff --git a/src/components/sprite_renderable.h b/src/components/sprite_renderable.h new file mode 100644 index 0000000..b4465c3 --- /dev/null +++ b/src/components/sprite_renderable.h
@@ -0,0 +1,25 @@
1#ifndef SPRITE_RENDERABLE_H_D3AACBBF
2#define SPRITE_RENDERABLE_H_D3AACBBF
3
4#include "component.h"
5#include "renderer.h"
6
7class SpriteRenderableComponent : public Component {
8 public:
9 SpriteRenderableComponent(const char* filename, int frame_width, int frame_height, int frames_across);
10
11 int getFrame() const;
12 void setFrame(int frame);
13
14 const Texture& getTexture() const;
15 Rectangle getFrameRect() const;
16
17 private:
18 Texture texture;
19 int frame_width;
20 int frame_height;
21 int frames_across;
22 int frame = 0;
23};
24
25#endif /* end of include guard: SPRITE_RENDERABLE_H_D3AACBBF */
diff --git a/src/components/transformable.cpp b/src/components/transformable.cpp new file mode 100644 index 0000000..0d6b67e --- /dev/null +++ b/src/components/transformable.cpp
@@ -0,0 +1,47 @@
1#include "transformable.h"
2
3TransformableComponent::TransformableComponent(double x, double y, int w, int h)
4 : x(x), y(y), w(w), h(h)
5{
6
7}
8
9double TransformableComponent::getX() const
10{
11 return x;
12}
13
14double TransformableComponent::getY() const
15{
16 return y;
17}
18
19int TransformableComponent::getW() const
20{
21 return w;
22}
23
24int TransformableComponent::getH() const
25{
26 return h;
27}
28
29void TransformableComponent::setX(double v)
30{
31 x = v;
32}
33
34void TransformableComponent::setY(double v)
35{
36 y = v;
37}
38
39void TransformableComponent::setW(int v)
40{
41 w = v;
42}
43
44void TransformableComponent::setH(int v)
45{
46 h = v;
47}
diff --git a/src/components/transformable.h b/src/components/transformable.h new file mode 100644 index 0000000..87ba84d --- /dev/null +++ b/src/components/transformable.h
@@ -0,0 +1,27 @@
1#ifndef LOCATABLE_H_39E526CA
2#define LOCATABLE_H_39E526CA
3
4#include "component.h"
5
6class TransformableComponent : public Component {
7 public:
8 TransformableComponent(double x, double y, int w, int h);
9
10 double getX() const;
11 double getY() const;
12 int getW() const;
13 int getH() const;
14
15 void setX(double v);
16 void setY(double v);
17 void setW(int v);
18 void setH(int v);
19
20 private:
21 double x;
22 double y;
23 int w;
24 int h;
25};
26
27#endif /* end of include guard: LOCATABLE_H_39E526CA */
diff --git a/src/entity_manager.cpp b/src/entity_manager.cpp new file mode 100644 index 0000000..4bdfe8a --- /dev/null +++ b/src/entity_manager.cpp
@@ -0,0 +1,38 @@
1#ifndef ENTITY_MANAGER_CPP_42D78C22
2#define ENTITY_MANAGER_CPP_42D78C22
3
4#include "entity_manager.h"
5
6template <>
7std::set<int> EntityManager::getEntitiesWithComponents<>(std::set<std::type_index>& componentTypes)
8{
9 if (cachedComponents.count(componentTypes) == 1)
10 {
11 return cachedComponents[componentTypes];
12 }
13
14 std::set<int>& cache = cachedComponents[componentTypes];
15 for (auto& entity : entities)
16 {
17 EntityData& data = entity.second;
18 bool cacheEntity = true;
19
20 for (auto& componentType : componentTypes)
21 {
22 if (data.components.count(componentType) == 0)
23 {
24 cacheEntity = false;
25 break;
26 }
27 }
28
29 if (cacheEntity)
30 {
31 cache.insert(entity.first);
32 }
33 }
34
35 return cache;
36}
37
38#endif /* end of include guard: ENTITY_MANAGER_CPP_42D78C22 */
diff --git a/src/entity_manager.h b/src/entity_manager.h index 74e758c..5f0f2d4 100644 --- a/src/entity_manager.h +++ b/src/entity_manager.h
@@ -6,70 +6,31 @@
6#include <set> 6#include <set>
7#include <cassert> 7#include <cassert>
8#include "component.h" 8#include "component.h"
9#include "algorithms.h"
9 10
10class EntityManager { 11class EntityManager {
11 private: 12 private:
12 struct EntityData { 13 struct EntityData {
13 int parent = -1;
14 std::map<std::type_index, std::unique_ptr<Component>> components; 14 std::map<std::type_index, std::unique_ptr<Component>> components;
15 }; 15 };
16 16
17 std::map<int, EntityData> entities; 17 std::map<int, EntityData> entities;
18 std::map<int, std::set<int>> cachedChildren;
19 std::map<std::set<std::type_index>, std::set<int>> cachedComponents; 18 std::map<std::set<std::type_index>, std::set<int>> cachedComponents;
20 19
21 int nextEntityID = 0; 20 int nextEntityID = 0;
22 21
23 bool ensureNoParentCycles(int entity, int parent) 22 template <class T, class... R>
23 std::set<int> getEntitiesWithComponentsHelper(std::set<std::type_index>& componentTypes)
24 { 24 {
25 EntityData& data = entities[parent]; 25 componentTypes.insert(typeid(T));
26 if (data.parent == entity)
27 {
28 return false;
29 } else if (data.parent == -1)
30 {
31 return true;
32 }
33 26
34 return ensureNoParentCycles(entity, data.parent); 27 return getEntitiesWithComponents<R...>(componentTypes);
35 } 28 }
36 29
30 template <class... R>
37 std::set<int> getEntitiesWithComponents(std::set<std::type_index>& componentTypes) 31 std::set<int> getEntitiesWithComponents(std::set<std::type_index>& componentTypes)
38 { 32 {
39 if (cachedComponents.count(componentTypes) == 1) 33 return getEntitiesWithComponentsHelper<R...>(componentTypes);
40 {
41 return cachedComponents[componentTypes];
42 }
43
44 std::set<int>& cache = cachedComponents[componentTypes];
45 for (auto& entity : entities)
46 {
47 EntityData& data = entity.second;
48 bool cacheEntity = true;
49
50 for (auto& componentType : componentTypes)
51 {
52 if (data.components.count(componentType) == 0)
53 {
54 cacheEntity = false;
55 break;
56 }
57 }
58
59 if (cacheEntity)
60 {
61 cache.insert(entity.first);
62 }
63 }
64
65 return cache;
66 }
67
68 template <class T, class... R> std::set<int> getEntitiesWithComponents(std::set<std::type_index>& componentTypes)
69 {
70 componentTypes.insert(typeid(T));
71
72 return getEntitiesWithComponents<R...>(componentTypes);
73 } 34 }
74 35
75 public: 36 public:
@@ -107,26 +68,6 @@ class EntityManager {
107 { 68 {
108 assert(entities.count(entity) == 1); 69 assert(entities.count(entity) == 1);
109 70
110 EntityData& data = entities[entity];
111
112 // Destroy the children
113 std::set<int> children = getChildren(entity);
114 for (int child : children)
115 {
116 EntityData& childData = entities[child];
117 childData.parent = -1;
118
119 deleteEntity(child);
120 }
121
122 // Uncache children
123 cachedChildren.erase(entity);
124
125 if ((data.parent != -1) && (cachedChildren.count(data.parent) == 1))
126 {
127 cachedChildren[data.parent].erase(entity);
128 }
129
130 // Uncache components 71 // Uncache components
131 for (auto& cache : cachedComponents) 72 for (auto& cache : cachedComponents)
132 { 73 {
@@ -137,81 +78,8 @@ class EntityManager {
137 entities.erase(entity); 78 entities.erase(entity);
138 } 79 }
139 80
140 std::set<int> getChildren(int parent) 81 template <class T, class... Args>
141 { 82 T& emplaceComponent(int entity, Args&&... args)
142 assert(entities.count(parent) == 1);
143
144 if (cachedChildren.count(parent) == 1)
145 {
146 return cachedChildren[parent];
147 }
148
149 std::set<int>& cache = cachedChildren[parent];
150 for (auto& entity : entities)
151 {
152 EntityData& data = entity.second;
153 if (data.parent == parent)
154 {
155 cache.insert(entity.first);
156 }
157 }
158
159 return cache;
160 }
161
162 void setParent(int entity, int parent)
163 {
164 assert(entities.count(entity) == 1);
165 assert(entities.count(parent) == 1);
166 assert(ensureNoParentCycles(entity, parent));
167
168 EntityData& data = entities[entity];
169
170 // Remove from old parent
171 if (data.parent != -1)
172 {
173 if (cachedChildren.count(data.parent) == 1)
174 {
175 cachedChildren[data.parent].erase(entity);
176 }
177 }
178
179 data.parent = parent;
180
181 // Cache new parent
182 if (cachedChildren.count(parent) == 1)
183 {
184 cachedChildren[parent].insert(entity);
185 }
186 }
187
188 void setNoParent(int entity)
189 {
190 assert(entities.count(entity) == 1);
191
192 EntityData& data = entities[entity];
193
194 // Remove from old parent
195 if (data.parent != -1)
196 {
197 if (cachedChildren.count(data.parent) == 1)
198 {
199 cachedChildren[data.parent].erase(entity);
200 }
201 }
202
203 data.parent = -1;
204 }
205
206 int getParent(int entity)
207 {
208 assert(entities.count(entity) == 1);
209
210 EntityData& data = entities[entity];
211 return data.parent;
212 }
213
214 template <class T, class... Args> T& emplaceComponent(int entity, Args&&... args)
215 { 83 {
216 assert(entities.count(entity) == 1); 84 assert(entities.count(entity) == 1);
217 85
@@ -226,14 +94,15 @@ class EntityManager {
226 data.components[componentType] = std::move(ptr); 94 data.components[componentType] = std::move(ptr);
227 95
228 // Invalidate related caches 96 // Invalidate related caches
229 std::remove_if(begin(cachedComponents), end(cachedComponents), [&] (std::pair<std::set<std::type_index>, int>& cache) { 97 erase_if(cachedComponents, [&componentType] (std::pair<const std::set<std::type_index>, std::set<int>>& cache) {
230 return cache.first.count(componentType) == 1; 98 return cache.first.count(componentType) == 1;
231 }); 99 });
232 100
233 return component; 101 return component;
234 } 102 }
235 103
236 template <class T> void removeComponent(int entity) 104 template <class T>
105 void removeComponent(int entity)
237 { 106 {
238 assert(entities.count(entity) == 1); 107 assert(entities.count(entity) == 1);
239 108
@@ -255,7 +124,8 @@ class EntityManager {
255 } 124 }
256 } 125 }
257 126
258 template <class T> T& getComponent(int entity) 127 template <class T>
128 T& getComponent(int entity)
259 { 129 {
260 assert(entities.count(entity) == 1); 130 assert(entities.count(entity) == 1);
261 131
@@ -264,16 +134,19 @@ class EntityManager {
264 134
265 assert(data.components.count(componentType) == 1); 135 assert(data.components.count(componentType) == 1);
266 136
267 return *(data.components[componentType]); 137 return *((T*)data.components[componentType].get());
268 } 138 }
269 139
270 template <class T, class... R> std::set<int> getEntitiesWithComponents() 140 template <class... R>
141 std::set<int> getEntitiesWithComponents()
271 { 142 {
272 std::set<std::type_index> componentTypes; 143 std::set<std::type_index> componentTypes;
273 componentTypes.insert(typeid(T));
274 144
275 return getEntitiesWithComponents<R...>(componentTypes); 145 return getEntitiesWithComponentsHelper<R...>(componentTypes);
276 } 146 }
277}; 147};
278 148
149template <>
150std::set<int> EntityManager::getEntitiesWithComponents<>(std::set<std::type_index>& componentTypes);
151
279#endif /* end of include guard: ENTITY_MANAGER_H_C5832F11 */ 152#endif /* end of include guard: ENTITY_MANAGER_H_C5832F11 */
diff --git a/src/main.cpp b/src/main.cpp index 29a364b..dcf8d87 100644 --- a/src/main.cpp +++ b/src/main.cpp
@@ -4,22 +4,39 @@
4#include "renderer.h" 4#include "renderer.h"
5#include "muxer.h" 5#include "muxer.h"
6#include "entity_manager.h" 6#include "entity_manager.h"
7#include "components/sprite_renderable.h"
8#include "components/transformable.h"
9#include "systems/rendering.h"
7 10
8int main() 11int main()
9{ 12{
10 srand(time(NULL)); 13 srand(time(NULL));
11 14
12 GLFWwindow* window = initRenderer(); 15 GLFWwindow* window = initRenderer();
16 glfwSwapInterval(1);
17
13 initMuxer(); 18 initMuxer();
14 19
15 // Put this in a block so game goes out of scope before we destroy the renderer 20 // Put this in a block so game goes out of scope before we destroy the renderer
16 { 21 {
17 EntityManager manager; 22 EntityManager manager;
18 23
19 int eRef = manager.emplaceEntity(); 24 int player = manager.emplaceEntity();
20 int eRef2 = manager.emplaceEntity(); 25 manager.emplaceComponent<SpriteRenderableComponent>(player, "res/Starla.png", 10, 12, 6);
21 manager.setParent(eRef, eRef2); 26 manager.emplaceComponent<TransformableComponent>(player, 203, 44, 10, 12);
22 printf("%d\n", manager.getParent(eRef)); 27
28 std::list<std::unique_ptr<System>> loop;
29 loop.push_back(std::unique_ptr<System>(new RenderingSystem()));
30
31 while (!glfwWindowShouldClose(window))
32 {
33 for (auto& sys : loop)
34 {
35 sys->tick(manager, 1.0);
36 }
37
38 glfwPollEvents();
39 }
23 } 40 }
24 41
25 destroyMuxer(); 42 destroyMuxer();
diff --git a/src/system.h b/src/system.h new file mode 100644 index 0000000..85415f0 --- /dev/null +++ b/src/system.h
@@ -0,0 +1,11 @@
1#ifndef SYSTEM_H_B61A8CEA
2#define SYSTEM_H_B61A8CEA
3
4class EntityManager;
5
6class System {
7 public:
8 virtual void tick(EntityManager& manager, float dt) = 0;
9};
10
11#endif /* end of include guard: SYSTEM_H_B61A8CEA */
diff --git a/src/systems/rendering.cpp b/src/systems/rendering.cpp new file mode 100644 index 0000000..0034dc3 --- /dev/null +++ b/src/systems/rendering.cpp
@@ -0,0 +1,21 @@
1#include "rendering.h"
2#include "entity_manager.h"
3#include "components/sprite_renderable.h"
4#include "components/transformable.h"
5
6void RenderingSystem::tick(EntityManager& manager, float dt)
7{
8 texture.fill(texture.entirety(), 0, 0, 0);
9
10 std::set<int> spriteEntities = manager.getEntitiesWithComponents<SpriteRenderableComponent, TransformableComponent>();
11 for (int entity : spriteEntities)
12 {
13 auto& sprite = manager.getComponent<SpriteRenderableComponent>(entity);
14 auto& transform = manager.getComponent<TransformableComponent>(entity);
15 Rectangle dstrect {(int) transform.getX(), (int) transform.getY(), transform.getW(), transform.getH()};
16
17 texture.blit(sprite.getTexture(), sprite.getFrameRect(), dstrect);
18 }
19
20 texture.renderScreen();
21}
diff --git a/src/systems/rendering.h b/src/systems/rendering.h new file mode 100644 index 0000000..80ea79e --- /dev/null +++ b/src/systems/rendering.h
@@ -0,0 +1,16 @@
1#ifndef RENDERING_H_76ABC02A
2#define RENDERING_H_76ABC02A
3
4#include "system.h"
5#include "renderer.h"
6#include "consts.h"
7
8class RenderingSystem : public System {
9 public:
10 void tick(EntityManager& manager, float dt);
11
12 private:
13 Texture texture {GAME_WIDTH, GAME_HEIGHT};
14};
15
16#endif /* end of include guard: RENDERING_H_76ABC02A */