summary refs log tree commit diff stats
path: root/src/components.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/components.cpp')
-rw-r--r--src/components.cpp630
1 files changed, 0 insertions, 630 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}