A retro platform game
git clone git://soophie.de/freezo
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 once3
+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);
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"7
typedef enum {8
ENTITY_ENEMY,9
ENTITY_GATE,10
ENTITY_DOOR,11
+ ENTITY_BOSS,12
} entity_e;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
};
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
};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
};16
game_t *game_create(void);
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,
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
+}
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) {
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
}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
}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
}
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) {19
void game_draw(game_t *game) {20
// render overlay21
- 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 overlay31
- DrawTexture(overlay_texture.texture, 0, 0, WHITE);32
+ DrawTexture(game->overlay.texture, 0, 0, WHITE);33
EndMode2D();34
// draw interface35
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
}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
}
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
}
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) {
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;
diff --git a/todo.txt b/todo.txt
index a605b0c..609c3f2 100644
--- a/todo.txt
+++ b/todo.txt
1
@@ -10,7 +10,7 @@ Todos2
- [x] Add wall collision3
- [ ] Add move velocity (for damage and maybe icy surfaces)4
- [x] Stop enemy movement on walls5
-- [ ] Stop freeze laser on walls6
+- [x] Stop freeze laser on walls7
- [ ] Add hitboxes (make them visible in debug mode)8
- [ ] Add countdown9
- [ ] Add new enemies