QUOTE: Be someone’s rainbow today.

freezo

A retro platform game

commit a5e9ff259a83b6dcb534a2e141795a4f86322da8
parent 3f88293188282ff12f5d6b06150032ad4298d502
Author: Sophie <info@soophie.de>
Date:   Tue, 17 Dec 2024 22:23:42 +0100

feat: Added boss movement logic

Diffstat:
Massets/entities.png | 0
Minclude/boss.h | 17++++++++---------
Minclude/util.h | 1+
Msrc/boss.c | 48++++++++++++++++++++++++++++++++++--------------
Msrc/entity.c | 2+-
Msrc/player.c | 55+++++++++++++++++++++++++++++++------------------------
Msrc/util.c | 9+++++++++
7 files changed, 84 insertions(+), 48 deletions(-)

diff --git a/assets/entities.png b/assets/entities.png Binary files differ. diff --git a/include/boss.h b/include/boss.h @@ -5,6 +5,12 @@ typedef struct Boss boss_t; #include "game.h" #include "util.h" +#define BOSS_WIDTH 12 * SCALE +#define BOSS_HEIGHT 12 * SCALE +#define BOSS_SPEED 0.5 +#define BOSS_FLOAT_TIME 80 +#define BOSS_RANGE 6 * TILE_WIDTH + typedef enum { BOSS_TEST, } boss_e; @@ -12,16 +18,9 @@ typedef enum { struct Boss { pos_t pos; boss_e type; - bool on_ground; - float velocity; - float gravity; int dir; - bool stunned; - bool frozen; - int frozen_timer; - float fall_height; - fz_timer_t *timer_walking; - fz_timer_t *timer_sneaking; + int float_timer; + bool is_angry; }; boss_t *boss_create(pos_t pos, boss_e type); diff --git a/include/util.h b/include/util.h @@ -29,6 +29,7 @@ pos_t pos_snap(pos_t vec); rect_t rect_from_pos(pos_t pos, int width, int height); bool rect_collide(rect_t a, rect_t b); +bool rect_collide_threshold(rect_t a, rect_t b, float threshold); Texture texture_load(char *filename, int scale); Rectangle texture_rect(int x, int y, int width, int height); diff --git a/src/boss.c b/src/boss.c @@ -11,28 +11,50 @@ boss_t *boss_create(pos_t pos, boss_e type) { *boss = (boss_t) { .pos = pos, .type = type, - .on_ground = false, - .velocity = 0.0, - .gravity = 0.0, .dir = 1, - .stunned = false, - .frozen = false, - .frozen_timer = 0, - .fall_height = 0.0, - .timer_walking = fz_timer_create(9, 8), - .timer_sneaking = fz_timer_create(9, 16), + .float_timer = 0, + .is_angry = false, }; return boss; } void boss_update(boss_t *boss, game_t *game) { - (void) boss; - (void) game; + pos_t player_origin = { + .x = game->player->pos.x + PLAYER_WIDTH / 2.0, + .y = game->player->pos.y + PLAYER_HEIGHT / 2.0, + }; + pos_t boss_origin = { + .x = boss->pos.x + BOSS_WIDTH / 2.0, + .y = boss->pos.y + BOSS_HEIGHT / 2.0, + }; + float dx = player_origin.x - boss_origin.x; + float dy = player_origin.y - boss_origin.y; + float distance = sqrtf(dx * dx + dy * dy); + boss->is_angry = distance < BOSS_RANGE && distance > BOSS_HEIGHT / 2.0; + if (boss->is_angry) { + float norm_dx = dx / distance; + float norm_dy = dy / distance; + boss->pos.x += norm_dx * BOSS_SPEED; + boss->pos.y += norm_dy * BOSS_SPEED; + boss->dir = (norm_dx > 0) ? 1 : -1; + } + else { + if (boss->float_timer == BOSS_FLOAT_TIME) { + boss->float_timer = 0; + } + boss->float_timer++; + boss->pos.y += 0.4 * sin((2 * PI) / BOSS_FLOAT_TIME * boss->float_timer); + } } void boss_draw(boss_t *boss, game_t *game) { pos_t pos = pos_snap(boss->pos); - DrawTextureRec(game->assets.entities, texture_rect_v(10, 6, 2, 1, ENEMY_WIDTH, ENEMY_HEIGHT), pos, WHITE); + if (boss->dir > 0) { + DrawTextureRec(game->assets.entities, texture_rect_v(boss->is_angry ? 12 : 10, 6, 2, 1, ENEMY_WIDTH, ENEMY_HEIGHT), pos, WHITE); + } + else { + DrawTextureRec(game->assets.entities, texture_rect_v(boss->is_angry ? 12 : 10, 7, 2, 1, ENEMY_WIDTH, ENEMY_HEIGHT), pos, WHITE); + } } void boss_kill(boss_t *boss, game_t *game) { @@ -52,7 +74,5 @@ void boss_kill(boss_t *boss, game_t *game) { } void boss_free(boss_t *boss) { - fz_timer_free(boss->timer_walking); - fz_timer_free(boss->timer_sneaking); free(boss); } diff --git a/src/entity.c b/src/entity.c @@ -94,7 +94,7 @@ rect_t entity_get_rect(entity_t *entity) { rect = rect_from_pos((pos_t) { entity->door->pos.x, entity->door->pos.y - TILE_HEIGHT }, ENEMY_WIDTH, ENEMY_HEIGHT); break; case ENTITY_BOSS: - rect = rect_from_pos((pos_t) { entity->boss->pos.x, entity->boss->pos.y - TILE_HEIGHT }, 2 * ENEMY_WIDTH, ENEMY_HEIGHT); + rect = rect_from_pos(entity->boss->pos, BOSS_WIDTH, BOSS_HEIGHT); break; } return rect; diff --git a/src/player.c b/src/player.c @@ -253,6 +253,10 @@ void player_update(player_t *player, game_t *game) { if (!entity->is_bad) { continue; } + // ignore bosses + if (entity->type == ENTITY_BOSS) { + continue; + } rect_t entity_rect = entity_get_rect(entity); if (rect_collide(shooting_rect, entity_rect)) { float entity_x = entity_rect.x + entity_rect.width / 2.0; @@ -371,31 +375,34 @@ void player_update(player_t *player, game_t *game) { } } // detect damage + rect_t player_rect = { + .x = player->pos.x, + .y = player->pos.y, + .width = PLAYER_WIDTH, + .height = PLAYER_HEIGHT, + }; for (int i = 0; i < game->entities_len; i++) { - if (game->entities[i].type == ENTITY_ENEMY) { - enemy_t *enemy = game->entities[i].enemy; - if (!enemy->frozen) { - float tolerance = TILE_WIDTH / 5.0; - if ( - player->pos.x <= enemy->pos.x + ENEMY_WIDTH - tolerance && - player->pos.x + PLAYER_WIDTH >= enemy->pos.x + tolerance && - player->pos.y <= enemy->pos.y + ENEMY_HEIGHT - tolerance && - player->pos.y + PLAYER_HEIGHT >= enemy->pos.y + tolerance - ) { - if (player->damage_timer == 0) { - if (player->health > 0) { - player->health--; - player->damage_timer = 80; - player->velocity = 8.0; - if (player->pos.x + PLAYER_WIDTH / 2.0 > enemy->pos.x + ENEMY_WIDTH / 2.0) { - player->pos.x += 20.0; - } - else { - player->pos.x -= 20.0; - } - if (player->held_enemy != NULL) { - player->held_enemy = NULL; - } + entity_t *entity = &game->entities[i]; + if (entity->is_bad) { + // ignore frozen enemies + if (entity->type == ENTITY_ENEMY && entity->enemy->frozen) { + continue; + } + rect_t entity_rect = entity_get_rect(entity); + if (rect_collide_threshold(entity_rect, player_rect, PLAYER_WIDTH / 4.0)) { + if (player->damage_timer == 0) { + if (player->health > 0) { + player->health--; + player->damage_timer = 80; + player->velocity = 8.0; + if (player->pos.x + PLAYER_WIDTH / 2.0 > entity_rect.x + entity_rect.width / 2.0) { + player->pos.x += 20.0; + } + else { + player->pos.x -= 20.0; + } + if (player->held_enemy != NULL) { + player->held_enemy = NULL; } } } diff --git a/src/util.c b/src/util.c @@ -54,6 +54,15 @@ bool rect_collide(rect_t a, rect_t b) { ); } +bool rect_collide_threshold(rect_t a, rect_t b, float threshold) { + return !( + a.x > b.x + (b.width - threshold) || + a.x + (a.width - threshold) < b.x || + a.y + (a.height - threshold) < b.y || + a.y > b.y + (b.height - threshold) + ); +} + Texture2D texture_load(char *filename, int scale) { Image image = LoadImage(filename); ImageResizeNN(&image, scale * image.width, scale * image.height);