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.cpp537
1 files changed, 537 insertions, 0 deletions
diff --git a/src/components.cpp b/src/components.cpp new file mode 100644 index 0000000..f9c7c10 --- /dev/null +++ b/src/components.cpp
@@ -0,0 +1,537 @@
1#include "components.h"
2#include "game.h"
3
4// User movement component
5
6void UserMovementComponent::input(int key, int action)
7{
8 if (action == GLFW_PRESS)
9 {
10 if (key == GLFW_KEY_LEFT)
11 {
12 holdingLeft = true;
13
14 message_t msg;
15 msg.type = CM_WALK_LEFT;
16
17 entity.send(msg);
18 } else if (key == GLFW_KEY_RIGHT)
19 {
20 holdingRight = true;
21
22 message_t msg;
23 msg.type = CM_WALK_RIGHT;
24
25 entity.send(msg);
26 } else if (key == GLFW_KEY_UP)
27 {
28 message_t msg;
29 msg.type = CM_JUMP;
30
31 entity.send(msg);
32 } else if (key == GLFW_KEY_DOWN)
33 {
34 message_t msg;
35 msg.type = CM_CAN_DROP;
36
37 entity.send(msg);
38 }
39 } else if (action == GLFW_RELEASE)
40 {
41 if (key == GLFW_KEY_LEFT)
42 {
43 holdingLeft = false;
44
45 if (holdingRight)
46 {
47 message_t msg;
48 msg.type = CM_WALK_RIGHT;
49
50 entity.send(msg);
51 } else {
52 message_t msg;
53 msg.type = CM_STOP_WALKING;
54
55 entity.send(msg);
56 }
57 } else if (key == GLFW_KEY_RIGHT)
58 {
59 holdingRight = false;
60
61 if (holdingLeft)
62 {
63 message_t msg;
64 msg.type = CM_WALK_LEFT;
65
66 entity.send(msg);
67 } else {
68 message_t msg;
69 msg.type = CM_STOP_WALKING;
70
71 entity.send(msg);
72 }
73 } else if (key == GLFW_KEY_DOWN)
74 {
75 message_t msg;
76 msg.type = CM_CANT_DROP;
77
78 entity.send(msg);
79 } else if (key == GLFW_KEY_UP)
80 {
81 message_t msg;
82 msg.type = CM_STOP_JUMP;
83
84 entity.send(msg);
85 }
86 }
87}
88
89// Physics component
90
91void PhysicsBodyComponent::receive(message_t msg)
92{
93 if (msg.type == CM_WALK_LEFT)
94 {
95 velocity.first = -1.5;
96 } else if (msg.type == CM_WALK_RIGHT)
97 {
98 velocity.first = 1.5;
99 } else if (msg.type == CM_STOP_WALKING)
100 {
101 velocity.first = 0.0;
102 }
103}
104
105void PhysicsBodyComponent::tick()
106{
107 velocity.first += accel.first;
108 velocity.second += accel.second;
109
110 position.first += velocity.first;
111 position.second += velocity.second;
112}
113
114void PhysicsBodyComponent::detectCollision(Entity& player, Locatable& physics, std::pair<double, double> old_position)
115{
116 // If already colliding, do nothing!
117 if ((old_position.first + physics.size.first > this->position.first)
118 && (old_position.first < this->position.first + this->size.first)
119 && (old_position.second + physics.size.second > this->position.second)
120 && (old_position.second < this->position.second + this->size.second))
121 {
122 return;
123 }
124
125 // If newly colliding, SHOCK AND HORROR!
126 if ((physics.position.first + physics.size.first > this->position.first)
127 && (physics.position.first < this->position.first + this->size.first)
128 && (physics.position.second + physics.size.second > this->position.second)
129 && (physics.position.second < this->position.second + this->size.second))
130 {
131 message_t msg;
132 msg.type = CM_COLLISION;
133 msg.collisionEntity = &player;
134
135 entity.send(msg);
136 }
137}
138
139// Render player
140
141PlayerSpriteComponent::PlayerSpriteComponent(Entity& entity, Locatable& physics) : Component(entity), physics(physics)
142{
143 sprite = loadTextureFromFile("../res/Starla.png");
144}
145
146PlayerSpriteComponent::~PlayerSpriteComponent()
147{
148 destroyTexture(sprite);
149}
150
151void PlayerSpriteComponent::render(Texture* buffer)
152{
153 int frame = 0;
154 if (isMoving)
155 {
156 frame += 2;
157
158 if (animFrame < 10)
159 {
160 frame += 2;
161 }
162 }
163 if (facingLeft) frame++;
164
165 Rectangle src_rect(frame*10, 0, 10, 12);
166 Rectangle dst_rect((int) physics.position.first, (int) physics.position.second, physics.size.first, physics.size.second);
167 blitTexture(sprite, buffer, &src_rect, &dst_rect);
168}
169
170void PlayerSpriteComponent::receive(message_t msg)
171{
172 if (msg.type == CM_WALK_LEFT)
173 {
174 facingLeft = true;
175 isMoving = true;
176 } else if (msg.type == CM_WALK_RIGHT)
177 {
178 facingLeft = false;
179 isMoving = true;
180 } else if (msg.type == CM_STOP_WALKING)
181 {
182 isMoving = false;
183 }
184}
185
186void PlayerSpriteComponent::tick()
187{
188 animFrame++;
189 animFrame %= 20;
190}
191
192// Player physics
193
194#define JUMP_VELOCITY(h, l) (-2 * (h) / (l))
195#define JUMP_GRAVITY(h, l) (2 * ((h) / (l)) / (l))
196
197PlayerPhysicsComponent::PlayerPhysicsComponent(Entity& entity) : Component(entity)
198{
199 jump_velocity = JUMP_VELOCITY(TILE_HEIGHT*4.5, 0.3*FRAMES_PER_SECOND);
200 jump_gravity = JUMP_GRAVITY(TILE_HEIGHT*4.5, 0.3*FRAMES_PER_SECOND);
201 jump_gravity_short = JUMP_GRAVITY(TILE_HEIGHT*3.5, 0.233*FRAMES_PER_SECOND);
202
203 accel.second = jump_gravity_short;
204}
205
206void PlayerPhysicsComponent::receive(message_t msg)
207{
208 if (msg.type == CM_WALK_LEFT)
209 {
210 velocity.first = -1.5;
211 direction = -1;
212 } else if (msg.type == CM_WALK_RIGHT)
213 {
214 velocity.first = 1.5;
215 direction = 1;
216 } else if (msg.type == CM_STOP_WALKING)
217 {
218 velocity.first = 0.0;
219 direction = 0;
220 } else if (msg.type == CM_JUMP)
221 {
222 velocity.second = jump_velocity;
223 accel.second = jump_gravity;
224 } else if (msg.type == CM_STOP_JUMP)
225 {
226 accel.second = jump_gravity_short;
227 } else if (msg.type == CM_CAN_DROP)
228 {
229 canDrop = true;
230 } else if (msg.type == CM_CANT_DROP)
231 {
232 canDrop = false;
233 } else if (msg.type == CM_DROP)
234 {
235 if (canDrop)
236 {
237 canDrop = false;
238 } else {
239 position.second = msg.dropAxis - size.second;
240 velocity.second = 0;
241 }
242 }
243}
244
245void PlayerPhysicsComponent::tick()
246{
247 // Continue walking even if blocked earlier
248 if (velocity.first == 0)
249 {
250 if (direction < 0)
251 {
252 velocity.first = -1.5;
253 } else if (direction > 0)
254 {
255 velocity.first = 1.5;
256 }
257 }
258
259 // Increase gravity at the height of jump
260 if ((accel.second == jump_gravity) && (velocity.second >= 0))
261 {
262 accel.second = jump_gravity_short;
263 }
264
265 // Apply acceleration
266 velocity.first += accel.first;
267 velocity.second += accel.second;
268
269 // Terminal velocity
270 if (velocity.first < -16) velocity.first = -16;
271 if (velocity.first > 16) velocity.first = 16;
272 if (velocity.second < -16) velocity.second = -16;
273 if (velocity.second > 16) velocity.second = 16;
274
275 // Do the movement
276 std::pair<double, double> old_position = std::make_pair(position.first, position.second);
277 position.first += velocity.first;
278 position.second += velocity.second;
279
280 // Check for collisions
281 for (auto it = entity.world->bodies.begin(); it != entity.world->bodies.end(); it++)
282 {
283 auto poop = *it;
284 poop->detectCollision(entity, *this, old_position);
285 }
286}
287
288// Map rendering
289
290MapRenderComponent::MapRenderComponent(Entity& entity, Map* map) : Component(entity)
291{
292 screen = createTexture(GAME_WIDTH, GAME_HEIGHT);
293 fillTexture(screen, NULL, 0, 0, 0);
294
295 Texture* tiles = loadTextureFromFile("../res/tiles.png");
296
297 for (int i=0; i<MAP_WIDTH*(MAP_HEIGHT-1); i++)
298 {
299 int tile = map->mapdata()[i];
300 int x = i % MAP_WIDTH;
301 int y = i / MAP_WIDTH;
302 Rectangle dst(x*TILE_WIDTH, y*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT);
303 Rectangle src(tile%8*TILE_WIDTH, tile/8*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT);
304
305 if (tile > 0)
306 {
307 blitTexture(tiles, screen, &src, &dst);
308 }
309 }
310
311 destroyTexture(tiles);
312
313 Texture* font = loadTextureFromFile("../res/font.bmp");
314 const char* map_name = map->title();
315 int start_x = (40/2) - (strlen(map_name)/2);
316 for (size_t i=0; i<strlen(map_name); i++)
317 {
318 Rectangle srcRect(map_name[i] % 16 * 8, map_name[i] / 16 * 8, 8, 8);
319 Rectangle dstRect((start_x + i)*8, 24*8, 8, 8);
320 blitTexture(font, screen, &srcRect, &dstRect);
321 }
322
323 destroyTexture(font);
324}
325
326MapRenderComponent::~MapRenderComponent()
327{
328 destroyTexture(screen);
329}
330
331void MapRenderComponent::render(Texture* buffer)
332{
333 blitTexture(screen, buffer, NULL, NULL);
334}
335
336// Map collision
337
338MapCollisionComponent::MapCollisionComponent(Entity& entity, Map* map) : Component(entity)
339{
340 this->map = map;
341
342 add_collision(-6, 0, GAME_WIDTH, left, (map->getLeftMap() == NULL) ? 1 : 2);
343 add_collision(GAME_WIDTH+6, 0, GAME_WIDTH, right, (map->getRightMap() == NULL) ? 3 : 2);
344
345 for (int i=0; i<MAP_WIDTH*(MAP_HEIGHT-1); i++)
346 {
347 int x = i % MAP_WIDTH;
348 int y = i / MAP_WIDTH;
349 int tile = map->mapdata()[i];
350
351 if ((tile > 0) && (!((tile >= 5) && (tile <= 7))))
352 {
353 add_collision(x*TILE_WIDTH, y*TILE_HEIGHT, (y+1)*TILE_HEIGHT, right, 0);
354 add_collision((x+1)*TILE_WIDTH, y*TILE_HEIGHT, (y+1)*TILE_HEIGHT, left, 0);
355 add_collision(y*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, down, 0);
356 add_collision((y+1)*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, up, 0);
357 } else if ((tile >= 5) && (tile <= 7))
358 {
359 add_collision(y*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, down, 3);
360 }
361 }
362}
363
364void MapCollisionComponent::add_collision(int axis, int lower, int upper, direction_t dir, int type)
365{
366 std::list<collision_t>::iterator it;
367
368 switch (dir)
369 {
370 case up:
371 it = up_collisions.begin();
372 for (; it!=up_collisions.end(); it++)
373 {
374 if (it->axis < axis) break;
375 }
376
377 up_collisions.insert(it, {axis, lower, upper, type});
378
379 break;
380 case down:
381 it = down_collisions.begin();
382 for (; it!=down_collisions.end(); it++)
383 {
384 if (it->axis > axis) break;
385 }
386
387 down_collisions.insert(it, {axis, lower, upper, type});
388
389 break;
390 case left:
391 it = left_collisions.begin();
392 for (; it!=left_collisions.end(); it++)
393 {
394 if (it->axis < axis) break;
395 }
396
397 left_collisions.insert(it, {axis, lower, upper, type});
398
399 break;
400 case right:
401 it = right_collisions.begin();
402 for (; it!=right_collisions.end(); it++)
403 {
404 if (it->axis > axis) break;
405 }
406
407 right_collisions.insert(it, {axis, lower, upper, type});
408
409 break;
410 }
411}
412
413void MapCollisionComponent::detectCollision(Entity& player, Locatable& physics, std::pair<double, double> old_position)
414{
415 int fixed_x = (int) physics.position.first;
416 int fixed_y = (int) physics.position.second;
417 int fixed_ox = (int) old_position.first;
418 int fixed_oy = (int) old_position.second;
419
420 if (fixed_x < fixed_ox)
421 {
422 for (auto it=left_collisions.begin(); it!=left_collisions.end(); it++)
423 {
424 if (it->axis > fixed_ox) continue;
425 if (it->axis < fixed_x) break;
426
427 if ((fixed_oy+physics.size.second > it->lower) && (fixed_oy < it->upper))
428 {
429 // We have a collision!
430 if (it->type == 0)
431 {
432 physics.position.first = it->axis;
433 physics.velocity.first = 0;
434 } else if (it->type == 1)
435 {
436 physics.position.first = GAME_WIDTH-physics.size.first/2;
437 } else if (it->type == 2)
438 {
439 physics.position.first = GAME_WIDTH-physics.size.first/2;
440 Game::getInstance().loadMap(map->getLeftMap());
441 }
442
443 break;
444 }
445 }
446 } else if (fixed_x > fixed_ox)
447 {
448 for (auto it=right_collisions.begin(); it!=right_collisions.end(); it++)
449 {
450 if (it->axis < fixed_ox+physics.size.first) continue;
451 if (it->axis > fixed_x+physics.size.first) break;
452
453 if ((fixed_oy+physics.size.second > it->lower) && (fixed_oy < it->upper))
454 {
455 // We have a collision!
456 if (it->type == 0)
457 {
458 physics.position.first = it->axis - physics.size.first;
459 physics.velocity.first = 0;
460 } else if (it->type == 1)
461 {
462 physics.position.first = -physics.size.first/2;
463 } else if (it->type == 2)
464 {
465 physics.position.first = -physics.size.first/2;
466 Game::getInstance().loadMap(map->getRightMap());
467 } else if (it->type == 3)
468 {
469 physics.position.first = it->axis - physics.size.first;
470
471 message_t msg;
472 msg.type = CM_WALK_LEFT;
473 player.send(msg);
474 }
475
476 break;
477 }
478 }
479 }
480
481 fixed_x = (int) physics.position.first;
482 fixed_y = (int) physics.position.second;
483
484 if (fixed_y < fixed_oy)
485 {
486 for (auto it=up_collisions.begin(); it!=up_collisions.end(); it++)
487 {
488 if (it->axis > fixed_oy) continue;
489 if (it->axis < fixed_y) break;
490
491 if ((fixed_x+physics.size.first > it->lower) && (fixed_x < it->upper))
492 {
493 // We have a collision!
494 if (it->type == 0)
495 {
496 physics.position.second = it->axis;
497 physics.velocity.second = 0;
498 } else if (it->type == 1)
499 {
500 physics.position.second = GAME_HEIGHT-physics.size.second/2-1;
501 }
502
503 break;
504 }
505 }
506 } else if (fixed_y > fixed_oy)
507 {
508 for (auto it=down_collisions.begin(); it!=down_collisions.end(); it++)
509 {
510 if (it->axis < fixed_oy+physics.size.second) continue;
511 if (it->axis > fixed_y+physics.size.second) break;
512
513 if ((fixed_x+physics.size.first > it->lower) && (fixed_x < it->upper))
514 {
515 // We have a collision!
516 if (it->type == 0)
517 {
518 physics.position.second = it->axis - physics.size.second;
519 physics.velocity.second = 0;
520 //mob->onGround = true;
521 } else if (it->type == 1)
522 {
523 physics.position.second = -physics.size.second/2;
524 } else if (it->type == 3)
525 {
526 message_t msg;
527 msg.type = CM_DROP;
528 msg.dropAxis = it->axis;
529
530 player.send(msg);
531 }
532
533 break;
534 }
535 }
536 }
537}