so://phie

freezo

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

feat: Added boss movement logic


commit: a5e9ff259a83b6dcb534a2e141795a4f86322da8
parent: 3f88293188282ff12f5d6b06150032ad4298d502
author: Sophie <info@soophie.de>
time: 2024-12-17 22:23

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

index 9029169..e195020 100644

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

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

index d67b88e..793e6a2 100644

--- a/include/boss.h

+++ b/include/boss.h

1@@ -5,6 +5,12 @@ typedef struct Boss boss_t;

2 #include "game.h"

3 #include "util.h"

4

5+#define BOSS_WIDTH 12 * SCALE

6+#define BOSS_HEIGHT 12 * SCALE

7+#define BOSS_SPEED 0.5

8+#define BOSS_FLOAT_TIME 80

9+#define BOSS_RANGE 6 * TILE_WIDTH

10+

11 typedef enum {

12 BOSS_TEST,

13 } boss_e;

14@@ -12,16 +18,9 @@ typedef enum {

15 struct Boss {

16 pos_t pos;

17 boss_e type;

18- bool on_ground;

19- float velocity;

20- float gravity;

21 int dir;

22- bool stunned;

23- bool frozen;

24- int frozen_timer;

25- float fall_height;

26- fz_timer_t *timer_walking;

27- fz_timer_t *timer_sneaking;

28+ int float_timer;

29+ bool is_angry;

30 };

31

32 boss_t *boss_create(pos_t pos, boss_e type);

33

34

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

index 135e9b9..fb424a1 100644

--- a/include/util.h

+++ b/include/util.h

1@@ -29,6 +29,7 @@ pos_t pos_snap(pos_t vec);

2

3 rect_t rect_from_pos(pos_t pos, int width, int height);

4 bool rect_collide(rect_t a, rect_t b);

5+bool rect_collide_threshold(rect_t a, rect_t b, float threshold);

6

7 Texture texture_load(char *filename, int scale);

8 Rectangle texture_rect(int x, int y, int width, int height);

9

10

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

index 3b68016..4dff351 100644

--- a/src/boss.c

+++ b/src/boss.c

1@@ -11,28 +11,50 @@ boss_t *boss_create(pos_t pos, boss_e type) {

2 *boss = (boss_t) {

3 .pos = pos,

4 .type = type,

5- .on_ground = false,

6- .velocity = 0.0,

7- .gravity = 0.0,

8 .dir = 1,

9- .stunned = false,

10- .frozen = false,

11- .frozen_timer = 0,

12- .fall_height = 0.0,

13- .timer_walking = fz_timer_create(9, 8),

14- .timer_sneaking = fz_timer_create(9, 16),

15+ .float_timer = 0,

16+ .is_angry = false,

17 };

18 return boss;

19 }

20

21 void boss_update(boss_t *boss, game_t *game) {

22- (void) boss;

23- (void) game;

24+ pos_t player_origin = {

25+ .x = game->player->pos.x + PLAYER_WIDTH / 2.0,

26+ .y = game->player->pos.y + PLAYER_HEIGHT / 2.0,

27+ };

28+ pos_t boss_origin = {

29+ .x = boss->pos.x + BOSS_WIDTH / 2.0,

30+ .y = boss->pos.y + BOSS_HEIGHT / 2.0,

31+ };

32+ float dx = player_origin.x - boss_origin.x;

33+ float dy = player_origin.y - boss_origin.y;

34+ float distance = sqrtf(dx * dx + dy * dy);

35+ boss->is_angry = distance < BOSS_RANGE && distance > BOSS_HEIGHT / 2.0;

36+ if (boss->is_angry) {

37+ float norm_dx = dx / distance;

38+ float norm_dy = dy / distance;

39+ boss->pos.x += norm_dx * BOSS_SPEED;

40+ boss->pos.y += norm_dy * BOSS_SPEED;

41+ boss->dir = (norm_dx > 0) ? 1 : -1;

42+ }

43+ else {

44+ if (boss->float_timer == BOSS_FLOAT_TIME) {

45+ boss->float_timer = 0;

46+ }

47+ boss->float_timer++;

48+ boss->pos.y += 0.4 * sin((2 * PI) / BOSS_FLOAT_TIME * boss->float_timer);

49+ }

50 }

51

52 void boss_draw(boss_t *boss, game_t *game) {

53 pos_t pos = pos_snap(boss->pos);

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

55+ if (boss->dir > 0) {

56+ DrawTextureRec(game->assets.entities, texture_rect_v(boss->is_angry ? 12 : 10, 6, 2, 1, ENEMY_WIDTH, ENEMY_HEIGHT), pos, WHITE);

57+ }

58+ else {

59+ DrawTextureRec(game->assets.entities, texture_rect_v(boss->is_angry ? 12 : 10, 7, 2, 1, ENEMY_WIDTH, ENEMY_HEIGHT), pos, WHITE);

60+ }

61 }

62

63 void boss_kill(boss_t *boss, game_t *game) {

64@@ -52,7 +74,5 @@ void boss_kill(boss_t *boss, game_t *game) {

65 }

66

67 void boss_free(boss_t *boss) {

68- fz_timer_free(boss->timer_walking);

69- fz_timer_free(boss->timer_sneaking);

70 free(boss);

71 }

72

73

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

index 8d6d434..64a5d7f 100644

--- a/src/entity.c

+++ b/src/entity.c

1@@ -94,7 +94,7 @@ rect_t entity_get_rect(entity_t *entity) {

2 rect = rect_from_pos((pos_t) { entity->door->pos.x, entity->door->pos.y - TILE_HEIGHT }, ENEMY_WIDTH, ENEMY_HEIGHT);

3 break;

4 case ENTITY_BOSS:

5- rect = rect_from_pos((pos_t) { entity->boss->pos.x, entity->boss->pos.y - TILE_HEIGHT }, 2 * ENEMY_WIDTH, ENEMY_HEIGHT);

6+ rect = rect_from_pos(entity->boss->pos, BOSS_WIDTH, BOSS_HEIGHT);

7 break;

8 }

9 return rect;

10

11

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

index 162b96d..35cba26 100644

--- a/src/player.c

+++ b/src/player.c

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

2 if (!entity->is_bad) {

3 continue;

4 }

5+ // ignore bosses

6+ if (entity->type == ENTITY_BOSS) {

7+ continue;

8+ }

9 rect_t entity_rect = entity_get_rect(entity);

10 if (rect_collide(shooting_rect, entity_rect)) {

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

12@@ -371,31 +375,34 @@ void player_update(player_t *player, game_t *game) {

13 }

14 }

15 // detect damage

16+ rect_t player_rect = {

17+ .x = player->pos.x,

18+ .y = player->pos.y,

19+ .width = PLAYER_WIDTH,

20+ .height = PLAYER_HEIGHT,

21+ };

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

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

24- enemy_t *enemy = game->entities[i].enemy;

25- if (!enemy->frozen) {

26- float tolerance = TILE_WIDTH / 5.0;

27- if (

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

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

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

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

32- ) {

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

34- if (player->health > 0) {

35- player->health--;

36- player->damage_timer = 80;

37- player->velocity = 8.0;

38- if (player->pos.x + PLAYER_WIDTH / 2.0 > enemy->pos.x + ENEMY_WIDTH / 2.0) {

39- player->pos.x += 20.0;

40- }

41- else {

42- player->pos.x -= 20.0;

43- }

44- if (player->held_enemy != NULL) {

45- player->held_enemy = NULL;

46- }

47+ entity_t *entity = &game->entities[i];

48+ if (entity->is_bad) {

49+ // ignore frozen enemies

50+ if (entity->type == ENTITY_ENEMY && entity->enemy->frozen) {

51+ continue;

52+ }

53+ rect_t entity_rect = entity_get_rect(entity);

54+ if (rect_collide_threshold(entity_rect, player_rect, PLAYER_WIDTH / 4.0)) {

55+ if (player->damage_timer == 0) {

56+ if (player->health > 0) {

57+ player->health--;

58+ player->damage_timer = 80;

59+ player->velocity = 8.0;

60+ if (player->pos.x + PLAYER_WIDTH / 2.0 > entity_rect.x + entity_rect.width / 2.0) {

61+ player->pos.x += 20.0;

62+ }

63+ else {

64+ player->pos.x -= 20.0;

65+ }

66+ if (player->held_enemy != NULL) {

67+ player->held_enemy = NULL;

68 }

69 }

70 }

71

72

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

index b8deb3e..2f69149 100644

--- a/src/util.c

+++ b/src/util.c

1@@ -54,6 +54,15 @@ bool rect_collide(rect_t a, rect_t b) {

2 );

3 }

4

5+bool rect_collide_threshold(rect_t a, rect_t b, float threshold) {

6+ return !(

7+ a.x > b.x + (b.width - threshold) ||

8+ a.x + (a.width - threshold) < b.x ||

9+ a.y + (a.height - threshold) < b.y ||

10+ a.y > b.y + (b.height - threshold)

11+ );

12+}

13+

14 Texture2D texture_load(char *filename, int scale) {

15 Image image = LoadImage(filename);

16 ImageResizeNN(&image, scale * image.width, scale * image.height);

17

18