so://phie

freezo

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

feat: Added boss (unstable) & redesigned entity/background textures


commit: 0619481f3da52146179ce4c102f7011515b6c52c
parent: cc01827ef453d3e9c4cd93c85f774f0aa6486746
author: Sophie <info@soophie.de>
time: 2024-12-16 23:48

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

index dcdc44a..2fa9e50 100644

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

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

index df2bead..9029169 100644

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

diff --git a/assets/locked.wav b/assets/locked.wav

new file mode 100644

index 0000000..cb87c85

Binary files /dev/null and b/assets/locked.wav differ

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

new file mode 100644

index 0000000..d67b88e

--- /dev/null

+++ b/include/boss.h

1@@ -0,0 +1,31 @@

2+#pragma once

3+

4+typedef struct Boss boss_t;

5+

6+#include "game.h"

7+#include "util.h"

8+

9+typedef enum {

10+ BOSS_TEST,

11+} boss_e;

12+

13+struct Boss {

14+ pos_t pos;

15+ boss_e type;

16+ bool on_ground;

17+ float velocity;

18+ float gravity;

19+ int dir;

20+ bool stunned;

21+ bool frozen;

22+ int frozen_timer;

23+ float fall_height;

24+ fz_timer_t *timer_walking;

25+ fz_timer_t *timer_sneaking;

26+};

27+

28+boss_t *boss_create(pos_t pos, boss_e type);

29+void boss_update(boss_t *boss, game_t *game);

30+void boss_draw(boss_t *boss, game_t *game);

31+void boss_kill(boss_t *boss, game_t *game);

32+void boss_free(boss_t *boss);

33

34

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

index bdccd78..41a34bb 100644

--- a/include/entity.h

+++ b/include/entity.h

1@@ -6,11 +6,13 @@ typedef struct Entity entity_t;

2 #include "gate.h"

3 #include "game.h"

4 #include "door.h"

5+#include "boss.h"

6

7 typedef enum {

8 ENTITY_ENEMY,

9 ENTITY_GATE,

10 ENTITY_DOOR,

11+ ENTITY_BOSS,

12 } entity_e;

13

14 struct Entity {

15@@ -19,6 +21,7 @@ struct Entity {

16 enemy_t *enemy;

17 gate_t *gate;

18 door_t *door;

19+ boss_t *boss;

20 };

21 bool is_bad;

22 };

23

24

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

index 7b1385d..12cec31 100644

--- a/include/game.h

+++ b/include/game.h

1@@ -25,6 +25,7 @@ struct Assets {

2 Texture2D images;

3 Texture2D background;

4 Sound track;

5+ Sound locked;

6 };

7

8 struct Game {

9@@ -46,6 +47,7 @@ struct Game {

10 int xp;

11 int sceen_timer;

12 door_t *door;

13+ RenderTexture2D overlay;

14 };

15

16 game_t *game_create(void);

17

18

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

index b38da60..5aeba23 100644

--- a/include/tile.h

+++ b/include/tile.h

1@@ -15,7 +15,8 @@ typedef enum {

2 TILE_SNOW,

3 TILE_SAND,

4 TILE_BG_CHANDELIER,

5- TILE_BG_WINDOW,

6+ TILE_BG_WINDOW_1,

7+ TILE_BG_WINDOW_2,

8 TILE_BG_BANNER,

9 TILE_BG_BRICK_1,

10 TILE_BG_BRICK_2,

11

12

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

new file mode 100644

index 0000000..3b68016

--- /dev/null

+++ b/src/boss.c

1@@ -0,0 +1,58 @@

2+#include <stdlib.h>

3+#include <math.h>

4+

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

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

7+#include "../include/entity.h"

8+#include "../include/effect.h"

9+

10+boss_t *boss_create(pos_t pos, boss_e type) {

11+ boss_t *boss = malloc(sizeof(boss_t));

12+ *boss = (boss_t) {

13+ .pos = pos,

14+ .type = type,

15+ .on_ground = false,

16+ .velocity = 0.0,

17+ .gravity = 0.0,

18+ .dir = 1,

19+ .stunned = false,

20+ .frozen = false,

21+ .frozen_timer = 0,

22+ .fall_height = 0.0,

23+ .timer_walking = fz_timer_create(9, 8),

24+ .timer_sneaking = fz_timer_create(9, 16),

25+ };

26+ return boss;

27+}

28+

29+void boss_update(boss_t *boss, game_t *game) {

30+ (void) boss;

31+ (void) game;

32+}

33+

34+void boss_draw(boss_t *boss, game_t *game) {

35+ pos_t pos = pos_snap(boss->pos);

36+ DrawTextureRec(game->assets.entities, texture_rect_v(10, 6, 2, 1, ENEMY_WIDTH, ENEMY_HEIGHT), pos, WHITE);

37+}

38+

39+void boss_kill(boss_t *boss, game_t *game) {

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

41+ if (game->entities[i].type == ENTITY_BOSS && game->entities[i].boss == boss) {

42+ if (i + 1 < game->entities_len) {

43+ for (int j = i; j < game->entities_len - 1; j++) {

44+ game->entities[j] = game->entities[j + 1];

45+ }

46+ }

47+ game->entities_len--;

48+ game->entities = realloc(game->entities, sizeof(entity_t) * game->entities_len);

49+ game->xp += 10;

50+ break;

51+ }

52+ }

53+}

54+

55+void boss_free(boss_t *boss) {

56+ fz_timer_free(boss->timer_walking);

57+ fz_timer_free(boss->timer_sneaking);

58+ free(boss);

59+}

60

61

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

index 53c84ba..4dd7151 100644

--- a/src/enemy.c

+++ b/src/enemy.c

1@@ -171,10 +171,10 @@ void enemy_draw(enemy_t *enemy, game_t *game) {

2 int frame_walking = fz_timer_get(enemy->timer_walking);

3 int frame_sneaking = fz_timer_get(enemy->timer_sneaking);

4 if (enemy->dir > 0) {

5- DrawTextureRec(game->assets.entities, texture_rect(enemy->stunned ? frame_sneaking : frame_walking, 8, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE);

6+ DrawTextureRec(game->assets.entities, texture_rect(enemy->stunned ? frame_sneaking : frame_walking, 10, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE);

7 }

8 else {

9- DrawTextureRec(game->assets.entities, texture_rect(enemy->stunned ? frame_sneaking : frame_walking, 9, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE);

10+ DrawTextureRec(game->assets.entities, texture_rect(enemy->stunned ? frame_sneaking : frame_walking, 11, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE);

11 }

12 if (enemy->frozen) {

13 if (enemy->frozen_timer <= 1200) {

14

15

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

index 60c9329..5c7c32f 100644

--- a/src/entity.c

+++ b/src/entity.c

1@@ -18,6 +18,9 @@ entity_t *entity_create(entity_e type) {

2 case ENTITY_DOOR:

3 entity->is_bad = false;

4 break;

5+ case ENTITY_BOSS:

6+ entity->is_bad = true;

7+ break;

8 }

9 return entity;

10 }

11@@ -33,6 +36,9 @@ void entity_update(entity_t *entity, game_t *game) {

12 case ENTITY_DOOR:

13 door_update(entity->door, game);

14 break;

15+ case ENTITY_BOSS:

16+ boss_update(entity->boss, game);

17+ break;

18 }

19 }

20

21@@ -47,6 +53,9 @@ void entity_draw(entity_t *entity, game_t *game) {

22 case ENTITY_DOOR:

23 door_draw(entity->door, game);

24 break;

25+ case ENTITY_BOSS:

26+ boss_draw(entity->boss, game);

27+ break;

28 }

29 }

30

31@@ -61,6 +70,9 @@ void entity_detach(entity_t *entity) {

32 case ENTITY_DOOR:

33 door_free(entity->door);

34 break;

35+ case ENTITY_BOSS:

36+ boss_free(entity->boss);

37+ break;

38 }

39 }

40

41

42

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

index b30bb09..2034b44 100644

--- a/src/game.c

+++ b/src/game.c

1@@ -33,6 +33,7 @@ game_t *game_create(void) {

2 .assets.images = texture_load("assets/images.png", SCALE),

3 .assets.background = texture_load("assets/background.png", SCALE),

4 .assets.track = LoadSound("assets/track.wav"),

5+ .assets.locked = LoadSound("assets/locked.wav"),

6 .camera = (Camera2D) {

7 .offset = (pos_t) { 0.0, 0.0 },

8 .zoom = 1,

9@@ -40,6 +41,7 @@ game_t *game_create(void) {

10 .xp = 0,

11 .sceen_timer = 0,

12 .door = NULL,

13+ .overlay = LoadRenderTexture(WINDOW_WIDTH, WINDOW_HEIGHT),

14 };

15 level_load(game, LEVEL_1);

16 return game;

17@@ -137,8 +139,7 @@ void game_update(game_t *game) {

18

19 void game_draw(game_t *game) {

20 // render overlay

21- RenderTexture2D overlay_texture = LoadRenderTexture(WINDOW_WIDTH, WINDOW_HEIGHT);

22- BeginTextureMode(overlay_texture);

23+ BeginTextureMode(game->overlay);

24 ClearBackground(BLACK);

25 DrawRectangle(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, BLACK);

26 BeginBlendMode(BLEND_SUBTRACT_COLORS);

27@@ -168,7 +169,7 @@ void game_draw(game_t *game) {

28 effect_draw(game->effects[i], game);

29 }

30 // draw overlay

31- DrawTexture(overlay_texture.texture, 0, 0, WHITE);

32+ DrawTexture(game->overlay.texture, 0, 0, WHITE);

33 EndMode2D();

34 // draw interface

35 int i = 0;

36@@ -201,7 +202,6 @@ void game_draw(game_t *game) {

37 menu_draw(game->menu, game);

38 }

39 EndDrawing();

40- UnloadRenderTexture(overlay_texture);

41 }

42

43 void game_free(game_t *game) {

44@@ -215,5 +215,7 @@ void game_free(game_t *game) {

45 UnloadTexture(game->assets.images);

46 UnloadTexture(game->assets.background);

47 UnloadSound(game->assets.track);

48+ UnloadSound(game->assets.locked);

49+ UnloadRenderTexture(game->overlay);

50 free(game);

51 }

52

53

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

index e84fd41..3e2cc46 100644

--- a/src/level.c

+++ b/src/level.c

1@@ -9,7 +9,7 @@

2 const char *LEVEL_MAP_1 = {

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

4 "........................"

5- "........k.......o......."

6+ "........k.......O......."

7 "..1....................."

8 "........................"

9 "........................"

10@@ -32,9 +32,9 @@ const char *LEVEL_MAP_2 = {

11 "........................"

12 "................u......."

13 "...............xxxx....."

14- "..o......s.e............"

15+ ".........s.e............"

16 ".......xxxxxxtxxx--xx..."

17- ".............w.........."

18+ "...o.........w.........."

19 ".........2...w...--.1..."

20 ".............w.........."

21 ".........----x...--....."

22@@ -140,8 +140,11 @@ void level_generate(game_t *game, const char *map, int width, int height) {

23 case 'k':

24 tile->type = TILE_BG_CHANDELIER;

25 break;

26+ case 'O':

27+ tile->type = TILE_BG_WINDOW_1;

28+ break;

29 case 'o':

30- tile->type = TILE_BG_WINDOW;

31+ tile->type = TILE_BG_WINDOW_2;

32 break;

33 case 'b':

34 tile->type = TILE_BG_BANNER;

35@@ -209,6 +212,20 @@ void level_generate(game_t *game, const char *map, int width, int height) {

36 game->entities_len++;

37 break;

38 }

39+ case 'z': {

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

41+ boss_t *boss = boss_create((pos_t) {

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

43+ .y = y * TILE_HEIGHT,

44+ }, BOSS_TEST);

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

46+ .type = ENTITY_BOSS,

47+ .boss = boss,

48+ .is_bad = true,

49+ };

50+ game->entities_len++;

51+ break;

52+ }

53 default:

54 break;

55 }

56

57

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

index 352073f..d24d4f3 100644

--- a/src/player.c

+++ b/src/player.c

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

2 case ENTITY_DOOR:

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

4 break;

5+ case ENTITY_BOSS:

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

7+ break;

8 }

9 if (rect_collide(shooting_rect, entity_rect)) {

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

11@@ -359,6 +362,9 @@ void player_update(player_t *player, game_t *game) {

12 game->door = door;

13 game->victory = true;

14 }

15+ else {

16+ PlaySound(game->assets.locked);

17+ }

18 }

19 }

20 }

21@@ -420,18 +426,18 @@ void player_draw(player_t *player, game_t *game) {

22 if (player->damage_timer / 4 % 2 == 0) {

23 if (player->sneaking) {

24 if (player->dir > 0) {

25- DrawTextureRec(game->assets.entities, texture_rect(frame, 6, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE);

26+ DrawTextureRec(game->assets.entities, texture_rect(frame, 14, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE);

27 }

28 else {

29- DrawTextureRec(game->assets.entities, texture_rect(frame, 7, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE);

30+ DrawTextureRec(game->assets.entities, texture_rect(frame, 15, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE);

31 }

32 }

33 else {

34 if (player->dir > 0) {

35- DrawTextureRec(game->assets.entities, texture_rect(frame, 4, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE);

36+ DrawTextureRec(game->assets.entities, texture_rect(frame, 12, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE);

37 }

38 else {

39- DrawTextureRec(game->assets.entities, texture_rect(frame, 5, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE);

40+ DrawTextureRec(game->assets.entities, texture_rect(frame, 13, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE);

41 }

42 }

43 if (player->shooting) {

44

45

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

index b11ea08..186e0f1 100644

--- a/src/tile.c

+++ b/src/tile.c

1@@ -58,10 +58,14 @@ void tile_draw(tile_t *tile, game_t *game) {

2 DrawTextureRec(game->assets.background, texture_rect_v(3, 5, 4, 3, TILE_WIDTH, TILE_HEIGHT), tile->pos, WHITE);

3 break;

4 }

5- case TILE_BG_WINDOW: {

6+ case TILE_BG_WINDOW_1: {

7 DrawTextureRec(game->assets.background, texture_rect_v(8, 0, 4, 6, TILE_WIDTH, TILE_HEIGHT), tile->pos, WHITE);

8 break;

9 }

10+ case TILE_BG_WINDOW_2: {

11+ DrawTextureRec(game->assets.background, texture_rect_v(8, 7, 3, 4, TILE_WIDTH, TILE_HEIGHT), tile->pos, WHITE);

12+ break;

13+ }

14 case TILE_BG_BANNER: {

15 DrawTextureRec(game->assets.background, texture_rect_v(3, 0, 3, 4, TILE_WIDTH, TILE_HEIGHT), tile->pos, WHITE);

16 break;

17

18

diff --git a/todo.txt b/todo.txt

index a605b0c..609c3f2 100644

--- a/todo.txt

+++ b/todo.txt

1@@ -10,7 +10,7 @@ Todos

2 - [x] Add wall collision

3 - [ ] Add move velocity (for damage and maybe icy surfaces)

4 - [x] Stop enemy movement on walls

5-- [ ] Stop freeze laser on walls

6+- [x] Stop freeze laser on walls

7 - [ ] Add hitboxes (make them visible in debug mode)

8 - [ ] Add countdown

9 - [ ] Add new enemies

10

11