A retro platform game
git clone git://soophie.de/freezo
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"5
+#define BOSS_WIDTH 12 * SCALE6
+#define BOSS_HEIGHT 12 * SCALE7
+#define BOSS_SPEED 0.58
+#define BOSS_FLOAT_TIME 809
+#define BOSS_RANGE 6 * TILE_WIDTH10
+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
};32
boss_t *boss_create(pos_t pos, boss_e type);
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);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);7
Texture texture_load(char *filename, int scale);8
Rectangle texture_rect(int x, int y, int width, int height);
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
}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
}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
}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
}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
}
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;
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 bosses6
+ 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 damage16
+ 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 + tolerance32
- ) {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 enemies50
+ 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
}
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
}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);