summary refs log tree commit diff stats
path: root/src/systems
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2018-02-18 12:35:45 -0500
committerKelly Rauchenberger <fefferburbia@gmail.com>2018-02-18 12:35:45 -0500
commite16fb5be90c889c371cbb0ca2444735c2e12073c (patch)
treecbaa20e14a34c460b6c9886f266c4b4b6f62ae87 /src/systems
parented08b673c50b076042d8f0c49501372168142764 (diff)
downloadtherapy-e16fb5be90c889c371cbb0ca2444735c2e12073c.tar.gz
therapy-e16fb5be90c889c371cbb0ca2444735c2e12073c.tar.bz2
therapy-e16fb5be90c889c371cbb0ca2444735c2e12073c.zip
Implemented map adjacency
This brings along with it the ability to move to different maps, for which the PlayingSystem and PlayableComponent were introduced. The PlayingSystem is a general overseer system that handles big picture stuff like initializing the player and changing maps. The PlayableComponent represents the player. While the ControllableComponent is also likely to always only be on the player entity, the two are distinct by separation of concerns.

This also required a refactoring of how collisions are processed, because of a bug where the player can move to a new map when horizontal collisions are checked, and vertical collisions are skipped, causing the player to clip through the ground because the normal force was never handled.
Diffstat (limited to 'src/systems')
-rw-r--r--src/systems/mapping.cpp28
-rw-r--r--src/systems/playing.cpp98
-rw-r--r--src/systems/playing.h21
-rw-r--r--src/systems/pondering.cpp347
-rw-r--r--src/systems/pondering.h11
5 files changed, 381 insertions, 124 deletions
diff --git a/src/systems/mapping.cpp b/src/systems/mapping.cpp index 120a27a..05167c1 100644 --- a/src/systems/mapping.cpp +++ b/src/systems/mapping.cpp
@@ -93,6 +93,34 @@ void MappingSystem::loadMap(size_t mapId)
93 93
94 const Map& map = game_.getWorld().getMap(mappable.getMapId()); 94 const Map& map = game_.getWorld().getMap(mappable.getMapId());
95 95
96 addBoundary(
97 mappable.getLeftBoundaries(),
98 -WALL_GAP,
99 0,
100 MAP_HEIGHT * TILE_HEIGHT,
101 MappableComponent::Boundary::Type::adjacency);
102
103 addBoundary(
104 mappable.getRightBoundaries(),
105 GAME_WIDTH + WALL_GAP,
106 0,
107 MAP_HEIGHT * TILE_HEIGHT,
108 MappableComponent::Boundary::Type::adjacency);
109
110 addBoundary(
111 mappable.getUpBoundaries(),
112 -WALL_GAP,
113 0,
114 GAME_WIDTH,
115 MappableComponent::Boundary::Type::adjacency);
116
117 addBoundary(
118 mappable.getDownBoundaries(),
119 MAP_HEIGHT * TILE_HEIGHT + WALL_GAP,
120 0,
121 GAME_WIDTH,
122 MappableComponent::Boundary::Type::adjacency);
123
96 for (size_t i = 0; i < MAP_WIDTH * MAP_HEIGHT; i++) 124 for (size_t i = 0; i < MAP_WIDTH * MAP_HEIGHT; i++)
97 { 125 {
98 size_t x = i % MAP_WIDTH; 126 size_t x = i % MAP_WIDTH;
diff --git a/src/systems/playing.cpp b/src/systems/playing.cpp new file mode 100644 index 0000000..2c6a419 --- /dev/null +++ b/src/systems/playing.cpp
@@ -0,0 +1,98 @@
1#include "playing.h"
2#include "game.h"
3#include "components/transformable.h"
4#include "components/animatable.h"
5#include "components/playable.h"
6#include "components/controllable.h"
7#include "components/orientable.h"
8#include "systems/mapping.h"
9#include "systems/pondering.h"
10#include "animation.h"
11
12void PlayingSystem::tick(double)
13{
14 // Check if we need to change the map
15 auto players = game_.getEntityManager().getEntitiesWithComponents<
16 PlayableComponent>();
17
18 for (id_type player : players)
19 {
20 auto& playable = game_.getEntityManager().
21 getComponent<PlayableComponent>(player);
22
23 if (playable.changingMap)
24 {
25 // Change the map!
26 auto entities = game_.getEntityManager().getEntities();
27
28 for (id_type entity : entities)
29 {
30 if (entity != player)
31 {
32 game_.getEntityManager().deleteEntity(entity);
33 }
34 }
35
36 game_.getSystemManager().getSystem<MappingSystem>().
37 loadMap(playable.newMapId);
38
39 auto& transformable = game_.getEntityManager().
40 getComponent<TransformableComponent>(player);
41
42 transformable.setX(playable.newMapX);
43 transformable.setY(playable.newMapY);
44
45 playable.changingMap = false;
46
47 break;
48 }
49 }
50}
51
52void PlayingSystem::initPlayer()
53{
54 id_type player = game_.getEntityManager().emplaceEntity();
55
56 AnimationSet playerGraphics {"res/Starla.png", 10, 12, 6};
57 playerGraphics.emplaceAnimation("stillLeft", 3, 1, 1);
58 playerGraphics.emplaceAnimation("stillRight", 0, 1, 1);
59 playerGraphics.emplaceAnimation("walkingLeft", 4, 2, 10);
60 playerGraphics.emplaceAnimation("walkingRight", 1, 2, 10);
61
62 game_.getEntityManager().emplaceComponent<AnimatableComponent>(
63 player,
64 std::move(playerGraphics),
65 "stillLeft");
66
67 game_.getEntityManager().emplaceComponent<TransformableComponent>(
68 player,
69 203, 44, 10, 12);
70
71 game_.getSystemManager().getSystem<PonderingSystem>().initializeBody(
72 player,
73 PonderableComponent::Type::freefalling);
74
75 game_.getEntityManager().emplaceComponent<ControllableComponent>(player);
76 game_.getEntityManager().emplaceComponent<OrientableComponent>(player);
77 game_.getEntityManager().emplaceComponent<PlayableComponent>(player);
78}
79
80void PlayingSystem::changeMap(
81 size_t mapId,
82 double x,
83 double y)
84{
85 auto players = game_.getEntityManager().getEntitiesWithComponents<
86 PlayableComponent>();
87
88 for (id_type player : players)
89 {
90 auto& playable = game_.getEntityManager().
91 getComponent<PlayableComponent>(player);
92
93 playable.changingMap = true;
94 playable.newMapId = mapId;
95 playable.newMapX = x;
96 playable.newMapY = y;
97 }
98}
diff --git a/src/systems/playing.h b/src/systems/playing.h new file mode 100644 index 0000000..c98a464 --- /dev/null +++ b/src/systems/playing.h
@@ -0,0 +1,21 @@
1#ifndef PLAYING_H_70A54F7D
2#define PLAYING_H_70A54F7D
3
4#include "system.h"
5
6class PlayingSystem : public System {
7public:
8
9 PlayingSystem(Game& game) : System(game)
10 {
11 }
12
13 void tick(double dt);
14
15 void initPlayer();
16
17 void changeMap(size_t mapId, double x, double y);
18
19};
20
21#endif /* end of include guard: PLAYING_H_70A54F7D */
diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index 4a165b1..2490dc9 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp
@@ -1,11 +1,14 @@
1#include "pondering.h" 1#include "pondering.h"
2#include <queue>
2#include "game.h" 3#include "game.h"
3#include "components/ponderable.h" 4#include "components/ponderable.h"
4#include "components/transformable.h" 5#include "components/transformable.h"
5#include "components/orientable.h" 6#include "components/orientable.h"
6#include "components/mappable.h" 7#include "components/mappable.h"
7#include "systems/orienting.h" 8#include "systems/orienting.h"
9#include "systems/playing.h"
8#include "consts.h" 10#include "consts.h"
11#include "collision.h"
9 12
10void PonderingSystem::tick(double dt) 13void PonderingSystem::tick(double dt)
11{ 14{
@@ -42,6 +45,9 @@ void PonderingSystem::tick(double dt)
42 bool oldGrounded = ponderable.isGrounded(); 45 bool oldGrounded = ponderable.isGrounded();
43 ponderable.setGrounded(false); 46 ponderable.setGrounded(false);
44 47
48 std::priority_queue<Collision> collisions;
49
50 // Find collisions
45 for (id_type mapEntity : maps) 51 for (id_type mapEntity : maps)
46 { 52 {
47 auto& mappable = game_.getEntityManager(). 53 auto& mappable = game_.getEntityManager().
@@ -57,13 +63,13 @@ void PonderingSystem::tick(double dt)
57 && (oldY < it->second.getUpper())) 63 && (oldY < it->second.getUpper()))
58 { 64 {
59 // We have a collision! 65 // We have a collision!
60 processCollision( 66 collisions.emplace(
61 entity, 67 mapEntity,
62 Direction::left, 68 Direction::left,
63 newX, 69 it->second.getType(),
64 newY,
65 it->first, 70 it->first,
66 it->second.getType()); 71 it->second.getLower(),
72 it->second.getUpper());
67 } 73 }
68 } 74 }
69 } else if (newX > oldX) 75 } else if (newX > oldX)
@@ -77,13 +83,13 @@ void PonderingSystem::tick(double dt)
77 && (oldY < it->second.getUpper())) 83 && (oldY < it->second.getUpper()))
78 { 84 {
79 // We have a collision! 85 // We have a collision!
80 processCollision( 86 collisions.emplace(
81 entity, 87 mapEntity,
82 Direction::right, 88 Direction::right,
83 newX, 89 it->second.getType(),
84 newY,
85 it->first, 90 it->first,
86 it->second.getType()); 91 it->second.getLower(),
92 it->second.getUpper());
87 } 93 }
88 } 94 }
89 } 95 }
@@ -98,13 +104,13 @@ void PonderingSystem::tick(double dt)
98 && (oldX < it->second.getUpper())) 104 && (oldX < it->second.getUpper()))
99 { 105 {
100 // We have a collision! 106 // We have a collision!
101 processCollision( 107 collisions.emplace(
102 entity, 108 mapEntity,
103 Direction::up, 109 Direction::up,
104 newX, 110 it->second.getType(),
105 newY,
106 it->first, 111 it->first,
107 it->second.getType()); 112 it->second.getLower(),
113 it->second.getUpper());
108 } 114 }
109 } 115 }
110 } else if (newY > oldY) 116 } else if (newY > oldY)
@@ -118,13 +124,221 @@ void PonderingSystem::tick(double dt)
118 && (oldX < it->second.getUpper())) 124 && (oldX < it->second.getUpper()))
119 { 125 {
120 // We have a collision! 126 // We have a collision!
121 processCollision( 127 collisions.emplace(
122 entity, 128 mapEntity,
123 Direction::down, 129 Direction::down,
124 newX, 130 it->second.getType(),
125 newY,
126 it->first, 131 it->first,
127 it->second.getType()); 132 it->second.getLower(),
133 it->second.getUpper());
134 }
135 }
136 }
137 }
138
139 // Process collisions in order of priority
140 while (!collisions.empty())
141 {
142 Collision collision = collisions.top();
143 collisions.pop();
144
145 // Make sure that they are still colliding
146 if (!collision.isColliding(
147 newX,
148 newY,
149 transformable.getW(),
150 transformable.getH()))
151 {
152 continue;
153 }
154
155 bool touchedWall = false;
156 bool stopProcessing = false;
157
158 switch (collision.getType())
159 {
160 case Collision::Type::wall:
161 {
162 touchedWall = true;
163
164 break;
165 }
166
167 case Collision::Type::platform:
168 {
169 if (game_.getEntityManager().
170 hasComponent<OrientableComponent>(entity))
171 {
172 auto& orientable = game_.getEntityManager().
173 getComponent<OrientableComponent>(entity);
174
175 if (orientable.getDropState() !=
176 OrientableComponent::DropState::none)
177 {
178 orientable.setDropState(OrientableComponent::DropState::active);
179 } else {
180 touchedWall = true;
181 }
182 } else {
183 touchedWall = true;
184 }
185
186 break;
187 }
188
189 case Collision::Type::adjacency:
190 {
191 auto& mappable = game_.getEntityManager().
192 getComponent<MappableComponent>(collision.getCollider());
193 const Map& map = game_.getWorld().getMap(mappable.getMapId());
194 auto& adj = [&] () -> const Map::Adjacent& {
195 switch (collision.getDirection())
196 {
197 case Direction::left: return map.getLeftAdjacent();
198 case Direction::right: return map.getRightAdjacent();
199 case Direction::up: return map.getUpAdjacent();
200 case Direction::down: return map.getDownAdjacent();
201 }
202 }();
203
204 switch (adj.getType())
205 {
206 case Map::Adjacent::Type::wall:
207 {
208 touchedWall = true;
209
210 break;
211 }
212
213 case Map::Adjacent::Type::wrap:
214 {
215 switch (collision.getDirection())
216 {
217 case Direction::left:
218 {
219 newX = GAME_WIDTH + WALL_GAP - transformable.getW();
220
221 break;
222 }
223
224 case Direction::right:
225 {
226 newX = -WALL_GAP;
227
228 break;
229 }
230
231 case Direction::up:
232 {
233 newY = MAP_HEIGHT * TILE_HEIGHT + WALL_GAP -
234 transformable.getH();
235
236 break;
237 }
238
239 case Direction::down:
240 {
241 newY = -WALL_GAP;
242
243 break;
244 }
245 }
246 }
247
248 case Map::Adjacent::Type::warp:
249 {
250 double warpX = newX;
251 double warpY = newY;
252
253 switch (collision.getDirection())
254 {
255 case Direction::left:
256 {
257 warpX = GAME_WIDTH + WALL_GAP - transformable.getW();
258
259 break;
260 }
261
262 case Direction::right:
263 {
264 warpX = -WALL_GAP;
265
266 break;
267 }
268
269 case Direction::up:
270 {
271 warpY = MAP_HEIGHT * TILE_HEIGHT - transformable.getH();
272
273 break;
274 }
275
276 case Direction::down:
277 {
278 warpY = -WALL_GAP;
279
280 break;
281 }
282 }
283
284 game_.getSystemManager().getSystem<PlayingSystem>().
285 changeMap(adj.getMapId(), warpX, warpY);
286
287 stopProcessing = true;
288
289 break;
290 }
291 }
292 }
293
294 default:
295 {
296 // Not yet implemented.
297
298 break;
299 }
300 }
301
302 if (stopProcessing)
303 {
304 break;
305 }
306
307 if (touchedWall)
308 {
309 switch (collision.getDirection())
310 {
311 case Direction::left:
312 {
313 newX = collision.getAxis();
314 ponderable.setVelocityX(0.0);
315
316 break;
317 }
318
319 case Direction::right:
320 {
321 newX = collision.getAxis() - transformable.getW();
322 ponderable.setVelocityX(0.0);
323
324 break;
325 }
326
327 case Direction::up:
328 {
329 newY = collision.getAxis();
330 ponderable.setVelocityY(0.0);
331
332 break;
333 }
334
335 case Direction::down:
336 {
337 newY = collision.getAxis() - transformable.getH();
338 ponderable.setVelocityY(0.0);
339 ponderable.setGrounded(true);
340
341 break;
128 } 342 }
129 } 343 }
130 } 344 }
@@ -173,96 +387,3 @@ void PonderingSystem::initializeBody(
173 ponderable.setAccelY(NORMAL_GRAVITY); 387 ponderable.setAccelY(NORMAL_GRAVITY);
174 } 388 }
175} 389}
176
177void PonderingSystem::processCollision(
178 id_type entity,
179 Direction dir,
180 double& newX,
181 double& newY,
182 int axis,
183 MappableComponent::Boundary::Type type)
184{
185 auto& ponderable = game_.getEntityManager().
186 getComponent<PonderableComponent>(entity);
187
188 auto& transformable = game_.getEntityManager().
189 getComponent<TransformableComponent>(entity);
190
191 bool touchedGround = false;
192
193 switch (type)
194 {
195 case MappableComponent::Boundary::Type::wall:
196 {
197 switch (dir)
198 {
199 case Direction::left:
200 {
201 newX = axis;
202 ponderable.setVelocityX(0.0);
203
204 break;
205 }
206
207 case Direction::right:
208 {
209 newX = axis - transformable.getW();
210 ponderable.setVelocityX(0.0);
211
212 break;
213 }
214
215 case Direction::up:
216 {
217 newY = axis;
218 ponderable.setVelocityY(0.0);
219
220 break;
221 }
222
223 case Direction::down:
224 {
225 touchedGround = true;
226
227 break;
228 }
229 }
230
231 break;
232 }
233
234 case MappableComponent::Boundary::Type::platform:
235 {
236 if (game_.getEntityManager().hasComponent<OrientableComponent>(entity))
237 {
238 auto& orientable = game_.getEntityManager().
239 getComponent<OrientableComponent>(entity);
240
241 if (orientable.getDropState() != OrientableComponent::DropState::none)
242 {
243 orientable.setDropState(OrientableComponent::DropState::active);
244 } else {
245 touchedGround = true;
246 }
247 } else {
248 touchedGround = true;
249 }
250
251 break;
252 }
253
254 default:
255 {
256 // Not yet implemented.
257
258 break;
259 }
260 }
261
262 if (touchedGround)
263 {
264 newY = axis - transformable.getH();
265 ponderable.setVelocityY(0.0);
266 ponderable.setGrounded(true);
267 }
268}
diff --git a/src/systems/pondering.h b/src/systems/pondering.h index a16622b..d70525b 100644 --- a/src/systems/pondering.h +++ b/src/systems/pondering.h
@@ -2,7 +2,6 @@
2#define PONDERING_H_F2530E0E 2#define PONDERING_H_F2530E0E
3 3
4#include "system.h" 4#include "system.h"
5#include "components/mappable.h"
6#include "components/ponderable.h" 5#include "components/ponderable.h"
7#include "direction.h" 6#include "direction.h"
8 7
@@ -17,16 +16,6 @@ public:
17 16
18 void initializeBody(id_type entity, PonderableComponent::Type type); 17 void initializeBody(id_type entity, PonderableComponent::Type type);
19 18
20private:
21
22 void processCollision(
23 id_type entity,
24 Direction dir,
25 double& newX,
26 double& newY,
27 int axis,
28 MappableComponent::Boundary::Type type);
29
30}; 19};
31 20
32#endif /* end of include guard: PONDERING_H_F2530E0E */ 21#endif /* end of include guard: PONDERING_H_F2530E0E */