diff options
author | Kelly Rauchenberger <fefferburbia@gmail.com> | 2015-03-07 11:29:57 -0500 |
---|---|---|
committer | Kelly Rauchenberger <fefferburbia@gmail.com> | 2015-03-07 11:29:57 -0500 |
commit | b53826079429939cdfbda073608cb85be8ba0738 (patch) | |
tree | 3c40de4658f0cea01cd3938f07fe82788ef3dd01 /src | |
parent | 0751446e1d069263d25abcff49a32a380231709a (diff) | |
download | therapy-b53826079429939cdfbda073608cb85be8ba0738.tar.gz therapy-b53826079429939cdfbda073608cb85be8ba0738.tar.bz2 therapy-b53826079429939cdfbda073608cb85be8ba0738.zip |
Created entity-component system
Also tweaked the bloom flicker, tweaked the scanline texture, created a second test map, and created some currently unused sound effects.
Diffstat (limited to 'src')
-rw-r--r-- | src/components.cpp | 537 | ||||
-rw-r--r-- | src/components.h | 93 | ||||
-rw-r--r-- | src/entity.cpp | 38 | ||||
-rw-r--r-- | src/entity.h | 72 | ||||
-rw-r--r-- | src/game.cpp | 124 | ||||
-rw-r--r-- | src/game.h | 43 | ||||
-rw-r--r-- | src/main.cpp | 67 | ||||
-rw-r--r-- | src/map.cpp | 2 | ||||
-rw-r--r-- | src/mapview.cpp | 393 | ||||
-rw-r--r-- | src/mapview.h | 65 | ||||
-rw-r--r-- | src/mob.h | 12 | ||||
-rw-r--r-- | src/renderer.cpp | 6 | ||||
-rw-r--r-- | src/renderer.h | 2 | ||||
-rw-r--r-- | src/state.h | 13 | ||||
-rw-r--r-- | src/world.cpp | 32 | ||||
-rw-r--r-- | src/world.h | 27 |
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 | |||
6 | void 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 | |||
91 | void 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 | |||
105 | void 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 | |||
114 | void 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 | |||
141 | PlayerSpriteComponent::PlayerSpriteComponent(Entity& entity, Locatable& physics) : Component(entity), physics(physics) | ||
142 | { | ||
143 | sprite = loadTextureFromFile("../res/Starla.png"); | ||
144 | } | ||
145 | |||
146 | PlayerSpriteComponent::~PlayerSpriteComponent() | ||
147 | { | ||
148 | destroyTexture(sprite); | ||
149 | } | ||
150 | |||
151 | void 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 | |||
170 | void 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 | |||
186 | void 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 | |||
197 | PlayerPhysicsComponent::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 | |||
206 | void 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 | |||
245 | void 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 | |||
290 | MapRenderComponent::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 | |||
326 | MapRenderComponent::~MapRenderComponent() | ||
327 | { | ||
328 | destroyTexture(screen); | ||
329 | } | ||
330 | |||
331 | void MapRenderComponent::render(Texture* buffer) | ||
332 | { | ||
333 | blitTexture(screen, buffer, NULL, NULL); | ||
334 | } | ||
335 | |||
336 | // Map collision | ||
337 | |||
338 | MapCollisionComponent::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 | |||
364 | void 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 | |||
413 | void 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 | |||
9 | class 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 | |||
19 | class 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 | |||
27 | class 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 | |||
43 | class 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 | |||
57 | class 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 | |||
67 | enum direction_t { | ||
68 | up, left, down, right | ||
69 | }; | ||
70 | |||
71 | typedef struct { | ||
72 | int axis; | ||
73 | int lower; | ||
74 | int upper; | ||
75 | int type; | ||
76 | } collision_t; | ||
77 | |||
78 | class 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 | |||
3 | void Entity::addComponent(std::shared_ptr<Component> c) | ||
4 | { | ||
5 | components.push_back(c); | ||
6 | } | ||
7 | |||
8 | void Entity::send(message_t msg) | ||
9 | { | ||
10 | for (auto it = components.begin(); it != components.end(); it++) | ||
11 | { | ||
12 | (*it)->receive(msg); | ||
13 | } | ||
14 | } | ||
15 | |||
16 | void Entity::tick() | ||
17 | { | ||
18 | for (auto it = components.begin(); it != components.end(); it++) | ||
19 | { | ||
20 | (*it)->tick(); | ||
21 | } | ||
22 | } | ||
23 | |||
24 | void 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 | |||
32 | void 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 | |||
4 | class Entity; | ||
5 | class Component; | ||
6 | class Locatable; | ||
7 | class Collidable; | ||
8 | |||
9 | #include <list> | ||
10 | #include "renderer.h" | ||
11 | #include "world.h" | ||
12 | |||
13 | enum 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 | |||
25 | typedef struct { | ||
26 | message_type type; | ||
27 | Entity* collisionEntity; | ||
28 | int dropAxis; | ||
29 | } message_t; | ||
30 | |||
31 | class 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 | |||
47 | class 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 | |||
59 | class 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 | |||
67 | class 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 | |||
4 | Game::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 | |||
36 | Game::~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 | |||
54 | void 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 | |||
68 | void 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 | |||
99 | void Game::input(int key, int action) | ||
100 | { | ||
101 | if (world != NULL) | ||
102 | { | ||
103 | world->input(key, action); | ||
104 | } | ||
105 | } | ||
106 | |||
107 | void 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 | |||
6 | const int TILE_WIDTH = 8; | ||
7 | const int TILE_HEIGHT = 8; | ||
8 | const int GAME_WIDTH = 320; | ||
9 | const int GAME_HEIGHT = 200; | ||
10 | const int MAP_WIDTH = GAME_WIDTH/TILE_WIDTH; | ||
11 | const int MAP_HEIGHT = GAME_HEIGHT/TILE_HEIGHT; | ||
12 | |||
13 | const int FRAMES_PER_SECOND = 60; | ||
14 | const double SECONDS_PER_FRAME = 1.0 / FRAMES_PER_SECOND; | ||
15 | |||
16 | class 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" | |
9 | using namespace::std; | ||
10 | |||
11 | bool quit = false; | ||
12 | |||
13 | State* curGameState; | ||
14 | |||
15 | void 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 | ||
28 | int main() | 7 | int 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 | ||
4 | Map::Map(char* filename) | 4 | Map::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 | ||
7 | double jump_height = TILE_HEIGHT*4; | ||
8 | double 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; | ||
11 | double jump_velocity = JUMP_VELOCITY(TILE_HEIGHT*4, 0.30*FRAMES_PER_SECOND); | ||
12 | double jump_gravity = JUMP_GRAVITY(TILE_HEIGHT*4, 0.30*FRAMES_PER_SECOND); | ||
13 | double jump_gravity_short = JUMP_GRAVITY(TILE_HEIGHT*3, 0.20*FRAMES_PER_SECOND); | ||
14 | |||
15 | MapView::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 | |||
37 | MapView::~MapView() | ||
38 | { | ||
39 | destroyTexture(bg); | ||
40 | destroyTexture(chara); | ||
41 | destroyTexture(tiles); | ||
42 | |||
43 | delete player; | ||
44 | } | ||
45 | |||
46 | void 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 | |||
115 | void 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 | |||
161 | void 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 | |||
192 | void 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 | |||
227 | void 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 | |||
277 | void 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 | |||
9 | using namespace::std; | ||
10 | |||
11 | const int TILE_WIDTH = 8; | ||
12 | const int TILE_HEIGHT = 8; | ||
13 | const int GAME_WIDTH = 320; | ||
14 | const int GAME_HEIGHT = 200; | ||
15 | const int MAP_WIDTH = GAME_WIDTH/TILE_WIDTH; | ||
16 | const int MAP_HEIGHT = GAME_HEIGHT/TILE_HEIGHT; | ||
17 | |||
18 | const int FRAMES_PER_SECOND = 60; | ||
19 | const double SECONDS_PER_FRAME = 1.0 / FRAMES_PER_SECOND; | ||
20 | |||
21 | enum direction_t { | ||
22 | up, left, down, right | ||
23 | }; | ||
24 | |||
25 | typedef struct { | ||
26 | int axis; | ||
27 | int lower; | ||
28 | int upper; | ||
29 | int type; | ||
30 | } collision_t; | ||
31 | |||
32 | class 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 @@ | |||
1 | typedef 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 | ||
510 | Texture* loadTextureFromBMP(char* filename) | 510 | Texture* 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(); | |||
35 | void destroyRenderer(); | 35 | void destroyRenderer(); |
36 | Texture* createTexture(int width, int height); | 36 | Texture* createTexture(int width, int height); |
37 | void destroyTexture(Texture* tex); | 37 | void destroyTexture(Texture* tex); |
38 | Texture* loadTextureFromBMP(char* filename); | 38 | Texture* loadTextureFromFile(char* filename); |
39 | void saveTextureToBMP(Texture* tex, char* filename); | 39 | void saveTextureToBMP(Texture* tex, char* filename); |
40 | void fillTexture(Texture* tex, Rectangle* loc, int r, int g, int b); | 40 | void fillTexture(Texture* tex, Rectangle* loc, int r, int g, int b); |
41 | void blitTexture(Texture* srctex, Texture* dsttex, Rectangle* srcrect, Rectangle* dstrect); | 41 | void 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 | |||
6 | class State { | ||
7 | public: | ||
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 | |||
3 | void World::tick() | ||
4 | { | ||
5 | for (auto it = entities.begin(); it != entities.end(); it++) | ||
6 | { | ||
7 | (*it)->tick(); | ||
8 | } | ||
9 | } | ||
10 | |||
11 | void 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 | |||
19 | void 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 | |||
29 | void 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 | |||
4 | class World; | ||
5 | |||
6 | #include <list> | ||
7 | #include "renderer.h" | ||
8 | #include "entity.h" | ||
9 | #include <cstdio> | ||
10 | |||
11 | class 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 | ||