so://phie

freezo

A retro platform game
git clone git://soophie.de/freezo

feat: Added doors & updated levels


commit: 34267decfdf74e85e5b74df2d07cfaf43c531275
parent: daadafd033e5442fbd78ef33c5c3f96f52b36767
author: Sophie <info@soophie.de>
time: 2024-12-16 13:16

diff --git a/assets/background.png b/assets/background.png

index dd58683..dcdc44a 100644

Binary files a/assets/background.png and b/assets/background.png differ

diff --git a/assets/tiles.png b/assets/tiles.png

index 412b610..c4b6692 100644

Binary files a/assets/tiles.png and b/assets/tiles.png differ

diff --git a/include/door.h b/include/door.h

new file mode 100644

index 0000000..6f41e1f

--- /dev/null

+++ b/include/door.h

1@@ -0,0 +1,21 @@

2+#pragma once

3+

4+typedef struct Door door_t;

5+

6+#include "game.h"

7+#include "util.h"

8+

9+#define DOOR_COUNTDOWN 20

10+

11+struct Door {

12+ pos_t pos;

13+ bool is_locked;

14+ int countdown;

15+};

16+

17+door_t *door_create(pos_t pos);

18+void door_update(door_t *door, game_t *game);

19+void door_draw(door_t *door, game_t *game);

20+void door_free(door_t *door);

21+

22+bool door_unlock(door_t *door, game_t *game);

23

24

diff --git a/include/entity.h b/include/entity.h

index 0524eee..bdccd78 100644

--- a/include/entity.h

+++ b/include/entity.h

1@@ -5,10 +5,12 @@ typedef struct Entity entity_t;

2 #include "enemy.h"

3 #include "gate.h"

4 #include "game.h"

5+#include "door.h"

6

7 typedef enum {

8 ENTITY_ENEMY,

9 ENTITY_GATE,

10+ ENTITY_DOOR,

11 } entity_e;

12

13 struct Entity {

14@@ -16,7 +18,9 @@ struct Entity {

15 union {

16 enemy_t *enemy;

17 gate_t *gate;

18+ door_t *door;

19 };

20+ bool is_bad;

21 };

22

23 entity_t *entity_create(entity_e type);

24

25

diff --git a/src/door.c b/src/door.c

new file mode 100644

index 0000000..c1633a2

--- /dev/null

+++ b/src/door.c

1@@ -0,0 +1,65 @@

2+#include <stdlib.h>

3+

4+#include "../include/door.h"

5+#include "../include/const.h"

6+

7+door_t *door_create(pos_t pos) {

8+ door_t *door = malloc(sizeof(door_t));

9+ door->pos = pos;

10+ door->is_locked = true;

11+ door->countdown = 0;

12+ return door;

13+}

14+

15+void door_update(door_t *door, game_t *game) {

16+ (void) game;

17+ if (door->countdown > 0) {

18+ door->countdown--;

19+ }

20+}

21+

22+void door_draw(door_t *door, game_t *game) {

23+ if (door->is_locked) {

24+ DrawTextureRec(game->assets.tiles, texture_rect(1, 2, TILE_WIDTH, TILE_HEIGHT), (pos_t) { door->pos.x, door->pos.y - TILE_HEIGHT }, WHITE);

25+ DrawTextureRec(game->assets.tiles, texture_rect(1, 3, TILE_WIDTH, TILE_HEIGHT), door->pos, WHITE);

26+ if (door->countdown > 0) {

27+ pos_t lock_pos = {

28+ .x = door->pos.x,

29+ .y = door->pos.y - 2 * TILE_HEIGHT,

30+ };

31+ DrawTextureRec(game->assets.tiles, texture_rect(3, 1, TILE_WIDTH, TILE_HEIGHT), lock_pos, WHITE);

32+ }

33+ }

34+ else {

35+ DrawTextureRec(game->assets.tiles, texture_rect(2, 2, TILE_WIDTH, TILE_HEIGHT), (pos_t) { door->pos.x, door->pos.y - TILE_HEIGHT }, WHITE);

36+ DrawTextureRec(game->assets.tiles, texture_rect(2, 3, TILE_WIDTH, TILE_HEIGHT), door->pos, WHITE);

37+ }

38+}

39+

40+void door_free(door_t *door) {

41+ free(door);

42+}

43+

44+bool door_unlock(door_t *door, game_t *game) {

45+ if (!door->is_locked) {

46+ return true;

47+ }

48+ int enemies_len = 0;

49+ bool gates_frozen = true;

50+ for (int i = 0; i < game->entities_len; i++) {

51+ if(game->entities[i].type == ENTITY_ENEMY) {

52+ enemies_len++;

53+ }

54+ if(game->entities[i].type == ENTITY_GATE) {

55+ if (!game->entities[i].gate->frozen) {

56+ gates_frozen = false;

57+ }

58+ }

59+ }

60+ if (enemies_len == 0 && gates_frozen) {

61+ door->is_locked = false;

62+ return true;

63+ }

64+ door->countdown = DOOR_COUNTDOWN;

65+ return false;

66+}

67

68

diff --git a/src/entity.c b/src/entity.c

index 5ee085a..60c9329 100644

--- a/src/entity.c

+++ b/src/entity.c

1@@ -3,10 +3,22 @@

2 #include "../include/entity.h"

3 #include "../include/enemy.h"

4 #include "../include/gate.h"

5+#include "../include/door.h"

6

7 entity_t *entity_create(entity_e type) {

8 entity_t *entity = malloc(sizeof(entity_t));

9 entity->type = type;

10+ switch (entity->type) {

11+ case ENTITY_ENEMY:

12+ entity->is_bad = true;

13+ break;

14+ case ENTITY_GATE:

15+ entity->is_bad = true;

16+ break;

17+ case ENTITY_DOOR:

18+ entity->is_bad = false;

19+ break;

20+ }

21 return entity;

22 }

23

24@@ -18,6 +30,9 @@ void entity_update(entity_t *entity, game_t *game) {

25 case ENTITY_GATE:

26 gate_update(entity->gate, game);

27 break;

28+ case ENTITY_DOOR:

29+ door_update(entity->door, game);

30+ break;

31 }

32 }

33

34@@ -29,6 +44,9 @@ void entity_draw(entity_t *entity, game_t *game) {

35 case ENTITY_GATE:

36 gate_draw(entity->gate, game);

37 break;

38+ case ENTITY_DOOR:

39+ door_draw(entity->door, game);

40+ break;

41 }

42 }

43

44@@ -40,6 +58,9 @@ void entity_detach(entity_t *entity) {

45 case ENTITY_GATE:

46 gate_free(entity->gate);

47 break;

48+ case ENTITY_DOOR:

49+ door_free(entity->door);

50+ break;

51 }

52 }

53

54

55

diff --git a/src/game.c b/src/game.c

index 39d3ef9..f5675f0 100644

--- a/src/game.c

+++ b/src/game.c

1@@ -58,8 +58,9 @@ void game_update(game_t *game) {

2 // defeat

3 if (game->defeat) {

4 if (game->sceen_timer == 100) {

5+ level_e level = game->level->type;

6 level_unload(game);

7- level_load(game, LEVEL_1);

8+ level_load(game, level);

9 game->defeat = false;

10 game->xp = 0;

11 game->sceen_timer = 0;

12@@ -69,34 +70,19 @@ void game_update(game_t *game) {

13 }

14 }

15 // victory

16- int enemies_len = 0;

17- bool gates_frozen = true;

18- for (int i = 0; i < game->entities_len; i++) {

19- if(game->entities[i].type == ENTITY_ENEMY) {

20- enemies_len++;

21- }

22- if(game->entities[i].type == ENTITY_GATE) {

23- if (!game->entities[i].gate->frozen) {

24- gates_frozen = false;

25+ if (game->victory) {

26+ if (game->sceen_timer == 100) {

27+ if (game->level->type < LEVELS) {

28+ level_e level = game->level->type;

29+ level++;

30+ level_unload(game);

31+ level_load(game, level);

32 }

33+ game->victory = false;

34+ game->sceen_timer = 0;

35 }

36- }

37- if (enemies_len == 0 && gates_frozen) {

38- game->victory = true;

39- if (game->victory) {

40- if (game->sceen_timer == 100) {

41- if (game->level->type < LEVELS) {

42- level_e level = game->level->type;

43- level++;

44- level_unload(game);

45- level_load(game, level);

46- }

47- game->victory = false;

48- game->sceen_timer = 0;

49- }

50- else {

51- game->sceen_timer++;

52- }

53+ else {

54+ game->sceen_timer++;

55 }

56 }

57 if (!game->victory && !game->defeat) {

58

59

diff --git a/src/level.c b/src/level.c

index 1c8f3b1..e84fd41 100644

--- a/src/level.c

+++ b/src/level.c

1@@ -14,12 +14,12 @@ const char *LEVEL_MAP_1 = {

2 "........................"

3 "........................"

4 "......e......3.........."

5- "....xxxx................"

6+ "....xxxxx..............."

7 ".....b.................."

8 "...........--...xxx....."

9 "................e......."

10 "...........2...--xxxxx.."

11- "....p..................."

12+ "....p....u.............."

13 "..xxxxxxxxx---xxxxxxxx.."

14 "........................"

15 "........................"

16@@ -30,7 +30,7 @@ const char *LEVEL_MAP_2 = {

17 "........................"

18 "......3....b............"

19 "........................"

20- "........................"

21+ "................u......."

22 "...............xxxx....."

23 "..o......s.e............"

24 ".......xxxxxxtxxx--xx..."

25@@ -51,8 +51,8 @@ const char *LEVEL_MAP_3 = {

26 "............-txx-......."

27 ".............w.........."

28 "............-w..-......."

29- "........s....w.........."

30- "..x---xxxxxxxtxxx--xx..."

31+ "........s....w......u..."

32+ "..x---xxxxxxxtxxx--xxx.."

33 "....e........w....e....."

34 "...---....2..w--txxx...."

35 "....3........w..w......."

36@@ -176,6 +176,7 @@ void level_generate(game_t *game, const char *map, int width, int height) {

37 game->entities[game->entities_len] = (entity_t) {

38 .type = ENTITY_ENEMY,

39 .enemy = enemy,

40+ .is_bad = true,

41 };

42 game->entities_len++;

43 break;

44@@ -189,6 +190,21 @@ void level_generate(game_t *game, const char *map, int width, int height) {

45 game->entities[game->entities_len] = (entity_t) {

46 .type = ENTITY_GATE,

47 .gate = gate,

48+ .is_bad = true,

49+ };

50+ game->entities_len++;

51+ break;

52+ }

53+ case 'u': {

54+ game->entities = realloc(game->entities, sizeof(enemy_t) * (game->entities_len + 1));

55+ door_t *door = door_create((pos_t) {

56+ .x = x * TILE_WIDTH + (TILE_WIDTH - ENEMY_WIDTH) / 2.0,

57+ .y = y * TILE_HEIGHT,

58+ });

59+ game->entities[game->entities_len] = (entity_t) {

60+ .type = ENTITY_DOOR,

61+ .door = door,

62+ .is_bad = false,

63 };

64 game->entities_len++;

65 break;

66

67

diff --git a/src/player.c b/src/player.c

index fd05da3..d983ed4 100644

--- a/src/player.c

+++ b/src/player.c

1@@ -248,6 +248,10 @@ void player_update(player_t *player, game_t *game) {

2 if (entity->type == ENTITY_GATE && entity->gate->frozen) {

3 continue;

4 }

5+ // ignore non-bad entities

6+ if (!entity->is_bad) {

7+ continue;

8+ }

9 rect_t entity_rect;

10 switch (entity->type) {

11 case ENTITY_ENEMY:

12@@ -256,6 +260,9 @@ void player_update(player_t *player, game_t *game) {

13 case ENTITY_GATE:

14 entity_rect = rect_from_pos((pos_t) { entity->gate->pos.x, entity->gate->pos.y - TILE_HEIGHT }, ENEMY_WIDTH, ENEMY_HEIGHT);

15 break;

16+ case ENTITY_DOOR:

17+ entity_rect = rect_from_pos((pos_t) { entity->gate->pos.x, entity->gate->pos.y - TILE_HEIGHT }, ENEMY_WIDTH, ENEMY_HEIGHT);

18+ break;

19 }

20 if (rect_collide(shooting_rect, entity_rect)) {

21 float entity_x = entity_rect.x + entity_rect.width / 2.0;

22@@ -314,8 +321,8 @@ void player_update(player_t *player, game_t *game) {

23 float tolerance = 0.0;

24 if (

25 player->pos.x <= enemy->pos.x + ENEMY_WIDTH - tolerance &&

26- player->pos.x + PLAYER_WIDTH >= enemy->pos.x + tolerance &&

27- player->pos.y <= enemy->pos.y + ENEMY_HEIGHT - tolerance &&

28+ player->pos.x + PLAYER_WIDTH >= enemy->pos.x + tolerance &&

29+ player->pos.y <= enemy->pos.y + ENEMY_HEIGHT - tolerance &&

30 player->pos.y + PLAYER_HEIGHT >= enemy->pos.y + tolerance

31 ) {

32 if (player->held_enemy == NULL) {

33@@ -336,6 +343,25 @@ void player_update(player_t *player, game_t *game) {

34 .y = player->pos.y - (player->sneaking ? 0.3 : 0.5) * TILE_HEIGHT,

35 };

36 }

37+ // detect door entering

38+ if (holding) {

39+ for (int i = 0; i < game->entities_len; i++) {

40+ if (game->entities[i].type == ENTITY_DOOR) {

41+ door_t *door = game->entities[i].door;

42+ float tolerance = 0.0;

43+ if (

44+ player->pos.x <= door->pos.x + ENEMY_WIDTH - tolerance &&

45+ player->pos.x + PLAYER_WIDTH >= door->pos.x + tolerance &&

46+ player->pos.y <= door->pos.y + ENEMY_HEIGHT - tolerance &&

47+ player->pos.y + PLAYER_HEIGHT >= door->pos.y + tolerance

48+ ) {

49+ if (door_unlock(door, game)) {

50+ game->victory = true;

51+ }

52+ }

53+ }

54+ }

55+ }

56 // detect damage

57 for (int i = 0; i < game->entities_len; i++) {

58 if (game->entities[i].type == ENTITY_ENEMY) {

59@@ -344,8 +370,8 @@ void player_update(player_t *player, game_t *game) {

60 float tolerance = TILE_WIDTH / 5.0;

61 if (

62 player->pos.x <= enemy->pos.x + ENEMY_WIDTH - tolerance &&

63- player->pos.x + PLAYER_WIDTH >= enemy->pos.x + tolerance &&

64- player->pos.y <= enemy->pos.y + ENEMY_HEIGHT - tolerance &&

65+ player->pos.x + PLAYER_WIDTH >= enemy->pos.x + tolerance &&

66+ player->pos.y <= enemy->pos.y + ENEMY_HEIGHT - tolerance &&

67 player->pos.y + PLAYER_HEIGHT >= enemy->pos.y + tolerance

68 ) {

69 if (player->damage_timer == 0) {

70

71