summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2015-03-14 19:25:23 -0400
committerKelly Rauchenberger <fefferburbia@gmail.com>2015-03-14 19:25:23 -0400
commit6b1dcc5df51df4a2d8b724187eb1bcdb4fd9df8b (patch)
tree0a884ddd12b4e5b0afcc9c4ecaea5ecc73605b57 /src
parentd9349f10d6d1972e87aea76d502703fae128a0e5 (diff)
downloadtherapy-6b1dcc5df51df4a2d8b724187eb1bcdb4fd9df8b.tar.gz
therapy-6b1dcc5df51df4a2d8b724187eb1bcdb4fd9df8b.tar.bz2
therapy-6b1dcc5df51df4a2d8b724187eb1bcdb4fd9df8b.zip
Added sound when you hit the ground
Also split up components.cpp into files for each class, fixed a bug concerning falling off the screen when you change maps, and converted collision data into doubles.
Diffstat (limited to 'src')
-rw-r--r--src/components.cpp630
-rw-r--r--src/components.h125
-rw-r--r--src/components/map_collision.cpp211
-rw-r--r--src/components/map_collision.h46
-rw-r--r--src/components/map_render.cpp39
-rw-r--r--src/components/map_render.h19
-rw-r--r--src/components/physics_body.cpp65
-rw-r--r--src/components/physics_body.h20
-rw-r--r--src/components/player_physics.cpp117
-rw-r--r--src/components/player_physics.h25
-rw-r--r--src/components/player_sprite.cpp60
-rw-r--r--src/components/player_sprite.h23
-rw-r--r--src/components/simple_collider.cpp14
-rw-r--r--src/components/simple_collider.h18
-rw-r--r--src/components/static_image.cpp11
-rw-r--r--src/components/static_image.h18
-rw-r--r--src/components/user_movement.cpp100
-rw-r--r--src/components/user_movement.h19
-rw-r--r--src/entity.cpp3
-rw-r--r--src/entity.h3
-rw-r--r--src/entityfactory.cpp5
-rw-r--r--src/game.cpp19
-rw-r--r--src/game.h3
23 files changed, 826 insertions, 767 deletions
diff --git a/src/components.cpp b/src/components.cpp deleted file mode 100644 index 512fbed..0000000 --- a/src/components.cpp +++ /dev/null
@@ -1,630 +0,0 @@
1#include "components.h"
2#include "game.h"
3#include "muxer.h"
4#include "map.h"
5
6// User movement component
7
8void UserMovementComponent::input(Game& game, Entity& entity, int key, int action)
9{
10 if (action == GLFW_PRESS)
11 {
12 if (key == GLFW_KEY_LEFT)
13 {
14 holdingLeft = true;
15
16 if (!frozen)
17 {
18 entity.send(game, Message::Type::walkLeft);
19 }
20 } else if (key == GLFW_KEY_RIGHT)
21 {
22 holdingRight = true;
23
24 if (!frozen)
25 {
26 entity.send(game, Message::Type::walkRight);
27 }
28 } else if (key == GLFW_KEY_UP)
29 {
30 if (!frozen)
31 {
32 entity.send(game, Message::Type::jump);
33 }
34 } else if (key == GLFW_KEY_DOWN)
35 {
36 if (!frozen)
37 {
38 entity.send(game, Message::Type::canDrop);
39 }
40 }
41 } else if (action == GLFW_RELEASE)
42 {
43 if (key == GLFW_KEY_LEFT)
44 {
45 holdingLeft = false;
46
47 if (!frozen)
48 {
49 if (holdingRight)
50 {
51 entity.send(game, Message::Type::walkRight);
52 } else {
53 entity.send(game, Message::Type::stopWalking);
54 }
55 }
56 } else if (key == GLFW_KEY_RIGHT)
57 {
58 holdingRight = false;
59
60 if (!frozen)
61 {
62 if (holdingLeft)
63 {
64 entity.send(game, Message::Type::walkLeft);
65 } else {
66 entity.send(game, Message::Type::stopWalking);
67 }
68 }
69 } else if (key == GLFW_KEY_DOWN)
70 {
71 if (!frozen)
72 {
73 entity.send(game, Message::Type::cantDrop);
74 }
75 } else if (key == GLFW_KEY_UP)
76 {
77 if (!frozen)
78 {
79 entity.send(game, Message::Type::stopJump);
80 }
81 }
82 }
83}
84
85void UserMovementComponent::receive(Game& game, Entity& entity, const Message& msg)
86{
87 if (msg.type == Message::Type::die)
88 {
89 frozen = true;
90
91 entity.send(game, Message::Type::stopWalking);
92 } else if (msg.type == Message::Type::stopDying)
93 {
94 frozen = false;
95
96 if (holdingLeft)
97 {
98 entity.send(game, Message::Type::walkLeft);
99 } else if (holdingRight)
100 {
101 entity.send(game, Message::Type::walkRight);
102 }
103 }
104}
105
106// Physics component
107
108void PhysicsBodyComponent::receive(Game&, Entity&, const Message& msg)
109{
110 if (msg.type == Message::Type::walkLeft)
111 {
112 velocity.first = -90;
113 } else if (msg.type == Message::Type::walkRight)
114 {
115 velocity.first = 90;
116 } else if (msg.type == Message::Type::stopWalking)
117 {
118 velocity.first = 0.0;
119 } else if (msg.type == Message::Type::stopMovingHorizontally)
120 {
121 velocity.first = 0.0;
122 } else if (msg.type == Message::Type::stopMovingVertically)
123 {
124 velocity.second = 0.0;
125 }
126}
127
128void PhysicsBodyComponent::tick(Game&, Entity& entity, double dt)
129{
130 // Accelerate
131 velocity.first += accel.first * dt;
132 velocity.second += accel.second * dt;
133
134 // Terminal velocity
135#define TERMINAL_VELOCITY_X (2 * TILE_WIDTH * FRAMES_PER_SECOND)
136#define TERMINAL_VELOCITY_Y (2 * TILE_HEIGHT * FRAMES_PER_SECOND)
137 if (velocity.first < -TERMINAL_VELOCITY_X) velocity.first = -TERMINAL_VELOCITY_X;
138 if (velocity.first > TERMINAL_VELOCITY_X) velocity.first = TERMINAL_VELOCITY_X;
139 if (velocity.second < -TERMINAL_VELOCITY_Y) velocity.second = -TERMINAL_VELOCITY_Y;
140 if (velocity.second > TERMINAL_VELOCITY_Y) velocity.second = TERMINAL_VELOCITY_Y;
141
142 // Do the movement
143 entity.position.first += velocity.first * dt;
144 entity.position.second += velocity.second * dt;
145}
146
147void PhysicsBodyComponent::detectCollision(Game& game, Entity& entity, Entity& collider, std::pair<double, double> old_position)
148{
149 // If already colliding, do nothing!
150 if ((old_position.first + collider.size.first > entity.position.first)
151 && (old_position.first < entity.position.first + entity.size.first)
152 && (old_position.second + collider.size.second > entity.position.second)
153 && (old_position.second < entity.position.second + entity.size.second))
154 {
155 return;
156 }
157
158 // If newly colliding, SHOCK AND HORROR!
159 if ((collider.position.first + collider.size.first > entity.position.first)
160 && (collider.position.first < entity.position.first + entity.size.first)
161 && (collider.position.second + collider.size.second > entity.position.second)
162 && (collider.position.second < entity.position.second + entity.size.second))
163 {
164 Message msg(Message::Type::collision);
165 msg.collisionEntity = &collider;
166
167 entity.send(game, msg);
168 }
169}
170
171// Render player
172
173void PlayerSpriteComponent::render(Game&, Entity& entity, Texture& buffer)
174{
175 animFrame++;
176
177 int frame = 0;
178 if (isMoving)
179 {
180 frame += 2;
181
182 if (animFrame % 20 < 10)
183 {
184 frame += 2;
185 }
186 }
187
188 if (facingLeft)
189 {
190 frame++;
191 }
192
193 double alpha = 1.0;
194 if (dying && (animFrame % 4 < 2))
195 {
196 alpha = 0.0;
197 }
198
199 Rectangle src_rect {frame*10, 0, 10, 12};
200 Rectangle dst_rect {(int) entity.position.first, (int) entity.position.second, entity.size.first, entity.size.second};
201 buffer.blit(sprite, src_rect, dst_rect, alpha);
202}
203
204void PlayerSpriteComponent::receive(Game&, Entity&, const Message& msg)
205{
206 if (msg.type == Message::Type::walkLeft)
207 {
208 facingLeft = true;
209 isMoving = true;
210 } else if (msg.type == Message::Type::walkRight)
211 {
212 facingLeft = false;
213 isMoving = true;
214 } else if (msg.type == Message::Type::stopWalking)
215 {
216 isMoving = false;
217 } else if (msg.type == Message::Type::die)
218 {
219 dying = true;
220 isMoving = false;
221 } else if (msg.type == Message::Type::stopDying)
222 {
223 dying = false;
224 }
225}
226
227// Player physics
228
229#define JUMP_VELOCITY(h, l) (-2 * (h) / (l))
230#define JUMP_GRAVITY(h, l) (2 * ((h) / (l)) / (l))
231
232PlayerPhysicsComponent::PlayerPhysicsComponent()
233{
234 jump_velocity = JUMP_VELOCITY(TILE_HEIGHT*4.5, 0.3);
235 jump_gravity = JUMP_GRAVITY(TILE_HEIGHT*4.5, 0.3);
236 jump_gravity_short = JUMP_GRAVITY(TILE_HEIGHT*3.5, 0.233);
237
238 accel.second = jump_gravity_short;
239}
240
241void PlayerPhysicsComponent::receive(Game&, Entity& entity, const Message& msg)
242{
243 if (msg.type == Message::Type::walkLeft)
244 {
245 velocity.first = -90;
246 direction = -1;
247 } else if (msg.type == Message::Type::walkRight)
248 {
249 velocity.first = 90;
250 direction = 1;
251 } else if (msg.type == Message::Type::stopWalking)
252 {
253 velocity.first = 0.0;
254 direction = 0;
255 } else if (msg.type == Message::Type::stopMovingHorizontally)
256 {
257 velocity.first = 0.0;
258 } else if (msg.type == Message::Type::stopMovingVertically)
259 {
260 velocity.second = 0.0;
261 } else if (msg.type == Message::Type::jump)
262 {
263 playSound("../res/Randomize87.wav", 0.25);
264
265 velocity.second = jump_velocity;
266 accel.second = jump_gravity;
267 } else if (msg.type == Message::Type::stopJump)
268 {
269 accel.second = jump_gravity_short;
270 } else if (msg.type == Message::Type::canDrop)
271 {
272 canDrop = true;
273 } else if (msg.type == Message::Type::cantDrop)
274 {
275 canDrop = false;
276 } else if (msg.type == Message::Type::drop)
277 {
278 if (canDrop)
279 {
280 canDrop = false;
281 } else {
282 entity.position.second = msg.dropAxis - entity.size.second;
283 velocity.second = 0;
284 }
285 } else if (msg.type == Message::Type::die)
286 {
287 frozen = true;
288 } else if (msg.type == Message::Type::stopDying)
289 {
290 frozen = false;
291 }
292}
293
294void PlayerPhysicsComponent::tick(Game& game, Entity& entity, double dt)
295{
296 // If frozen, do nothing
297 if (frozen)
298 {
299 return;
300 }
301
302 // Continue walking even if blocked earlier
303 if (velocity.first == 0)
304 {
305 if (direction < 0)
306 {
307 velocity.first = -90;
308 } else if (direction > 0)
309 {
310 velocity.first = 90;
311 }
312 }
313
314 // Increase gravity at the height of jump
315 if ((accel.second == jump_gravity) && (velocity.second >= 0))
316 {
317 accel.second = jump_gravity_short;
318 }
319
320 // Do the movement
321 std::pair<double, double> old_position = entity.position;
322 PhysicsBodyComponent::tick(game, entity, dt);
323
324 // Check for collisions
325 game.detectCollision(entity, old_position);
326}
327
328// Map rendering
329
330MapRenderComponent::MapRenderComponent(const Map& map)
331{
332 screen.fill(screen.entirety(), 0, 0, 0);
333
334 Texture tiles("../res/tiles.png");
335
336 for (int i=0; i<MAP_WIDTH*(MAP_HEIGHT-1); i++)
337 {
338 int tile = map.getMapdata()[i];
339 int x = i % MAP_WIDTH;
340 int y = i / MAP_WIDTH;
341 Rectangle dst {x*TILE_WIDTH, y*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT};
342 Rectangle src {tile%8*TILE_WIDTH, tile/8*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT};
343
344 if (tile > 0)
345 {
346 screen.blit(tiles, src, dst);
347 }
348 }
349
350 Texture font("../res/font.bmp");
351 const char* map_name = map.getTitle();
352 int start_x = (40/2) - (strlen(map_name)/2);
353 for (size_t i=0; i<strlen(map_name); i++)
354 {
355 Rectangle srcRect {map_name[i] % 16 * 8, map_name[i] / 16 * 8, 8, 8};
356 Rectangle dstRect {(start_x + (int)i)*8, 24*8, 8, 8};
357 screen.blit(font, srcRect, dstRect);
358 }
359}
360
361void MapRenderComponent::render(Game&, Entity&, Texture& buffer)
362{
363 buffer.blit(screen, screen.entirety(), buffer.entirety());
364}
365
366// Map collision
367
368MapCollisionComponent::MapCollisionComponent(const Map& map) : map(map)
369{
370 addCollision(-6, 0, GAME_WIDTH, Direction::left, (map.getLeftMap() == nullptr) ? Collision::Type::wrap : Collision::Type::teleport);
371 addCollision(GAME_WIDTH+6, 0, GAME_WIDTH, Direction::right, (map.getRightMap() == nullptr) ? Collision::Type::reverse : Collision::Type::teleport);
372
373 for (int i=0; i<MAP_WIDTH*(MAP_HEIGHT-1); i++)
374 {
375 int x = i % MAP_WIDTH;
376 int y = i / MAP_WIDTH;
377 int tile = map.getMapdata()[i];
378
379 if ((tile > 0) && (tile < 28) && (!((tile >= 5) && (tile <= 7))))
380 {
381 addCollision(x*TILE_WIDTH, y*TILE_HEIGHT, (y+1)*TILE_HEIGHT, Direction::right, Collision::Type::wall);
382 addCollision((x+1)*TILE_WIDTH, y*TILE_HEIGHT, (y+1)*TILE_HEIGHT, Direction::left, Collision::Type::wall);
383 addCollision(y*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, Direction::down, Collision::Type::wall);
384 addCollision((y+1)*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, Direction::up, Collision::Type::wall);
385 } else if ((tile >= 5) && (tile <= 7))
386 {
387 addCollision(y*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, Direction::down, Collision::Type::platform);
388 } else if (tile == 42)
389 {
390 addCollision(y*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, Direction::down, Collision::Type::danger);
391 }
392 }
393}
394
395void MapCollisionComponent::addCollision(int axis, int lower, int upper, Direction dir, Collision::Type type)
396{
397 std::list<Collision>::iterator it;
398
399 switch (dir)
400 {
401 case Direction::up:
402 it = up_collisions.begin();
403 for (; it!=up_collisions.end(); it++)
404 {
405 if (it->axis < axis) break;
406 }
407
408 up_collisions.insert(it, {axis, lower, upper, type});
409
410 break;
411 case Direction::down:
412 it = down_collisions.begin();
413 for (; it!=down_collisions.end(); it++)
414 {
415 if (it->axis > axis) break;
416 }
417
418 down_collisions.insert(it, {axis, lower, upper, type});
419
420 break;
421 case Direction::left:
422 it = left_collisions.begin();
423 for (; it!=left_collisions.end(); it++)
424 {
425 if (it->axis < axis) break;
426 }
427
428 left_collisions.insert(it, {axis, lower, upper, type});
429
430 break;
431 case Direction::right:
432 it = right_collisions.begin();
433 for (; it!=right_collisions.end(); it++)
434 {
435 if (it->axis > axis) break;
436 }
437
438 right_collisions.insert(it, {axis, lower, upper, type});
439
440 break;
441 }
442}
443
444void MapCollisionComponent::detectCollision(Game& game, Entity&, Entity& collider, std::pair<double, double> old_position)
445{
446 int fixed_x = (int) collider.position.first;
447 int fixed_y = (int) collider.position.second;
448 int fixed_ox = (int) old_position.first;
449 int fixed_oy = (int) old_position.second;
450
451 if (fixed_x < fixed_ox)
452 {
453 for (auto collision : left_collisions)
454 {
455 if (collision.axis > fixed_ox) continue;
456 if (collision.axis < fixed_x) break;
457
458 if ((fixed_oy+collider.size.second > collision.lower) && (fixed_oy < collision.upper))
459 {
460 // We have a collision!
461 if (processCollision(game, collider, collision, Direction::left))
462 {
463 collider.position.second = old_position.second;
464
465 return;
466 }
467
468 break;
469 }
470 }
471 } else if (fixed_x > fixed_ox)
472 {
473 for (auto collision : right_collisions)
474 {
475 if (collision.axis < fixed_ox+collider.size.first) continue;
476 if (collision.axis > fixed_x+collider.size.first) break;
477
478 if ((fixed_oy+collider.size.second > collision.lower) && (fixed_oy < collision.upper))
479 {
480 // We have a collision!
481 if (processCollision(game, collider, collision, Direction::right))
482 {
483 collider.position.second = old_position.second;
484
485 return;
486 }
487
488 break;
489 }
490 }
491 }
492
493 fixed_x = (int) collider.position.first;
494 fixed_y = (int) collider.position.second;
495
496 if (fixed_y < fixed_oy)
497 {
498 for (auto collision : up_collisions)
499 {
500 if (collision.axis > fixed_oy) continue;
501 if (collision.axis < fixed_y) break;
502
503 if ((fixed_x+collider.size.first > collision.lower) && (fixed_x < collision.upper))
504 {
505 // We have a collision!
506 if (processCollision(game, collider, collision, Direction::up))
507 {
508 return;
509 }
510
511 break;
512 }
513 }
514 } else if (fixed_y > fixed_oy)
515 {
516 for (auto collision : down_collisions)
517 {
518 if (collision.axis < fixed_oy+collider.size.second) continue;
519 if (collision.axis > fixed_y+collider.size.second) break;
520
521 if ((fixed_x+collider.size.first > collision.lower) && (fixed_x < collision.upper))
522 {
523 // We have a collision!
524 if (processCollision(game, collider, collision, Direction::down))
525 {
526 return;
527 }
528
529 break;
530 }
531 }
532 }
533}
534
535bool MapCollisionComponent::processCollision(Game& game, Entity& collider, Collision collision, Direction dir)
536{
537 if (collision.type == Collision::Type::wall)
538 {
539 if (dir == Direction::left)
540 {
541 collider.position.first = collision.axis;
542 collider.send(game, Message::Type::stopMovingHorizontally);
543 } else if (dir == Direction::right)
544 {
545 collider.position.first = collision.axis - collider.size.first;
546 collider.send(game, Message::Type::stopMovingHorizontally);
547 } else if (dir == Direction::up)
548 {
549 collider.position.second = collision.axis;
550 collider.send(game, Message::Type::stopMovingVertically);
551 } else if (dir == Direction::down)
552 {
553 collider.position.second = collision.axis - collider.size.second;
554 collider.send(game, Message::Type::stopMovingVertically);
555 }
556 } else if (collision.type == Collision::Type::wrap)
557 {
558 if (dir == Direction::left)
559 {
560 collider.position.first = GAME_WIDTH-collider.size.first/2;
561 } else if (dir == Direction::right)
562 {
563 collider.position.first = -collider.size.first/2;
564 } else if (dir == Direction::up)
565 {
566 collider.position.second = GAME_HEIGHT-collider.size.second/2-1;
567 } else if (dir == Direction::down)
568 {
569 collider.position.second = -collider.size.second/2;
570 }
571 } else if (collision.type == Collision::Type::teleport)
572 {
573 if (dir == Direction::left)
574 {
575 collider.position.first = GAME_WIDTH-collider.size.first/2;
576 game.loadMap(*map.getLeftMap());
577 } else if (dir == Direction::right)
578 {
579 collider.position.first = -collider.size.first/2;
580 game.loadMap(*map.getRightMap());
581 }
582
583 return true;
584 } else if (collision.type == Collision::Type::reverse)
585 {
586 if (dir == Direction::right)
587 {
588 collider.position.first = collision.axis - collider.size.first;
589 collider.send(game, Message::Type::walkLeft);
590 }
591 } else if (collision.type == Collision::Type::platform)
592 {
593 Message msg(Message::Type::drop);
594 msg.dropAxis = collision.axis;
595
596 collider.send(game, msg);
597 } else if (collision.type == Collision::Type::danger)
598 {
599 game.playerDie();
600 }
601
602 return false;
603}
604
605// Static image
606
607StaticImageComponent::StaticImageComponent(const char* filename) : sprite(Texture(filename))
608{
609
610}
611
612void StaticImageComponent::render(Game&, Entity& entity, Texture& buffer)
613{
614 buffer.blit(sprite, sprite.entirety(), {(int) entity.position.first, (int) entity.position.second, entity.size.first, entity.size.second});
615}
616
617// Simple collision
618
619SimpleColliderComponent::SimpleColliderComponent(std::function<void (Game& game, Entity& collider)> callback) : callback(callback)
620{
621
622}
623
624void SimpleColliderComponent::receive(Game& game, Entity&, const Message& msg)
625{
626 if (msg.type == Message::Type::collision)
627 {
628 callback(game, *msg.collisionEntity);
629 }
630}
diff --git a/src/components.h b/src/components.h deleted file mode 100644 index e0c4a24..0000000 --- a/src/components.h +++ /dev/null
@@ -1,125 +0,0 @@
1#ifndef COMPONENTS_H
2#define COMPONENTS_H
3
4#include <utility>
5#include <list>
6#include "renderer.h"
7#include "entity.h"
8#include "game.h"
9
10class Map;
11
12class UserMovementComponent : public Component {
13 public:
14 void input(Game& game, Entity& entity, int key, int action);
15 void receive(Game&, Entity&, const Message& msg);
16
17 private:
18 bool holdingLeft = false;
19 bool holdingRight = false;
20 bool frozen = false;
21};
22
23class PhysicsBodyComponent : public Component {
24 public:
25 void receive(Game& game, Entity& entity, const Message& msg);
26 void tick(Game& game, Entity& entity, double dt);
27 void detectCollision(Game& game, Entity& entity, Entity& collider, std::pair<double, double> old_position);
28
29 protected:
30 std::pair<double, double> velocity;
31 std::pair<double, double> accel;
32};
33
34class PlayerSpriteComponent : public Component {
35 public:
36 void render(Game& game, Entity& entity, Texture& buffer);
37 void receive(Game& game, Entity& entity, const Message& msg);
38
39 private:
40 Texture sprite {"../res/Starla.png"};
41 int animFrame = 0;
42 bool facingLeft = false;
43 bool isMoving = false;
44 bool dying = false;
45};
46
47class PlayerPhysicsComponent : public PhysicsBodyComponent {
48 public:
49 PlayerPhysicsComponent();
50 void tick(Game& game, Entity& entity, double dt);
51 void receive(Game& game, Entity& entity, const Message& msg);
52
53 private:
54 double jump_velocity;
55 double jump_gravity;
56 double jump_gravity_short;
57 int direction = 0;
58 bool canDrop = false;
59 bool frozen = false;
60};
61
62class MapRenderComponent : public Component {
63 public:
64 MapRenderComponent(const Map& map);
65 void render(Game& game, Entity& entity, Texture& buffer);
66
67 private:
68 Texture screen{GAME_WIDTH, GAME_HEIGHT};
69};
70
71class MapCollisionComponent : public Component {
72 public:
73 MapCollisionComponent(const Map& map);
74 void detectCollision(Game& game, Entity& entity, Entity& collider, std::pair<double, double> old_position);
75
76 private:
77 enum class Direction {
78 up, left, down, right
79 };
80
81 struct Collision {
82 enum class Type {
83 wall,
84 wrap,
85 teleport,
86 reverse,
87 platform,
88 danger
89 };
90
91 int axis;
92 int lower;
93 int upper;
94 Type type;
95 };
96
97 void addCollision(int axis, int lower, int upper, Direction dir, Collision::Type type);
98 bool processCollision(Game& game, Entity& collider, Collision collision, Direction dir);
99
100 std::list<Collision> left_collisions;
101 std::list<Collision> right_collisions;
102 std::list<Collision> up_collisions;
103 std::list<Collision> down_collisions;
104 const Map& map;
105};
106
107class StaticImageComponent : public Component {
108 public:
109 StaticImageComponent(const char* filename);
110 void render(Game& game, Entity& entity, Texture& buffer);
111
112 private:
113 Texture sprite;
114};
115
116class SimpleColliderComponent : public Component {
117 public:
118 SimpleColliderComponent(std::function<void (Game& game, Entity& collider)> callback);
119 void receive(Game& game, Entity& entity, const Message& msg);
120
121 private:
122 std::function<void (Game& game, Entity& collider)> callback;
123};
124
125#endif
diff --git a/src/components/map_collision.cpp b/src/components/map_collision.cpp new file mode 100644 index 0000000..f385320 --- /dev/null +++ b/src/components/map_collision.cpp
@@ -0,0 +1,211 @@
1#include "map_collision.h"
2#include "map.h"
3#include "game.h"
4
5MapCollisionComponent::MapCollisionComponent(const Map& map) : map(map)
6{
7 addCollision(-6, 0, GAME_WIDTH, Direction::left, (map.getLeftMap() == nullptr) ? Collision::Type::wrap : Collision::Type::teleport);
8 addCollision(GAME_WIDTH+6, 0, GAME_WIDTH, Direction::right, (map.getRightMap() == nullptr) ? Collision::Type::reverse : Collision::Type::teleport);
9
10 for (int i=0; i<MAP_WIDTH*(MAP_HEIGHT-1); i++)
11 {
12 int x = i % MAP_WIDTH;
13 int y = i / MAP_WIDTH;
14 int tile = map.getMapdata()[i];
15
16 if ((tile > 0) && (tile < 28) && (!((tile >= 5) && (tile <= 7))))
17 {
18 addCollision(x*TILE_WIDTH, y*TILE_HEIGHT, (y+1)*TILE_HEIGHT, Direction::right, Collision::Type::wall);
19 addCollision((x+1)*TILE_WIDTH, y*TILE_HEIGHT, (y+1)*TILE_HEIGHT, Direction::left, Collision::Type::wall);
20 addCollision(y*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, Direction::down, Collision::Type::wall);
21 addCollision((y+1)*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, Direction::up, Collision::Type::wall);
22 } else if ((tile >= 5) && (tile <= 7))
23 {
24 addCollision(y*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, Direction::down, Collision::Type::platform);
25 } else if (tile == 42)
26 {
27 addCollision(y*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, Direction::down, Collision::Type::danger);
28 }
29 }
30}
31
32void MapCollisionComponent::addCollision(double axis, double lower, double
33 upper, Direction dir, Collision::Type type)
34{
35 std::list<Collision>::iterator it;
36
37 switch (dir)
38 {
39 case Direction::up:
40 it = up_collisions.begin();
41 for (; it!=up_collisions.end(); it++)
42 {
43 if (it->axis < axis) break;
44 }
45
46 up_collisions.insert(it, {axis, lower, upper, type});
47
48 break;
49 case Direction::down:
50 it = down_collisions.begin();
51 for (; it!=down_collisions.end(); it++)
52 {
53 if (it->axis > axis) break;
54 }
55
56 down_collisions.insert(it, {axis, lower, upper, type});
57
58 break;
59 case Direction::left:
60 it = left_collisions.begin();
61 for (; it!=left_collisions.end(); it++)
62 {
63 if (it->axis < axis) break;
64 }
65
66 left_collisions.insert(it, {axis, lower, upper, type});
67
68 break;
69 case Direction::right:
70 it = right_collisions.begin();
71 for (; it!=right_collisions.end(); it++)
72 {
73 if (it->axis > axis) break;
74 }
75
76 right_collisions.insert(it, {axis, lower, upper, type});
77
78 break;
79 }
80}
81
82void MapCollisionComponent::detectCollision(Game& game, Entity&, Entity& collider, std::pair<double, double> old_position)
83{
84 if (collider.position.first < old_position.first)
85 {
86 for (auto collision : left_collisions)
87 {
88 if (collision.axis > old_position.first) continue;
89 if (collision.axis < collider.position.first) break;
90
91 if ((old_position.second+collider.size.second > collision.lower) && (old_position.second < collision.upper))
92 {
93 // We have a collision!
94 processCollision(game, collider, collision, Direction::left, old_position);
95
96 break;
97 }
98 }
99 } else if (collider.position.first > old_position.first)
100 {
101 for (auto collision : right_collisions)
102 {
103 if (collision.axis < old_position.first+collider.size.first) continue;
104 if (collision.axis > collider.position.first+collider.size.first) break;
105
106 if ((old_position.second+collider.size.second > collision.lower) && (old_position.second < collision.upper))
107 {
108 // We have a collision!
109 processCollision(game, collider, collision, Direction::right, old_position);
110
111 break;
112 }
113 }
114 }
115
116 if (collider.position.second < old_position.second)
117 {
118 for (auto collision : up_collisions)
119 {
120 if (collision.axis > old_position.second) continue;
121 if (collision.axis < collider.position.second) break;
122
123 if ((collider.position.first+collider.size.first > collision.lower) && (collider.position.first < collision.upper))
124 {
125 // We have a collision!
126 processCollision(game, collider, collision, Direction::up, old_position);
127
128 break;
129 }
130 }
131 } else if (collider.position.second > old_position.second)
132 {
133 for (auto collision : down_collisions)
134 {
135 if (collision.axis < old_position.second+collider.size.second) continue;
136 if (collision.axis > collider.position.second+collider.size.second) break;
137
138 if ((collider.position.first+collider.size.first > collision.lower) && (collider.position.first < collision.upper))
139 {
140 // We have a collision!
141 processCollision(game, collider, collision, Direction::down, old_position);
142
143 break;
144 }
145 }
146 }
147}
148
149void MapCollisionComponent::processCollision(Game& game, Entity& collider, Collision collision, Direction dir, std::pair<double, double> old_position)
150{
151 if (collision.type == Collision::Type::wall)
152 {
153 if (dir == Direction::left)
154 {
155 collider.position.first = collision.axis;
156 collider.send(game, Message::Type::stopMovingHorizontally);
157 } else if (dir == Direction::right)
158 {
159 collider.position.first = collision.axis - collider.size.first;
160 collider.send(game, Message::Type::stopMovingHorizontally);
161 } else if (dir == Direction::up)
162 {
163 collider.position.second = collision.axis;
164 collider.send(game, Message::Type::stopMovingVertically);
165 } else if (dir == Direction::down)
166 {
167 collider.position.second = collision.axis - collider.size.second;
168 collider.send(game, Message::Type::hitTheGround);
169 }
170 } else if (collision.type == Collision::Type::wrap)
171 {
172 if (dir == Direction::left)
173 {
174 collider.position.first = GAME_WIDTH-collider.size.first/2;
175 } else if (dir == Direction::right)
176 {
177 collider.position.first = -collider.size.first/2;
178 } else if (dir == Direction::up)
179 {
180 collider.position.second = GAME_HEIGHT-collider.size.second/2-1;
181 } else if (dir == Direction::down)
182 {
183 collider.position.second = -collider.size.second/2;
184 }
185 } else if (collision.type == Collision::Type::teleport)
186 {
187 if (dir == Direction::left)
188 {
189 game.loadMap(*map.getLeftMap(), std::make_pair(GAME_WIDTH-collider.size.first/2, old_position.second));
190 } else if (dir == Direction::right)
191 {
192 game.loadMap(*map.getRightMap(), std::make_pair(-collider.size.first/2, old_position.second));
193 }
194 } else if (collision.type == Collision::Type::reverse)
195 {
196 if (dir == Direction::right)
197 {
198 collider.position.first = collision.axis - collider.size.first;
199 collider.send(game, Message::Type::walkLeft);
200 }
201 } else if (collision.type == Collision::Type::platform)
202 {
203 Message msg(Message::Type::drop);
204 msg.dropAxis = collision.axis;
205
206 collider.send(game, msg);
207 } else if (collision.type == Collision::Type::danger)
208 {
209 game.playerDie();
210 }
211}
diff --git a/src/components/map_collision.h b/src/components/map_collision.h new file mode 100644 index 0000000..3b718b6 --- /dev/null +++ b/src/components/map_collision.h
@@ -0,0 +1,46 @@
1#ifndef MAP_COLLISION_H
2#define MAP_COLLISION_H
3
4#include "entity.h"
5#include <list>
6
7class Map;
8class Game;
9
10class MapCollisionComponent : public Component {
11 public:
12 MapCollisionComponent(const Map& map);
13 void detectCollision(Game& game, Entity& entity, Entity& collider, std::pair<double, double> old_position);
14
15 private:
16 enum class Direction {
17 up, left, down, right
18 };
19
20 struct Collision {
21 enum class Type {
22 wall,
23 wrap,
24 teleport,
25 reverse,
26 platform,
27 danger
28 };
29
30 double axis;
31 double lower;
32 double upper;
33 Type type;
34 };
35
36 void addCollision(double axis, double lower, double upper, Direction dir, Collision::Type type);
37 void processCollision(Game& game, Entity& collider, Collision collision, Direction dir, std::pair<double, double> old_position);
38
39 std::list<Collision> left_collisions;
40 std::list<Collision> right_collisions;
41 std::list<Collision> up_collisions;
42 std::list<Collision> down_collisions;
43 const Map& map;
44};
45
46#endif
diff --git a/src/components/map_render.cpp b/src/components/map_render.cpp new file mode 100644 index 0000000..d93afe6 --- /dev/null +++ b/src/components/map_render.cpp
@@ -0,0 +1,39 @@
1#include "map_render.h"
2#include "map.h"
3#include "game.h"
4
5MapRenderComponent::MapRenderComponent(const Map& map) : screen(GAME_WIDTH, GAME_HEIGHT)
6{
7 screen.fill(screen.entirety(), 0, 0, 0);
8
9 Texture tiles("../res/tiles.png");
10
11 for (int i=0; i<MAP_WIDTH*(MAP_HEIGHT-1); i++)
12 {
13 int tile = map.getMapdata()[i];
14 int x = i % MAP_WIDTH;
15 int y = i / MAP_WIDTH;
16 Rectangle dst {x*TILE_WIDTH, y*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT};
17 Rectangle src {tile%8*TILE_WIDTH, tile/8*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT};
18
19 if (tile > 0)
20 {
21 screen.blit(tiles, src, dst);
22 }
23 }
24
25 Texture font("../res/font.bmp");
26 const char* map_name = map.getTitle();
27 int start_x = (40/2) - (strlen(map_name)/2);
28 for (size_t i=0; i<strlen(map_name); i++)
29 {
30 Rectangle srcRect {map_name[i] % 16 * 8, map_name[i] / 16 * 8, 8, 8};
31 Rectangle dstRect {(start_x + (int)i)*8, 24*8, 8, 8};
32 screen.blit(font, srcRect, dstRect);
33 }
34}
35
36void MapRenderComponent::render(Game&, Entity&, Texture& buffer)
37{
38 buffer.blit(screen, screen.entirety(), buffer.entirety());
39}
diff --git a/src/components/map_render.h b/src/components/map_render.h new file mode 100644 index 0000000..a232aa6 --- /dev/null +++ b/src/components/map_render.h
@@ -0,0 +1,19 @@
1#ifndef MAP_RENDER_H
2#define MAP_RENDER_H
3
4#include "entity.h"
5#include "renderer.h"
6
7class Map;
8class Game;
9
10class MapRenderComponent : public Component {
11 public:
12 MapRenderComponent(const Map& map);
13 void render(Game& game, Entity& entity, Texture& buffer);
14
15 private:
16 Texture screen;
17};
18
19#endif
diff --git a/src/components/physics_body.cpp b/src/components/physics_body.cpp new file mode 100644 index 0000000..72f2fd8 --- /dev/null +++ b/src/components/physics_body.cpp
@@ -0,0 +1,65 @@
1#include "physics_body.h"
2#include "game.h"
3
4void PhysicsBodyComponent::receive(Game&, Entity&, const Message& msg)
5{
6 if (msg.type == Message::Type::walkLeft)
7 {
8 velocity.first = -90;
9 } else if (msg.type == Message::Type::walkRight)
10 {
11 velocity.first = 90;
12 } else if (msg.type == Message::Type::stopWalking)
13 {
14 velocity.first = 0.0;
15 } else if (msg.type == Message::Type::stopMovingHorizontally)
16 {
17 velocity.first = 0.0;
18 } else if (msg.type == Message::Type::stopMovingVertically)
19 {
20 velocity.second = 0.0;
21 }
22}
23
24void PhysicsBodyComponent::tick(Game&, Entity& entity, double dt)
25{
26 // Accelerate
27 velocity.first += accel.first * dt;
28 velocity.second += accel.second * dt;
29
30 // Terminal velocity
31#define TERMINAL_VELOCITY_X (2 * TILE_WIDTH * FRAMES_PER_SECOND)
32#define TERMINAL_VELOCITY_Y (2 * TILE_HEIGHT * FRAMES_PER_SECOND)
33 if (velocity.first < -TERMINAL_VELOCITY_X) velocity.first = -TERMINAL_VELOCITY_X;
34 if (velocity.first > TERMINAL_VELOCITY_X) velocity.first = TERMINAL_VELOCITY_X;
35 if (velocity.second < -TERMINAL_VELOCITY_Y) velocity.second = -TERMINAL_VELOCITY_Y;
36 if (velocity.second > TERMINAL_VELOCITY_Y) velocity.second = TERMINAL_VELOCITY_Y;
37
38 // Do the movement
39 entity.position.first += velocity.first * dt;
40 entity.position.second += velocity.second * dt;
41}
42
43void PhysicsBodyComponent::detectCollision(Game& game, Entity& entity, Entity& collider, std::pair<double, double> old_position)
44{
45 // If already colliding, do nothing!
46 if ((old_position.first + collider.size.first > entity.position.first)
47 && (old_position.first < entity.position.first + entity.size.first)
48 && (old_position.second + collider.size.second > entity.position.second)
49 && (old_position.second < entity.position.second + entity.size.second))
50 {
51 return;
52 }
53
54 // If newly colliding, SHOCK AND HORROR!
55 if ((collider.position.first + collider.size.first > entity.position.first)
56 && (collider.position.first < entity.position.first + entity.size.first)
57 && (collider.position.second + collider.size.second > entity.position.second)
58 && (collider.position.second < entity.position.second + entity.size.second))
59 {
60 Message msg(Message::Type::collision);
61 msg.collisionEntity = &collider;
62
63 entity.send(game, msg);
64 }
65}
diff --git a/src/components/physics_body.h b/src/components/physics_body.h new file mode 100644 index 0000000..079cc51 --- /dev/null +++ b/src/components/physics_body.h
@@ -0,0 +1,20 @@
1#ifndef PHYSICS_BODY_H
2#define PHYSICS_BODY_H
3
4#include "entity.h"
5#include <utility>
6
7class Game;
8
9class PhysicsBodyComponent : public Component {
10 public:
11 void receive(Game& game, Entity& entity, const Message& msg);
12 void tick(Game& game, Entity& entity, double dt);
13 void detectCollision(Game& game, Entity& entity, Entity& collider, std::pair<double, double> old_position);
14
15 protected:
16 std::pair<double, double> velocity;
17 std::pair<double, double> accel;
18};
19
20#endif
diff --git a/src/components/player_physics.cpp b/src/components/player_physics.cpp new file mode 100644 index 0000000..1be43b6 --- /dev/null +++ b/src/components/player_physics.cpp
@@ -0,0 +1,117 @@
1#include "player_physics.h"
2#include "muxer.h"
3#include "game.h"
4
5#define JUMP_VELOCITY(h, l) (-2 * (h) / (l))
6#define JUMP_GRAVITY(h, l) (2 * ((h) / (l)) / (l))
7
8PlayerPhysicsComponent::PlayerPhysicsComponent()
9{
10 jump_velocity = JUMP_VELOCITY(TILE_HEIGHT*4.5, 0.3);
11 jump_gravity = JUMP_GRAVITY(TILE_HEIGHT*4.5, 0.3);
12 jump_gravity_short = JUMP_GRAVITY(TILE_HEIGHT*3.5, 0.233);
13
14 accel.second = jump_gravity_short;
15}
16
17void PlayerPhysicsComponent::receive(Game&, Entity& entity, const Message& msg)
18{
19 if (msg.type == Message::Type::walkLeft)
20 {
21 velocity.first = -90;
22 direction = -1;
23 } else if (msg.type == Message::Type::walkRight)
24 {
25 velocity.first = 90;
26 direction = 1;
27 } else if (msg.type == Message::Type::stopWalking)
28 {
29 velocity.first = 0.0;
30 direction = 0;
31 } else if (msg.type == Message::Type::stopMovingHorizontally)
32 {
33 velocity.first = 0.0;
34 } else if (msg.type == Message::Type::stopMovingVertically)
35 {
36 velocity.second = 0.0;
37 } else if (msg.type == Message::Type::hitTheGround)
38 {
39 if (isFalling)
40 {
41 playSound("../res/Randomize27.wav", 0.05);
42 isFalling = false;
43 }
44
45 velocity.second = 0.0;
46 } else if (msg.type == Message::Type::jump)
47 {
48 playSound("../res/Randomize87.wav", 0.25);
49
50 velocity.second = jump_velocity;
51 accel.second = jump_gravity;
52 } else if (msg.type == Message::Type::stopJump)
53 {
54 accel.second = jump_gravity_short;
55 } else if (msg.type == Message::Type::canDrop)
56 {
57 canDrop = true;
58 } else if (msg.type == Message::Type::cantDrop)
59 {
60 canDrop = false;
61 } else if (msg.type == Message::Type::drop)
62 {
63 if (canDrop)
64 {
65 canDrop = false;
66 } else {
67 entity.position.second = msg.dropAxis - entity.size.second;
68 velocity.second = 0;
69 }
70 } else if (msg.type == Message::Type::die)
71 {
72 frozen = true;
73 } else if (msg.type == Message::Type::stopDying)
74 {
75 frozen = false;
76 }
77}
78
79void PlayerPhysicsComponent::tick(Game& game, Entity& entity, double dt)
80{
81 // If frozen, do nothing
82 if (frozen)
83 {
84 return;
85 }
86
87 // Continue walking even if blocked earlier
88 if (velocity.first == 0)
89 {
90 if (direction < 0)
91 {
92 velocity.first = -90;
93 } else if (direction > 0)
94 {
95 velocity.first = 90;
96 }
97 }
98
99 // Increase gravity at the height of jump
100 if ((accel.second == jump_gravity) && (velocity.second >= 0))
101 {
102 accel.second = jump_gravity_short;
103 }
104
105 // Do the movement
106 std::pair<double, double> old_position = entity.position;
107 PhysicsBodyComponent::tick(game, entity, dt);
108
109 // Check for collisions
110 game.detectCollision(entity, old_position);
111
112 // Are we moving due to gravity?
113 if (velocity.second != 0.0)
114 {
115 isFalling = true;
116 }
117}
diff --git a/src/components/player_physics.h b/src/components/player_physics.h new file mode 100644 index 0000000..26f1fae --- /dev/null +++ b/src/components/player_physics.h
@@ -0,0 +1,25 @@
1#ifndef PLAYER_PHYSICS_H
2#define PLAYER_PHYSICS_H
3
4#include "entity.h"
5#include "physics_body.h"
6
7class Game;
8
9class PlayerPhysicsComponent : public PhysicsBodyComponent {
10 public:
11 PlayerPhysicsComponent();
12 void tick(Game& game, Entity& entity, double dt);
13 void receive(Game& game, Entity& entity, const Message& msg);
14
15 private:
16 double jump_velocity;
17 double jump_gravity;
18 double jump_gravity_short;
19 int direction = 0;
20 bool canDrop = false;
21 bool frozen = false;
22 bool isFalling = false;
23};
24
25#endif
diff --git a/src/components/player_sprite.cpp b/src/components/player_sprite.cpp new file mode 100644 index 0000000..2814852 --- /dev/null +++ b/src/components/player_sprite.cpp
@@ -0,0 +1,60 @@
1#include "player_sprite.h"
2
3PlayerSpriteComponent::PlayerSpriteComponent() : sprite("../res/Starla.png")
4{
5
6}
7
8void PlayerSpriteComponent::render(Game&, Entity& entity, Texture& buffer)
9{
10 animFrame++;
11
12 int frame = 0;
13 if (isMoving)
14 {
15 frame += 2;
16
17 if (animFrame % 20 < 10)
18 {
19 frame += 2;
20 }
21 }
22
23 if (facingLeft)
24 {
25 frame++;
26 }
27
28 double alpha = 1.0;
29 if (dying && (animFrame % 4 < 2))
30 {
31 alpha = 0.0;
32 }
33
34 Rectangle src_rect {frame*10, 0, 10, 12};
35 Rectangle dst_rect {(int) entity.position.first, (int) entity.position.second, entity.size.first, entity.size.second};
36 buffer.blit(sprite, src_rect, dst_rect, alpha);
37}
38
39void PlayerSpriteComponent::receive(Game&, Entity&, const Message& msg)
40{
41 if (msg.type == Message::Type::walkLeft)
42 {
43 facingLeft = true;
44 isMoving = true;
45 } else if (msg.type == Message::Type::walkRight)
46 {
47 facingLeft = false;
48 isMoving = true;
49 } else if (msg.type == Message::Type::stopWalking)
50 {
51 isMoving = false;
52 } else if (msg.type == Message::Type::die)
53 {
54 dying = true;
55 isMoving = false;
56 } else if (msg.type == Message::Type::stopDying)
57 {
58 dying = false;
59 }
60}
diff --git a/src/components/player_sprite.h b/src/components/player_sprite.h new file mode 100644 index 0000000..b1ac0af --- /dev/null +++ b/src/components/player_sprite.h
@@ -0,0 +1,23 @@
1#ifndef PLAYER_SPRITE_H
2#define PLAYER_SPRITE_H
3
4#include "entity.h"
5#include "renderer.h"
6
7class Game;
8
9class PlayerSpriteComponent : public Component {
10 public:
11 PlayerSpriteComponent();
12 void render(Game& game, Entity& entity, Texture& buffer);
13 void receive(Game& game, Entity& entity, const Message& msg);
14
15 private:
16 Texture sprite;
17 int animFrame = 0;
18 bool facingLeft = false;
19 bool isMoving = false;
20 bool dying = false;
21};
22
23#endif
diff --git a/src/components/simple_collider.cpp b/src/components/simple_collider.cpp new file mode 100644 index 0000000..f4b414e --- /dev/null +++ b/src/components/simple_collider.cpp
@@ -0,0 +1,14 @@
1#include "simple_collider.h"
2
3SimpleColliderComponent::SimpleColliderComponent(std::function<void (Game& game, Entity& collider)> callback) : callback(callback)
4{
5
6}
7
8void SimpleColliderComponent::receive(Game& game, Entity&, const Message& msg)
9{
10 if (msg.type == Message::Type::collision)
11 {
12 callback(game, *msg.collisionEntity);
13 }
14}
diff --git a/src/components/simple_collider.h b/src/components/simple_collider.h new file mode 100644 index 0000000..15d78cf --- /dev/null +++ b/src/components/simple_collider.h
@@ -0,0 +1,18 @@
1#ifndef SIMPLE_COLLIDER_H
2#define SIMPLE_COLLIDER_H
3
4#include "entity.h"
5#include <functional>
6
7class Game;
8
9class SimpleColliderComponent : public Component {
10 public:
11 SimpleColliderComponent(std::function<void (Game& game, Entity& collider)> callback);
12 void receive(Game& game, Entity& entity, const Message& msg);
13
14 private:
15 std::function<void (Game& game, Entity& collider)> callback;
16};
17
18#endif
diff --git a/src/components/static_image.cpp b/src/components/static_image.cpp new file mode 100644 index 0000000..9fa8dca --- /dev/null +++ b/src/components/static_image.cpp
@@ -0,0 +1,11 @@
1#include "static_image.h"
2
3StaticImageComponent::StaticImageComponent(const char* filename) : sprite(Texture(filename))
4{
5
6}
7
8void StaticImageComponent::render(Game&, Entity& entity, Texture& buffer)
9{
10 buffer.blit(sprite, sprite.entirety(), {(int) entity.position.first, (int) entity.position.second, entity.size.first, entity.size.second});
11}
diff --git a/src/components/static_image.h b/src/components/static_image.h new file mode 100644 index 0000000..2dec78b --- /dev/null +++ b/src/components/static_image.h
@@ -0,0 +1,18 @@
1#ifndef STATIC_IMAGE_H
2#define STATIC_IMAGE_H
3
4#include "entity.h"
5#include "renderer.h"
6
7class Game;
8
9class StaticImageComponent : public Component {
10 public:
11 StaticImageComponent(const char* filename);
12 void render(Game& game, Entity& entity, Texture& buffer);
13
14 private:
15 Texture sprite;
16};
17
18#endif
diff --git a/src/components/user_movement.cpp b/src/components/user_movement.cpp new file mode 100644 index 0000000..e499fee --- /dev/null +++ b/src/components/user_movement.cpp
@@ -0,0 +1,100 @@
1#include "user_movement.h"
2#include "renderer.h"
3
4void UserMovementComponent::input(Game& game, Entity& entity, int key, int action)
5{
6 if (action == GLFW_PRESS)
7 {
8 if (key == GLFW_KEY_LEFT)
9 {
10 holdingLeft = true;
11
12 if (!frozen)
13 {
14 entity.send(game, Message::Type::walkLeft);
15 }
16 } else if (key == GLFW_KEY_RIGHT)
17 {
18 holdingRight = true;
19
20 if (!frozen)
21 {
22 entity.send(game, Message::Type::walkRight);
23 }
24 } else if (key == GLFW_KEY_UP)
25 {
26 if (!frozen)
27 {
28 entity.send(game, Message::Type::jump);
29 }
30 } else if (key == GLFW_KEY_DOWN)
31 {
32 if (!frozen)
33 {
34 entity.send(game, Message::Type::canDrop);
35 }
36 }
37 } else if (action == GLFW_RELEASE)
38 {
39 if (key == GLFW_KEY_LEFT)
40 {
41 holdingLeft = false;
42
43 if (!frozen)
44 {
45 if (holdingRight)
46 {
47 entity.send(game, Message::Type::walkRight);
48 } else {
49 entity.send(game, Message::Type::stopWalking);
50 }
51 }
52 } else if (key == GLFW_KEY_RIGHT)
53 {
54 holdingRight = false;
55
56 if (!frozen)
57 {
58 if (holdingLeft)
59 {
60 entity.send(game, Message::Type::walkLeft);
61 } else {
62 entity.send(game, Message::Type::stopWalking);
63 }
64 }
65 } else if (key == GLFW_KEY_DOWN)
66 {
67 if (!frozen)
68 {
69 entity.send(game, Message::Type::cantDrop);
70 }
71 } else if (key == GLFW_KEY_UP)
72 {
73 if (!frozen)
74 {
75 entity.send(game, Message::Type::stopJump);
76 }
77 }
78 }
79}
80
81void UserMovementComponent::receive(Game& game, Entity& entity, const Message& msg)
82{
83 if (msg.type == Message::Type::die)
84 {
85 frozen = true;
86
87 entity.send(game, Message::Type::stopWalking);
88 } else if (msg.type == Message::Type::stopDying)
89 {
90 frozen = false;
91
92 if (holdingLeft)
93 {
94 entity.send(game, Message::Type::walkLeft);
95 } else if (holdingRight)
96 {
97 entity.send(game, Message::Type::walkRight);
98 }
99 }
100}
diff --git a/src/components/user_movement.h b/src/components/user_movement.h new file mode 100644 index 0000000..1bcf05e --- /dev/null +++ b/src/components/user_movement.h
@@ -0,0 +1,19 @@
1#ifndef USER_MOVEMENT_H
2#define USER_MOVEMENT_H
3
4#include "entity.h"
5
6class Game;
7
8class UserMovementComponent : public Component {
9 public:
10 void input(Game& game, Entity& entity, int key, int action);
11 void receive(Game&, Entity&, const Message& msg);
12
13 private:
14 bool holdingLeft = false;
15 bool holdingRight = false;
16 bool frozen = false;
17};
18
19#endif
diff --git a/src/entity.cpp b/src/entity.cpp index 0ede567..2b6cd7f 100644 --- a/src/entity.cpp +++ b/src/entity.cpp
@@ -1,7 +1,4 @@
1#include "entity.h" 1#include "entity.h"
2#include <libxml/parser.h>
3#include "components.h"
4#include "muxer.h"
5 2
6void Entity::addComponent(std::shared_ptr<Component> c) 3void Entity::addComponent(std::shared_ptr<Component> c)
7{ 4{
diff --git a/src/entity.h b/src/entity.h index 26febfb..d09dbe5 100644 --- a/src/entity.h +++ b/src/entity.h
@@ -24,7 +24,8 @@ class Message {
24 canDrop, 24 canDrop,
25 cantDrop, 25 cantDrop,
26 die, 26 die,
27 stopDying 27 stopDying,
28 hitTheGround
28 }; 29 };
29 30
30 Message(Type type) : type(type) {} 31 Message(Type type) : type(type) {}
diff --git a/src/entityfactory.cpp b/src/entityfactory.cpp index 47a1463..bad72cf 100644 --- a/src/entityfactory.cpp +++ b/src/entityfactory.cpp
@@ -1,9 +1,12 @@
1#include "entityfactory.h" 1#include "entityfactory.h"
2#include <libxml/parser.h> 2#include <libxml/parser.h>
3#include "components.h"
4#include "muxer.h" 3#include "muxer.h"
5#include <cstdio> 4#include <cstdio>
6#include <map> 5#include <map>
6#include "components/static_image.h"
7#include "components/simple_collider.h"
8#include "components/physics_body.h"
9#include "game.h"
7 10
8struct EntityData { 11struct EntityData {
9 char* sprite; 12 char* sprite;
diff --git a/src/game.cpp b/src/game.cpp index 6e79f75..20b8564 100644 --- a/src/game.cpp +++ b/src/game.cpp
@@ -1,9 +1,12 @@
1#include "game.h" 1#include "game.h"
2#include "renderer.h" 2#include "renderer.h"
3#include "components.h"
4#include "muxer.h" 3#include "muxer.h"
5#include "entityfactory.h"
6#include "map.h" 4#include "map.h"
5#include "components/user_movement.h"
6#include "components/player_physics.h"
7#include "components/player_sprite.h"
8#include "components/map_render.h"
9#include "components/map_collision.h"
7 10
8Game::Game() 11Game::Game()
9{ 12{
@@ -23,7 +26,7 @@ Game::Game()
23 Map& startingMap = Map::getNamedMap("embarass"); 26 Map& startingMap = Map::getNamedMap("embarass");
24 save = {&startingMap, player->position}; 27 save = {&startingMap, player->position};
25 28
26 loadMap(startingMap); 29 loadMap(startingMap, player->position);
27} 30}
28 31
29void key_callback(GLFWwindow* window, int key, int, int action, int) 32void key_callback(GLFWwindow* window, int key, int, int action, int)
@@ -65,6 +68,8 @@ void Game::execute(GLFWwindow* window)
65 newWorld = false; 68 newWorld = false;
66 entities.clear(); 69 entities.clear();
67 entities = std::move(nextEntities); 70 entities = std::move(nextEntities);
71
72 player->position = nextPosition;
68 } 73 }
69 74
70 // Handle input 75 // Handle input
@@ -106,7 +111,7 @@ void Game::execute(GLFWwindow* window)
106 } 111 }
107} 112}
108 113
109void Game::loadMap(const Map& map) 114void Game::loadMap(const Map& map, std::pair<double, double> position)
110{ 115{
111 auto mapEn = std::make_shared<Entity>(); 116 auto mapEn = std::make_shared<Entity>();
112 117
@@ -125,6 +130,7 @@ void Game::loadMap(const Map& map)
125 newWorld = true; 130 newWorld = true;
126 131
127 currentMap = &map; 132 currentMap = &map;
133 nextPosition = position;
128} 134}
129 135
130void Game::detectCollision(Entity& collider, std::pair<double, double> old_position) 136void Game::detectCollision(Entity& collider, std::pair<double, double> old_position)
@@ -154,10 +160,11 @@ void Game::playerDie()
154 schedule(0.75, [&] () { 160 schedule(0.75, [&] () {
155 if (*currentMap != *save.map) 161 if (*currentMap != *save.map)
156 { 162 {
157 loadMap(*save.map); 163 loadMap(*save.map, save.position);
164 } else {
165 player->position = save.position;
158 } 166 }
159 167
160 player->position = save.position;
161 player->send(*this, Message::Type::stopDying); 168 player->send(*this, Message::Type::stopDying);
162 }); 169 });
163} 170}
diff --git a/src/game.h b/src/game.h index bc31912..a4620d4 100644 --- a/src/game.h +++ b/src/game.h
@@ -28,7 +28,7 @@ class Game {
28 public: 28 public:
29 Game(); 29 Game();
30 void execute(GLFWwindow* window); 30 void execute(GLFWwindow* window);
31 void loadMap(const Map& map); 31 void loadMap(const Map& map, std::pair<double, double> position);
32 void detectCollision(Entity& collider, std::pair<double, double> old_position); 32 void detectCollision(Entity& collider, std::pair<double, double> old_position);
33 void saveGame(); 33 void saveGame();
34 void schedule(double time, std::function<void ()> callback); 34 void schedule(double time, std::function<void ()> callback);
@@ -39,6 +39,7 @@ class Game {
39 39
40 std::list<std::shared_ptr<Entity>> entities; 40 std::list<std::shared_ptr<Entity>> entities;
41 std::list<std::shared_ptr<Entity>> nextEntities; 41 std::list<std::shared_ptr<Entity>> nextEntities;
42 std::pair<double, double> nextPosition;
42 bool newWorld; 43 bool newWorld;
43 std::shared_ptr<Entity> player; 44 std::shared_ptr<Entity> player;
44 const Map* currentMap; 45 const Map* currentMap;