summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components.cpp537
-rw-r--r--src/components.h93
-rw-r--r--src/entity.cpp38
-rw-r--r--src/entity.h72
-rw-r--r--src/game.cpp124
-rw-r--r--src/game.h43
-rw-r--r--src/main.cpp67
-rw-r--r--src/map.cpp2
-rw-r--r--src/mapview.cpp393
-rw-r--r--src/mapview.h65
-rw-r--r--src/mob.h12
-rw-r--r--src/renderer.cpp6
-rw-r--r--src/renderer.h2
-rw-r--r--src/state.h13
-rw-r--r--src/world.cpp32
-rw-r--r--src/world.h27
16 files changed, 973 insertions, 553 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}
diff --git a/src/components.h b/src/components.h new file mode 100644 index 0000000..687eab1 --- /dev/null +++ b/src/components.h
@@ -0,0 +1,93 @@
1#ifndef COMPONENTS_H
2#define COMPONENTS_H
3
4#include "entity.h"
5#include <utility>
6#include <list>
7#include "map.h"
8
9class UserMovementComponent : public Component {
10 public:
11 UserMovementComponent(Entity& parent) : Component(parent) {};
12 void input(int key, int action);
13
14 private:
15 bool holdingLeft = false;
16 bool holdingRight = false;
17};
18
19class PhysicsBodyComponent : public Component, public Collidable, public Locatable {
20 public:
21 PhysicsBodyComponent(Entity& parent) : Component(parent) {};
22 void receive(message_t msg);
23 void tick();
24 void detectCollision(Entity& player, Locatable& physics, std::pair<double, double> old_position);
25};
26
27class PlayerSpriteComponent : public Component {
28 public:
29 PlayerSpriteComponent(Entity& parent, Locatable& physics);
30 ~PlayerSpriteComponent();
31 void render(Texture* buffer);
32 void receive(message_t msg);
33 void tick();
34
35 private:
36 Locatable& physics;
37 Texture* sprite;
38 int animFrame = 0;
39 bool facingLeft = false;
40 bool isMoving = false;
41};
42
43class PlayerPhysicsComponent : public Component, public Locatable {
44 public:
45 PlayerPhysicsComponent(Entity& parent);
46 void tick();
47 void receive(message_t msg);
48
49 private:
50 double jump_velocity;
51 double jump_gravity;
52 double jump_gravity_short;
53 int direction = 0;
54 bool canDrop = false;
55};
56
57class MapRenderComponent : public Component {
58 public:
59 MapRenderComponent(Entity& parent, Map* map);
60 ~MapRenderComponent();
61 void render(Texture* buffer);
62
63 private:
64 Texture* screen;
65};
66
67enum direction_t {
68 up, left, down, right
69};
70
71typedef struct {
72 int axis;
73 int lower;
74 int upper;
75 int type;
76} collision_t;
77
78class MapCollisionComponent : public Component, public Collidable {
79 public:
80 MapCollisionComponent(Entity& parent, Map* map);
81 void detectCollision(Entity& player, Locatable& physics, std::pair<double, double> old_position);
82
83 private:
84 void add_collision(int axis, int lower, int upper, direction_t dir, int type);
85
86 std::list<collision_t> left_collisions;
87 std::list<collision_t> right_collisions;
88 std::list<collision_t> up_collisions;
89 std::list<collision_t> down_collisions;
90 Map* map;
91};
92
93#endif
diff --git a/src/entity.cpp b/src/entity.cpp new file mode 100644 index 0000000..405de24 --- /dev/null +++ b/src/entity.cpp
@@ -0,0 +1,38 @@
1#include "entity.h"
2
3void Entity::addComponent(std::shared_ptr<Component> c)
4{
5 components.push_back(c);
6}
7
8void Entity::send(message_t msg)
9{
10 for (auto it = components.begin(); it != components.end(); it++)
11 {
12 (*it)->receive(msg);
13 }
14}
15
16void Entity::tick()
17{
18 for (auto it = components.begin(); it != components.end(); it++)
19 {
20 (*it)->tick();
21 }
22}
23
24void Entity::input(int key, int action)
25{
26 for (auto it = components.begin(); it != components.end(); it++)
27 {
28 (*it)->input(key, action);
29 }
30}
31
32void Entity::render(Texture* buffer)
33{
34 for (auto it = components.begin(); it != components.end(); it++)
35 {
36 (*it)->render(buffer);
37 }
38}
diff --git a/src/entity.h b/src/entity.h new file mode 100644 index 0000000..5a37147 --- /dev/null +++ b/src/entity.h
@@ -0,0 +1,72 @@
1#ifndef ENTITY_H
2#define ENTITY_H
3
4class Entity;
5class Component;
6class Locatable;
7class Collidable;
8
9#include <list>
10#include "renderer.h"
11#include "world.h"
12
13enum message_type {
14 CM_WALK_LEFT,
15 CM_WALK_RIGHT,
16 CM_STOP_WALKING,
17 CM_COLLISION,
18 CM_JUMP,
19 CM_STOP_JUMP,
20 CM_DROP,
21 CM_CAN_DROP,
22 CM_CANT_DROP
23};
24
25typedef struct {
26 message_type type;
27 Entity* collisionEntity;
28 int dropAxis;
29} message_t;
30
31class Entity {
32 public:
33 Entity(World* world) : world(world) {}
34 ~Entity() {};
35 void addComponent(std::shared_ptr<Component> c);
36 void send(message_t msg);
37 void tick();
38 void input(int key, int action);
39 void render(Texture* buffer);
40
41 World* world;
42
43 private:
44 std::list<std::shared_ptr<Component>> components;
45};
46
47class Component {
48 public:
49 Component(Entity& entity) : entity(entity) {}
50 virtual ~Component() {};
51 virtual void receive(message_t msg) {(void)msg;}
52 virtual void render(Texture* tex) {(void)tex;}
53 virtual void tick() {}
54 virtual void input(int key, int action) {(void)key; (void)action;}
55
56 Entity& entity;
57};
58
59class Locatable {
60 public:
61 std::pair<double, double> position;
62 std::pair<int, int> size;
63 std::pair<double, double> velocity;
64 std::pair<double, double> accel;
65};
66
67class Collidable {
68 public:
69 virtual void detectCollision(Entity& player, Locatable& physics, std::pair<double, double> old_position) = 0;
70};
71
72#endif
diff --git a/src/game.cpp b/src/game.cpp new file mode 100644 index 0000000..2db0a2c --- /dev/null +++ b/src/game.cpp
@@ -0,0 +1,124 @@
1#include "game.h"
2#include "renderer.h"
3
4Game::Game()
5{
6 window = initRenderer();
7 glfwSwapInterval(1);
8
9 m = new Map("../maps/embarass.txt");
10 m2 = new Map("../maps/second.txt");
11
12 m->setLeftMap(m2);
13 m2->setRightMap(m);
14
15 world = new World();
16
17 auto player = std::make_shared<Entity>(world);
18
19 auto player_input = std::make_shared<UserMovementComponent>(*player);
20 player->addComponent(player_input);
21
22 auto player_physics = std::make_shared<PlayerPhysicsComponent>(*player);
23 player_physics->position = std::make_pair(100.0,100.0);
24 player_physics->size = std::make_pair(10.0,12.0);
25 player->addComponent(player_physics);
26
27 auto player_anim = std::make_shared<PlayerSpriteComponent>(*player, *player_physics);
28 player->addComponent(player_anim);
29
30 world->addEntity(player);
31 world->player = player;
32
33 loadMap(m);
34}
35
36Game::~Game()
37{
38 if (world != 0)
39 {
40 delete world;
41 }
42
43 if (nextWorld != 0)
44 {
45 delete nextWorld;
46 }
47
48 delete m;
49 delete m2;
50
51 destroyRenderer();
52}
53
54void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
55{
56 (void)window;
57 (void)scancode;
58 (void)mods;
59
60 if ((key == GLFW_KEY_ESCAPE) && (action == GLFW_PRESS))
61 {
62 Game::getInstance().shouldQuit = true;
63 }
64
65 Game::getInstance().input(key, action);
66}
67
68void Game::execute()
69{
70 glfwSetKeyCallback(window, key_callback);
71
72 Texture* buffer = createTexture(GAME_WIDTH, GAME_HEIGHT);
73
74 while (!(shouldQuit || glfwWindowShouldClose(window)))
75 {
76 // Should we load a new world?
77 if (nextWorld != 0)
78 {
79 delete world;
80 world = nextWorld;
81 world->player->world = world;
82 nextWorld = 0;
83 }
84
85 // Handle input
86 glfwPollEvents();
87
88 // Tick!
89 world->tick();
90
91 // Do rendering
92 world->render(buffer);
93 renderScreen(buffer);
94 }
95
96 destroyTexture(buffer);
97}
98
99void Game::input(int key, int action)
100{
101 if (world != NULL)
102 {
103 world->input(key, action);
104 }
105}
106
107void Game::loadMap(Map* map)
108{
109 nextWorld = new World();
110
111 nextWorld->player = world->player;
112
113 auto mapEn = std::make_shared<Entity>(nextWorld);
114
115 auto map_render = std::make_shared<MapRenderComponent>(*mapEn, map);
116 mapEn->addComponent(map_render);
117
118 auto map_collision = std::make_shared<MapCollisionComponent>(*mapEn, map);
119 mapEn->addComponent(map_collision);
120 nextWorld->bodies.push_back(map_collision.get());
121
122 nextWorld->addEntity(mapEn);
123 nextWorld->addEntity(nextWorld->player);
124}
diff --git a/src/game.h b/src/game.h new file mode 100644 index 0000000..69224dc --- /dev/null +++ b/src/game.h
@@ -0,0 +1,43 @@
1#ifndef GAME_H
2#define GAME_H
3
4#include "components.h"
5
6const int TILE_WIDTH = 8;
7const int TILE_HEIGHT = 8;
8const int GAME_WIDTH = 320;
9const int GAME_HEIGHT = 200;
10const int MAP_WIDTH = GAME_WIDTH/TILE_WIDTH;
11const int MAP_HEIGHT = GAME_HEIGHT/TILE_HEIGHT;
12
13const int FRAMES_PER_SECOND = 60;
14const double SECONDS_PER_FRAME = 1.0 / FRAMES_PER_SECOND;
15
16class Game {
17 public:
18 static Game& getInstance()
19 {
20 static Game instance;
21
22 return instance;
23 }
24
25 ~Game();
26 void execute();
27 void loadMap(Map* map);
28 void input(int key, int action);
29
30 bool shouldQuit = false;
31 private:
32 Game();
33 Game(Game const&);
34 void operator=(Game const&);
35
36 GLFWwindow* window;
37 World* world;
38 World* nextWorld;
39 Map* m;
40 Map* m2;
41};
42
43#endif
diff --git a/src/main.cpp b/src/main.cpp index bc7832d..c552d2a 100644 --- a/src/main.cpp +++ b/src/main.cpp
@@ -1,77 +1,14 @@
1#include <ctime> 1#include <ctime>
2#include <list> 2#include <list>
3#include "map.h"
4#include "state.h"
5#include "mapview.h"
6#include "renderer.h" 3#include "renderer.h"
7#include <cstdlib> 4#include <cstdlib>
8 5#include "game.h"
9using namespace::std;
10
11bool quit = false;
12
13State* curGameState;
14
15void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
16{
17 if ((key == GLFW_KEY_ESCAPE) && (action == GLFW_PRESS))
18 {
19 quit = true;
20 }
21
22 if (curGameState != NULL)
23 {
24 curGameState->input(key, action);
25 }
26}
27 6
28int main() 7int main()
29{ 8{
30 srand(time(NULL)); 9 srand(time(NULL));
31 10
32 GLFWwindow* window = initRenderer(); 11 Game::getInstance().execute();
33 glfwSwapInterval(1);
34 glfwSetKeyCallback(window, key_callback);
35
36 Map* m = new Map("../maps/embarass.txt");
37 //Map* m2 = new Map("../maps/cozy.txt");
38
39 //m->setLeftMap(m2);
40 //m2->setRightMap(m);
41
42 curGameState = new MapView(m, 100, 100);
43
44 Texture* buffer = createTexture(GAME_WIDTH, GAME_HEIGHT);
45 //Texture* buffer = loadTextureFromBMP("../res/title.png");
46
47 double lastTime = glfwGetTime();
48 int nbFrames = 0;
49
50 while (!(quit || glfwWindowShouldClose(window)))
51 {
52 double currentTime = glfwGetTime();
53 nbFrames++;
54 if (currentTime - lastTime >= 1.0)
55 {
56 // printf and reset timer
57 printf("%f ms/frame\n", 1000.0/double(nbFrames));
58 nbFrames = 0;
59 lastTime += 1.0;
60 }
61
62 curGameState->tick();
63
64 // Do rendering
65 curGameState->render(buffer);
66 renderScreen(buffer);
67
68 glfwPollEvents();
69 }
70
71 delete curGameState;
72 delete m;
73
74 destroyRenderer();
75 12
76 return 0; 13 return 0;
77} 14}
diff --git a/src/map.cpp b/src/map.cpp index 5f9e7bd..fda8009 100644 --- a/src/map.cpp +++ b/src/map.cpp
@@ -1,5 +1,5 @@
1#include "map.h" 1#include "map.h"
2#include "mapview.h" 2#include "game.h"
3 3
4Map::Map(char* filename) 4Map::Map(char* filename)
5{ 5{
diff --git a/src/mapview.cpp b/src/mapview.cpp deleted file mode 100644 index a85bb31..0000000 --- a/src/mapview.cpp +++ /dev/null
@@ -1,393 +0,0 @@
1#include "mapview.h"
2
3#define JUMP_VELOCITY(h, l) (-2 * (h) / (l))
4#define JUMP_GRAVITY(h, l) (2 * ((h) / (l)) / (l))
5
6// Initialize jump physics
7double jump_height = TILE_HEIGHT*4;
8double jump_length = 0.25 * FRAMES_PER_SECOND;
9//double jump_velocity = -2 * jump_height / jump_length;
10//double jump_gravity = -1 * jump_velocity / jump_length;
11double jump_velocity = JUMP_VELOCITY(TILE_HEIGHT*4, 0.30*FRAMES_PER_SECOND);
12double jump_gravity = JUMP_GRAVITY(TILE_HEIGHT*4, 0.30*FRAMES_PER_SECOND);
13double jump_gravity_short = JUMP_GRAVITY(TILE_HEIGHT*3, 0.20*FRAMES_PER_SECOND);
14
15MapView::MapView(Map* first, int x, int y)
16{
17 // Initialize player data
18 player = new mob_t();
19 player->x = x;
20 player->y = y;
21 player->x_vel = 0;
22 player->y_vel = 0;
23 player->y_accel = jump_gravity_short;
24 player->x_accel = 0;
25 player->w = 10;
26 player->h = 12;
27 player->onGround = false;
28 player->animFrame = 0;
29
30 bg = createTexture(GAME_WIDTH, GAME_HEIGHT);
31 chara = loadTextureFromBMP("../res/Starla.png");
32 tiles = loadTextureFromBMP("../res/tiles.png");
33
34 loadMap(first);
35}
36
37MapView::~MapView()
38{
39 destroyTexture(bg);
40 destroyTexture(chara);
41 destroyTexture(tiles);
42
43 delete player;
44}
45
46void MapView::loadMap(Map* m)
47{
48 curMap = m;
49
50 left_collisions.clear();
51 right_collisions.clear();
52 up_collisions.clear();
53 down_collisions.clear();
54
55 add_collision(-6, 0, GAME_WIDTH, left, (m->getLeftMap() == NULL) ? 1 : 2);
56 add_collision(GAME_WIDTH+6, 0, GAME_WIDTH, right, (m->getRightMap() == NULL) ? 1 : 2);
57
58 fillTexture(bg, NULL, 0, 0, 0);
59
60 const int* mapbuf = m->mapdata();
61
62 for (int i=0; i<MAP_WIDTH*(MAP_HEIGHT-1); i++)
63 {
64 int x = i % MAP_WIDTH;
65 int y = i / MAP_WIDTH;
66 Rectangle dst(x*TILE_WIDTH, y*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT);
67 Rectangle src(mapbuf[i]%8*TILE_WIDTH, mapbuf[i]/8*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT);
68
69 if (mapbuf[i] > 0)
70 {
71 blitTexture(tiles, bg, &src, &dst);
72 }
73 //blitTexture(tiles, bg, &src, &dst);
74
75 if ((mapbuf[i] > 0) && (!((mapbuf[i] >= 5) && (mapbuf[i] <= 7))))
76 {
77 //if ((x != 0) && (mapbuf[i-1] != 'X'))
78 {
79 add_collision(x*TILE_WIDTH, y*TILE_HEIGHT, (y+1)*TILE_HEIGHT, right, 0);
80 }
81
82 //if ((x != 39) && (mapbuf[i+1] != 'X'))
83 {
84 add_collision((x+1)*TILE_WIDTH, y*TILE_HEIGHT, (y+1)*TILE_HEIGHT, left, 0);
85 }
86
87 //if ((y != 0) && (mapbuf[i-MAP_WIDTH] != 'X'))
88 {
89 add_collision(y*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, down, 0);
90 }
91
92 //if ((y != 23) && (mapbuf[i+MAP_WIDTH] != 'X'))
93 {
94 add_collision((y+1)*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, up, 0);
95 }
96 } else if ((mapbuf[i] >= 5) && (mapbuf[i] <= 7))
97 {
98 add_collision(y*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, down, 3);
99 }
100 }
101
102 Texture* font = loadTextureFromBMP("../res/font.bmp");
103 const char* map_name = m->title();
104 int start_x = (40/2) - (strlen(map_name)/2);
105 for (size_t i=0; i<strlen(map_name); i++)
106 {
107 Rectangle srcRect(map_name[i] % 16 * 8, map_name[i] / 16 * 8, 8, 8);
108 Rectangle dstRect((start_x + i)*8, 24*8, 8, 8);
109 blitTexture(font, bg, &srcRect, &dstRect);
110 }
111
112 destroyTexture(font);
113}
114
115void MapView::input(int key, int action)
116{
117 if (action == GLFW_PRESS)
118 {
119 switch (key)
120 {
121 case GLFW_KEY_LEFT:
122 holding_left = true;
123 break;
124 case GLFW_KEY_RIGHT:
125 holding_right = true;
126 break;
127 case GLFW_KEY_UP:
128 if (player->onGround)
129 {
130 player->y_vel = jump_velocity;
131 player->onGround = false;
132 holding_up = true;
133 }
134 break;
135 case GLFW_KEY_DOWN:
136 holding_down = true;
137 break;
138 }
139 } else if (action == GLFW_RELEASE)
140 {
141 switch (key)
142 {
143 case GLFW_KEY_LEFT:
144 holding_left = false;
145 if (!holding_right) player->animFrame = 1;
146 break;
147 case GLFW_KEY_RIGHT:
148 holding_right = false;
149 if (!holding_left) player->animFrame = 0;
150 break;
151 case GLFW_KEY_DOWN:
152 holding_down = false;
153 break;
154 case GLFW_KEY_UP:
155 holding_up = false;
156 break;
157 }
158 }
159}
160
161void MapView::tick()
162{
163 if (holding_left && player->x_vel >= 0)
164 {
165 player->x_vel = -2;
166 } else if (holding_right && player->x_vel <= 0)
167 {
168 player->x_vel = 2;
169 } else if (!holding_left && !holding_right) {
170 player->x_vel = 0;
171 }
172
173 player->x_vel += player->x_accel;
174 if (player->x_vel < -16) player->x_vel = -16;
175 if (player->x_vel > 16) player->x_vel = 16;
176 int playerx_next = player->x + player->x_vel;
177
178 if (holding_up)
179 {
180 player->y_vel += jump_gravity;
181 } else {
182 player->y_vel += jump_gravity_short;
183 }
184
185 if (player->y_vel > 16) player->y_vel = 16; // Terminal velocity
186 if (player->y_vel < -16) player->y_vel = -16;
187 int playery_next = player->y + player->y_vel;
188
189 check_collisions(player, playerx_next, playery_next);
190}
191
192void MapView::render(Texture* tex)
193{
194 if (animFrame == 0)
195 {
196 if (holding_left)
197 {
198 if (player->animFrame == 3)
199 {
200 player->animFrame = 5;
201 } else {
202 player->animFrame = 3;
203 }
204 } else if (holding_right)
205 {
206 if (player->animFrame == 2)
207 {
208 player->animFrame = 4;
209 } else {
210 player->animFrame = 2;
211 }
212 }
213 }
214
215 animFrame++;
216 animFrame %= 10;
217
218 // Draw the background
219 blitTexture(bg, tex, NULL, NULL);
220
221 // Draw the player
222 Rectangle src_rect(player->animFrame * 10, 0, 10, 12);
223 Rectangle dst_rect(player->x, player->y, player->w, player->h);
224 blitTexture(chara, tex, &src_rect, &dst_rect);
225}
226
227void MapView::add_collision(int axis, int lower, int upper, direction_t dir, int type)
228{
229 //printf("added collision\n");
230 list<collision_t>::iterator it;
231
232 switch (dir)
233 {
234 case up:
235 it = up_collisions.begin();
236 for (; it!=up_collisions.end(); it++)
237 {
238 if (it->axis < axis) break;
239 }
240
241 up_collisions.insert(it, {axis, lower, upper, type});
242
243 break;
244 case down:
245 it = down_collisions.begin();
246 for (; it!=down_collisions.end(); it++)
247 {
248 if (it->axis > axis) break;
249 }
250
251 down_collisions.insert(it, {axis, lower, upper, type});
252
253 break;
254 case left:
255 it = left_collisions.begin();
256 for (; it!=left_collisions.end(); it++)
257 {
258 if (it->axis < axis) break;
259 }
260
261 left_collisions.insert(it, {axis, lower, upper, type});
262
263 break;
264 case right:
265 it = right_collisions.begin();
266 for (; it!=right_collisions.end(); it++)
267 {
268 if (it->axis > axis) break;
269 }
270
271 right_collisions.insert(it, {axis, lower, upper, type});
272
273 break;
274 }
275}
276
277void MapView::check_collisions(mob_t* mob, int x_next, int y_next)
278{
279 if (x_next < mob->x)
280 {
281 for (list<collision_t>::iterator it=left_collisions.begin(); it!=left_collisions.end(); it++)
282 {
283 if (it->axis > mob->x) continue;
284 if (it->axis < x_next) break;
285
286 if ((mob->y+mob->h > it->lower) && (mob->y < it->upper))
287 {
288 // We have a collision!
289 if (it->type == 0)
290 {
291 x_next = it->axis;
292 mob->x_vel = 0;
293 } else if (it->type == 1)
294 {
295 x_next = GAME_WIDTH-mob->w/2;
296 } else if (it->type == 2)
297 {
298 x_next = GAME_WIDTH-mob->w/2;
299 loadMap(curMap->getLeftMap());
300 }
301
302 break;
303 }
304 }
305 } else if (x_next > mob->x)
306 {
307 for (list<collision_t>::iterator it=right_collisions.begin(); it!=right_collisions.end(); it++)
308 {
309 if (it->axis < mob->x+mob->w) continue;
310 if (it->axis > x_next+mob->w) break;
311
312 if ((mob->y+mob->h > it->lower) && (mob->y < it->upper))
313 {
314 // We have a collision!
315 if (it->type == 0)
316 {
317 x_next = it->axis - mob->w;
318 mob->x_vel = 0;
319 } else if (it->type == 1)
320 {
321 x_next = -mob->w/2;
322 } else if (it->type == 2)
323 {
324 x_next = -mob->w/2;
325 loadMap(curMap->getRightMap());
326 }
327
328 break;
329 }
330 }
331 }
332
333 mob->x = x_next;
334
335 if (y_next < mob->y)
336 {
337 for (list<collision_t>::iterator it=up_collisions.begin(); it!=up_collisions.end(); it++)
338 {
339 if (it->axis > mob->y) continue;
340 if (it->axis < y_next) break;
341
342 if ((mob->x+mob->w > it->lower) && (mob->x < it->upper))
343 {
344 // We have a collision!
345 if (it->type == 0)
346 {
347 y_next = it->axis;
348 mob->y_vel = 0;
349 } else if (it->type == 1)
350 {
351 y_next = GAME_HEIGHT-mob->h/2-1;
352 }
353
354 break;
355 }
356 }
357 } else if (y_next > mob->y)
358 {
359 for (list<collision_t>::iterator it=down_collisions.begin(); it!=down_collisions.end(); it++)
360 {
361 if (it->axis < mob->y+mob->h) continue;
362 if (it->axis > y_next+mob->h) break;
363
364 if ((mob->x+mob->w > it->lower) && (mob->x < it->upper))
365 {
366 // We have a collision!
367 if (it->type == 0)
368 {
369 y_next = it->axis - mob->h;
370 mob->y_vel = 0;
371 mob->onGround = true;
372 } else if (it->type == 1)
373 {
374 y_next = 1 - mob->h/2;
375 } else if (it->type == 3)
376 {
377 if (holding_down)
378 {
379 holding_down = false;
380 } else {
381 y_next = it->axis - mob->h;
382 mob->y_vel = 0;
383 mob->onGround = true;
384 }
385 }
386
387 break;
388 }
389 }
390 }
391
392 mob->y = y_next;
393}
diff --git a/src/mapview.h b/src/mapview.h deleted file mode 100644 index 505ab25..0000000 --- a/src/mapview.h +++ /dev/null
@@ -1,65 +0,0 @@
1#ifndef MAPVIEW_H
2#define MAPVIEW_H
3
4#include <list>
5#include "state.h"
6#include "mob.h"
7#include "map.h"
8
9using namespace::std;
10
11const int TILE_WIDTH = 8;
12const int TILE_HEIGHT = 8;
13const int GAME_WIDTH = 320;
14const int GAME_HEIGHT = 200;
15const int MAP_WIDTH = GAME_WIDTH/TILE_WIDTH;
16const int MAP_HEIGHT = GAME_HEIGHT/TILE_HEIGHT;
17
18const int FRAMES_PER_SECOND = 60;
19const double SECONDS_PER_FRAME = 1.0 / FRAMES_PER_SECOND;
20
21enum direction_t {
22 up, left, down, right
23};
24
25typedef struct {
26 int axis;
27 int lower;
28 int upper;
29 int type;
30} collision_t;
31
32class MapView : public State {
33 public:
34 MapView(Map* start, int x, int y);
35 ~MapView();
36 void loadMap(Map* m);
37 void input(int key, int action);
38 void tick();
39 void render(Texture* tex);
40
41 private:
42 void add_collision(int axis, int lower, int upper, direction_t dir, int type);
43 void check_collisions(mob_t* mob, int x_next, int y_next);
44
45 list<collision_t> left_collisions;
46 list<collision_t> right_collisions;
47 list<collision_t> up_collisions;
48 list<collision_t> down_collisions;
49
50 Texture* bg = NULL;
51 Texture* chara;
52 Texture* tiles;
53
54 bool holding_left = false;
55 bool holding_right = false;
56 bool holding_down = false;
57 bool holding_up = false;
58 mob_t* player;
59
60 Map* curMap;
61
62 int animFrame = 0;
63};
64
65#endif
diff --git a/src/mob.h b/src/mob.h deleted file mode 100644 index 213b062..0000000 --- a/src/mob.h +++ /dev/null
@@ -1,12 +0,0 @@
1typedef struct {
2 int x;
3 int y;
4 double x_vel;
5 double y_vel;
6 double x_accel;
7 double y_accel;
8 int w;
9 int h;
10 bool onGround;
11 int animFrame;
12} mob_t;
diff --git a/src/renderer.cpp b/src/renderer.cpp index 72de8a9..e7db069 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp
@@ -4,8 +4,8 @@
4#include <vector> 4#include <vector>
5#include <cstdio> 5#include <cstdio>
6#include <cstring> 6#include <cstring>
7#include "mapview.h"
8#include <cstdlib> 7#include <cstdlib>
8#include "game.h"
9 9
10// include stb_image 10// include stb_image
11#define STB_IMAGE_IMPLEMENTATION 11#define STB_IMAGE_IMPLEMENTATION
@@ -405,7 +405,7 @@ GLFWwindow* initRenderer()
405 glGenTextures(1, &scanlinesTex); 405 glGenTextures(1, &scanlinesTex);
406 glBindTexture(GL_TEXTURE_2D, scanlinesTex); 406 glBindTexture(GL_TEXTURE_2D, scanlinesTex);
407 int stdw, stdh; 407 int stdw, stdh;
408 unsigned char* scanlinesTex_data = stbi_load("../res/scanlines_222.bmp", &stdw, &stdh, 0, 3); 408 unsigned char* scanlinesTex_data = stbi_load("../res/scanlines_333.bmp", &stdw, &stdh, 0, 3);
409 flipImageData(scanlinesTex_data, stdw, stdh, 3); 409 flipImageData(scanlinesTex_data, stdw, stdh, 3);
410 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, atdw, atdh, 0, GL_RGB, GL_UNSIGNED_BYTE, scanlinesTex_data); 410 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, atdw, atdh, 0, GL_RGB, GL_UNSIGNED_BYTE, scanlinesTex_data);
411 stbi_image_free(scanlinesTex_data); 411 stbi_image_free(scanlinesTex_data);
@@ -507,7 +507,7 @@ void destroyTexture(Texture* tex)
507 delete tex; 507 delete tex;
508} 508}
509 509
510Texture* loadTextureFromBMP(char* filename) 510Texture* loadTextureFromFile(char* filename)
511{ 511{
512 if (!rendererInitialized) 512 if (!rendererInitialized)
513 { 513 {
diff --git a/src/renderer.h b/src/renderer.h index 144956a..a4e21f7 100644 --- a/src/renderer.h +++ b/src/renderer.h
@@ -35,7 +35,7 @@ GLFWwindow* initRenderer();
35void destroyRenderer(); 35void destroyRenderer();
36Texture* createTexture(int width, int height); 36Texture* createTexture(int width, int height);
37void destroyTexture(Texture* tex); 37void destroyTexture(Texture* tex);
38Texture* loadTextureFromBMP(char* filename); 38Texture* loadTextureFromFile(char* filename);
39void saveTextureToBMP(Texture* tex, char* filename); 39void saveTextureToBMP(Texture* tex, char* filename);
40void fillTexture(Texture* tex, Rectangle* loc, int r, int g, int b); 40void fillTexture(Texture* tex, Rectangle* loc, int r, int g, int b);
41void blitTexture(Texture* srctex, Texture* dsttex, Rectangle* srcrect, Rectangle* dstrect); 41void blitTexture(Texture* srctex, Texture* dsttex, Rectangle* srcrect, Rectangle* dstrect);
diff --git a/src/state.h b/src/state.h deleted file mode 100644 index e7962ec..0000000 --- a/src/state.h +++ /dev/null
@@ -1,13 +0,0 @@
1#ifndef STATE_H
2#define STATE_H
3
4#include "renderer.h"
5
6class State {
7public:
8 virtual void input(int key, int action) = 0;
9 virtual void tick() = 0;
10 virtual void render(Texture* tex) = 0;
11};
12
13#endif
diff --git a/src/world.cpp b/src/world.cpp new file mode 100644 index 0000000..90d9ab8 --- /dev/null +++ b/src/world.cpp
@@ -0,0 +1,32 @@
1#include "world.h"
2
3void World::tick()
4{
5 for (auto it = entities.begin(); it != entities.end(); it++)
6 {
7 (*it)->tick();
8 }
9}
10
11void World::input(int key, int action)
12{
13 for (auto it = entities.begin(); it != entities.end(); it++)
14 {
15 (*it)->input(key, action);
16 }
17}
18
19void World::render(Texture* buffer)
20{
21 fillTexture(buffer, NULL, 0, 0, 0);
22
23 for (auto it = entities.begin(); it != entities.end(); it++)
24 {
25 (*it)->render(buffer);
26 }
27}
28
29void World::addEntity(std::shared_ptr<Entity> e)
30{
31 entities.push_back(e);
32}
diff --git a/src/world.h b/src/world.h new file mode 100644 index 0000000..ad6c788 --- /dev/null +++ b/src/world.h
@@ -0,0 +1,27 @@
1#ifndef WORLD_H
2#define WORLD_H
3
4class World;
5
6#include <list>
7#include "renderer.h"
8#include "entity.h"
9#include <cstdio>
10
11class World {
12 public:
13 World() {};
14 ~World() {};
15 void tick();
16 void input(int key, int action);
17 void render(Texture* buffer);
18 void addEntity(std::shared_ptr<Entity> e);
19
20 std::list<Collidable*> bodies;
21 std::shared_ptr<Entity> player;
22
23 private:
24 std::list<std::shared_ptr<Entity>> entities;
25};
26
27#endif