commit 0619481f3da52146179ce4c102f7011515b6c52c
parent cc01827ef453d3e9c4cd93c85f774f0aa6486746
Author: Sophie <info@soophie.de>
Date: Mon, 16 Dec 2024 23:48:05 +0100
feat: Added boss (unstable) & redesigned entity/background textures
Diffstat:
15 files changed, 153 insertions(+), 17 deletions(-)
diff --git a/assets/background.png b/assets/background.png
Binary files differ.
diff --git a/assets/entities.png b/assets/entities.png
Binary files differ.
diff --git a/assets/locked.wav b/assets/locked.wav
Binary files differ.
diff --git a/include/boss.h b/include/boss.h
@@ -0,0 +1,31 @@
+#pragma once
+
+typedef struct Boss boss_t;
+
+#include "game.h"
+#include "util.h"
+
+typedef enum {
+ BOSS_TEST,
+} boss_e;
+
+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;
+};
+
+boss_t *boss_create(pos_t pos, boss_e type);
+void boss_update(boss_t *boss, game_t *game);
+void boss_draw(boss_t *boss, game_t *game);
+void boss_kill(boss_t *boss, game_t *game);
+void boss_free(boss_t *boss);
diff --git a/include/entity.h b/include/entity.h
@@ -6,11 +6,13 @@ typedef struct Entity entity_t;
#include "gate.h"
#include "game.h"
#include "door.h"
+#include "boss.h"
typedef enum {
ENTITY_ENEMY,
ENTITY_GATE,
ENTITY_DOOR,
+ ENTITY_BOSS,
} entity_e;
struct Entity {
@@ -19,6 +21,7 @@ struct Entity {
enemy_t *enemy;
gate_t *gate;
door_t *door;
+ boss_t *boss;
};
bool is_bad;
};
diff --git a/include/game.h b/include/game.h
@@ -25,6 +25,7 @@ struct Assets {
Texture2D images;
Texture2D background;
Sound track;
+ Sound locked;
};
struct Game {
@@ -46,6 +47,7 @@ struct Game {
int xp;
int sceen_timer;
door_t *door;
+ RenderTexture2D overlay;
};
game_t *game_create(void);
diff --git a/include/tile.h b/include/tile.h
@@ -15,7 +15,8 @@ typedef enum {
TILE_SNOW,
TILE_SAND,
TILE_BG_CHANDELIER,
- TILE_BG_WINDOW,
+ TILE_BG_WINDOW_1,
+ TILE_BG_WINDOW_2,
TILE_BG_BANNER,
TILE_BG_BRICK_1,
TILE_BG_BRICK_2,
diff --git a/src/boss.c b/src/boss.c
@@ -0,0 +1,58 @@
+#include <stdlib.h>
+#include <math.h>
+
+#include "../include/boss.h"
+#include "../include/const.h"
+#include "../include/entity.h"
+#include "../include/effect.h"
+
+boss_t *boss_create(pos_t pos, boss_e type) {
+ boss_t *boss = malloc(sizeof(boss_t));
+ *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),
+ };
+ return boss;
+}
+
+void boss_update(boss_t *boss, game_t *game) {
+ (void) boss;
+ (void) game;
+}
+
+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);
+}
+
+void boss_kill(boss_t *boss, game_t *game) {
+ for (int i = 0; i < game->entities_len; i++) {
+ if (game->entities[i].type == ENTITY_BOSS && game->entities[i].boss == boss) {
+ if (i + 1 < game->entities_len) {
+ for (int j = i; j < game->entities_len - 1; j++) {
+ game->entities[j] = game->entities[j + 1];
+ }
+ }
+ game->entities_len--;
+ game->entities = realloc(game->entities, sizeof(entity_t) * game->entities_len);
+ game->xp += 10;
+ break;
+ }
+ }
+}
+
+void boss_free(boss_t *boss) {
+ fz_timer_free(boss->timer_walking);
+ fz_timer_free(boss->timer_sneaking);
+ free(boss);
+}
diff --git a/src/enemy.c b/src/enemy.c
@@ -171,10 +171,10 @@ void enemy_draw(enemy_t *enemy, game_t *game) {
int frame_walking = fz_timer_get(enemy->timer_walking);
int frame_sneaking = fz_timer_get(enemy->timer_sneaking);
if (enemy->dir > 0) {
- DrawTextureRec(game->assets.entities, texture_rect(enemy->stunned ? frame_sneaking : frame_walking, 8, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE);
+ DrawTextureRec(game->assets.entities, texture_rect(enemy->stunned ? frame_sneaking : frame_walking, 10, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE);
}
else {
- DrawTextureRec(game->assets.entities, texture_rect(enemy->stunned ? frame_sneaking : frame_walking, 9, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE);
+ DrawTextureRec(game->assets.entities, texture_rect(enemy->stunned ? frame_sneaking : frame_walking, 11, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE);
}
if (enemy->frozen) {
if (enemy->frozen_timer <= 1200) {
diff --git a/src/entity.c b/src/entity.c
@@ -18,6 +18,9 @@ entity_t *entity_create(entity_e type) {
case ENTITY_DOOR:
entity->is_bad = false;
break;
+ case ENTITY_BOSS:
+ entity->is_bad = true;
+ break;
}
return entity;
}
@@ -33,6 +36,9 @@ void entity_update(entity_t *entity, game_t *game) {
case ENTITY_DOOR:
door_update(entity->door, game);
break;
+ case ENTITY_BOSS:
+ boss_update(entity->boss, game);
+ break;
}
}
@@ -47,6 +53,9 @@ void entity_draw(entity_t *entity, game_t *game) {
case ENTITY_DOOR:
door_draw(entity->door, game);
break;
+ case ENTITY_BOSS:
+ boss_draw(entity->boss, game);
+ break;
}
}
@@ -61,6 +70,9 @@ void entity_detach(entity_t *entity) {
case ENTITY_DOOR:
door_free(entity->door);
break;
+ case ENTITY_BOSS:
+ boss_free(entity->boss);
+ break;
}
}
diff --git a/src/game.c b/src/game.c
@@ -33,6 +33,7 @@ game_t *game_create(void) {
.assets.images = texture_load("assets/images.png", SCALE),
.assets.background = texture_load("assets/background.png", SCALE),
.assets.track = LoadSound("assets/track.wav"),
+ .assets.locked = LoadSound("assets/locked.wav"),
.camera = (Camera2D) {
.offset = (pos_t) { 0.0, 0.0 },
.zoom = 1,
@@ -40,6 +41,7 @@ game_t *game_create(void) {
.xp = 0,
.sceen_timer = 0,
.door = NULL,
+ .overlay = LoadRenderTexture(WINDOW_WIDTH, WINDOW_HEIGHT),
};
level_load(game, LEVEL_1);
return game;
@@ -137,8 +139,7 @@ void game_update(game_t *game) {
void game_draw(game_t *game) {
// render overlay
- RenderTexture2D overlay_texture = LoadRenderTexture(WINDOW_WIDTH, WINDOW_HEIGHT);
- BeginTextureMode(overlay_texture);
+ BeginTextureMode(game->overlay);
ClearBackground(BLACK);
DrawRectangle(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, BLACK);
BeginBlendMode(BLEND_SUBTRACT_COLORS);
@@ -168,7 +169,7 @@ void game_draw(game_t *game) {
effect_draw(game->effects[i], game);
}
// draw overlay
- DrawTexture(overlay_texture.texture, 0, 0, WHITE);
+ DrawTexture(game->overlay.texture, 0, 0, WHITE);
EndMode2D();
// draw interface
int i = 0;
@@ -201,7 +202,6 @@ void game_draw(game_t *game) {
menu_draw(game->menu, game);
}
EndDrawing();
- UnloadRenderTexture(overlay_texture);
}
void game_free(game_t *game) {
@@ -215,5 +215,7 @@ void game_free(game_t *game) {
UnloadTexture(game->assets.images);
UnloadTexture(game->assets.background);
UnloadSound(game->assets.track);
+ UnloadSound(game->assets.locked);
+ UnloadRenderTexture(game->overlay);
free(game);
}
diff --git a/src/level.c b/src/level.c
@@ -9,7 +9,7 @@
const char *LEVEL_MAP_1 = {
"........................"
"........................"
- "........k.......o......."
+ "........k.......O......."
"..1....................."
"........................"
"........................"
@@ -32,9 +32,9 @@ const char *LEVEL_MAP_2 = {
"........................"
"................u......."
"...............xxxx....."
- "..o......s.e............"
+ ".........s.e............"
".......xxxxxxtxxx--xx..."
- ".............w.........."
+ "...o.........w.........."
".........2...w...--.1..."
".............w.........."
".........----x...--....."
@@ -140,8 +140,11 @@ void level_generate(game_t *game, const char *map, int width, int height) {
case 'k':
tile->type = TILE_BG_CHANDELIER;
break;
+ case 'O':
+ tile->type = TILE_BG_WINDOW_1;
+ break;
case 'o':
- tile->type = TILE_BG_WINDOW;
+ tile->type = TILE_BG_WINDOW_2;
break;
case 'b':
tile->type = TILE_BG_BANNER;
@@ -209,6 +212,20 @@ void level_generate(game_t *game, const char *map, int width, int height) {
game->entities_len++;
break;
}
+ case 'z': {
+ game->entities = realloc(game->entities, sizeof(enemy_t) * (game->entities_len + 1));
+ boss_t *boss = boss_create((pos_t) {
+ .x = x * TILE_WIDTH + (TILE_WIDTH - ENEMY_WIDTH) / 2.0,
+ .y = y * TILE_HEIGHT,
+ }, BOSS_TEST);
+ game->entities[game->entities_len] = (entity_t) {
+ .type = ENTITY_BOSS,
+ .boss = boss,
+ .is_bad = true,
+ };
+ game->entities_len++;
+ break;
+ }
default:
break;
}
diff --git a/src/player.c b/src/player.c
@@ -263,6 +263,9 @@ void player_update(player_t *player, game_t *game) {
case ENTITY_DOOR:
entity_rect = rect_from_pos((pos_t) { entity->gate->pos.x, entity->gate->pos.y - TILE_HEIGHT }, ENEMY_WIDTH, ENEMY_HEIGHT);
break;
+ case ENTITY_BOSS:
+ entity_rect = rect_from_pos((pos_t) { entity->gate->pos.x, entity->gate->pos.y - TILE_HEIGHT }, 2 * ENEMY_WIDTH, ENEMY_HEIGHT);
+ break;
}
if (rect_collide(shooting_rect, entity_rect)) {
float entity_x = entity_rect.x + entity_rect.width / 2.0;
@@ -359,6 +362,9 @@ void player_update(player_t *player, game_t *game) {
game->door = door;
game->victory = true;
}
+ else {
+ PlaySound(game->assets.locked);
+ }
}
}
}
@@ -420,18 +426,18 @@ void player_draw(player_t *player, game_t *game) {
if (player->damage_timer / 4 % 2 == 0) {
if (player->sneaking) {
if (player->dir > 0) {
- DrawTextureRec(game->assets.entities, texture_rect(frame, 6, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE);
+ DrawTextureRec(game->assets.entities, texture_rect(frame, 14, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE);
}
else {
- DrawTextureRec(game->assets.entities, texture_rect(frame, 7, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE);
+ DrawTextureRec(game->assets.entities, texture_rect(frame, 15, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE);
}
}
else {
if (player->dir > 0) {
- DrawTextureRec(game->assets.entities, texture_rect(frame, 4, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE);
+ DrawTextureRec(game->assets.entities, texture_rect(frame, 12, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE);
}
else {
- DrawTextureRec(game->assets.entities, texture_rect(frame, 5, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE);
+ DrawTextureRec(game->assets.entities, texture_rect(frame, 13, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE);
}
}
if (player->shooting) {
diff --git a/src/tile.c b/src/tile.c
@@ -58,10 +58,14 @@ void tile_draw(tile_t *tile, game_t *game) {
DrawTextureRec(game->assets.background, texture_rect_v(3, 5, 4, 3, TILE_WIDTH, TILE_HEIGHT), tile->pos, WHITE);
break;
}
- case TILE_BG_WINDOW: {
+ case TILE_BG_WINDOW_1: {
DrawTextureRec(game->assets.background, texture_rect_v(8, 0, 4, 6, TILE_WIDTH, TILE_HEIGHT), tile->pos, WHITE);
break;
}
+ case TILE_BG_WINDOW_2: {
+ DrawTextureRec(game->assets.background, texture_rect_v(8, 7, 3, 4, TILE_WIDTH, TILE_HEIGHT), tile->pos, WHITE);
+ break;
+ }
case TILE_BG_BANNER: {
DrawTextureRec(game->assets.background, texture_rect_v(3, 0, 3, 4, TILE_WIDTH, TILE_HEIGHT), tile->pos, WHITE);
break;
diff --git a/todo.txt b/todo.txt
@@ -10,7 +10,7 @@ Todos
- [x] Add wall collision
- [ ] Add move velocity (for damage and maybe icy surfaces)
- [x] Stop enemy movement on walls
-- [ ] Stop freeze laser on walls
+- [x] Stop freeze laser on walls
- [ ] Add hitboxes (make them visible in debug mode)
- [ ] Add countdown
- [ ] Add new enemies