aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--animation.c15
-rw-r--r--animation.h3
-rw-r--r--collision_system.c38
-rw-r--r--components.h3
-rw-r--r--enemy.c3
-rw-r--r--game.c134
-rw-r--r--game.h4
-rw-r--r--game_config.h4
-rw-r--r--menu.c4
-rw-r--r--platform.c4
-rw-r--r--platform.h2
-rw-r--r--player.c11
-rw-r--r--player.h2
-rw-r--r--spawner.c68
-rw-r--r--spawner.h12
-rw-r--r--systems.h3
-rw-r--r--wave.c45
-rw-r--r--wave.h4
-rw-r--r--world.h3
20 files changed, 325 insertions, 38 deletions
diff --git a/Makefile b/Makefile
index 715391a..2bc251d 100644
--- a/Makefile
+++ b/Makefile
@@ -103,6 +103,7 @@ sources = \
rect.c \
render.c \
solid.c \
+ spawner.c \
sprite.c \
sprite_system.c \
standard.c \
diff --git a/animation.c b/animation.c
index ff944eb..1912934 100644
--- a/animation.c
+++ b/animation.c
@@ -79,6 +79,21 @@ static const Animation animations[] = {
},
6,
3
+ },
+ /* animation_spawn */
+ {
+ {
+ { 133, 60, 15, 6 },
+ { 133, 60, 15, 6 },
+ { 133, 60, 15, 6 },
+ { 133, 60, 15, 6 },
+ { 133, 66, 15, 6 },
+ { 148, 60, 15, 6 },
+ { 148, 66, 15, 6 },
+ { 148, 72, 15, 6 },
+ },
+ 8,
+ 5
}
};
diff --git a/animation.h b/animation.h
index 0a36043..27eadb8 100644
--- a/animation.h
+++ b/animation.h
@@ -11,7 +11,8 @@ typedef enum {
animation_player_idle_right,
animation_enemy_bullet_explode,
animation_player_bullet_explode,
- animation_heart_break
+ animation_heart_break,
+ animation_spawn
} Animation_ID;
typedef struct {
diff --git a/collision_system.c b/collision_system.c
index 2bb8cdb..a5342d2 100644
--- a/collision_system.c
+++ b/collision_system.c
@@ -175,12 +175,13 @@ static void handle(
}
void collision_system(World* world) {
- int i, j, k, s, s2, p0x, p0y, r, l, t, b;
+ int i, j, k, s, s2, p0x, p0y, r, l, t, b, dx, dy, d;
int ax, ay, aw, ah, bx, by, bw, bh;
int overlap[4];
unsigned bits;
- const CPosition* pos0, * pos1;
+ CPosition* pos0, * pos1;
const CCollider* col0, * col1;
+ const CEnemy* e0, * e1;
Collision_Side side;
for (i = 0; i < world->entity_count; i++) {
@@ -254,6 +255,39 @@ void collision_system(World* world) {
}
}
}
+
+ for (i = 0; i < world->entity_count; i++) {
+ bits = world->bitmask[i];
+ if (
+ !(bits & ctype_enemy) ||
+ !(bits & ctype_position)
+ ) { continue; }
+
+ pos0 = &world->positions[i];
+ e0 = &world->enemies[i];
+
+ for (j = i + 1; j < world->entity_count; j++) {
+ bits = world->bitmask[j];
+ if (
+ !(bits & ctype_enemy) ||
+ !(bits & ctype_position)
+ ) { continue; }
+
+ pos1 = &world->positions[j];
+ e1 = &world->enemies[j];
+
+ dx = (pos0->x - pos1->x) >> 4;
+ dy = (pos0->y - pos1->y) >> 4;
+ d = ((dx * dx) + (dy * dy)) >> fbits;
+
+ if (d < enemy_min_distance) {
+ pos0->x += dx;
+ pos1->x -= dx;
+ pos0->y += dy;
+ pos1->y -= dy;
+ }
+ }
+ }
}
#endif
diff --git a/components.h b/components.h
index fb0df18..b759ec9 100644
--- a/components.h
+++ b/components.h
@@ -61,7 +61,8 @@ typedef enum {
ctype_player = 1 << 10,
ctype_destroy_on_anim_done = 1 << 11,
ctype_solid = 1 << 12,
- ctype_moveable = 1 << 13
+ ctype_moveable = 1 << 13,
+ ctype_spawner = 1 << 14
} CType;
#endif
diff --git a/enemy.c b/enemy.c
index 04baec4..60366fb 100644
--- a/enemy.c
+++ b/enemy.c
@@ -105,6 +105,7 @@ void enemy_system(World* world) {
enemy = &world->enemies[i];
if (enemy->hp <= 0) {
destroy_entity(world, i);
+ world->enemies_killed++;
if ((bits & ctype_position) && (bits & ctype_skull)) {
pos = &world->positions[i];
@@ -130,7 +131,7 @@ void enemy_system(World* world) {
dpy = ((ppos->y - pos->y) >> 4) + 256;
tpx = dpx;
tpy = dpy;
- d = ((dpx * dpx) >> fbits) + ((dpy * dpy) >> fbits);
+ d = ((dpx * dpx) + (dpy * dpy)) >> fbits;
if (enemy->being_damaged) {
enemy->being_damaged--;
diff --git a/game.c b/game.c
index b68d85a..064fc22 100644
--- a/game.c
+++ b/game.c
@@ -1,15 +1,38 @@
#include "asset.h"
#include "enemy.h"
#include "game.h"
+#include "input.h"
#include "platform.h"
#include "sprite.h"
#include "standard.h"
#include "systems.h"
-static void menu_new(Menu* menu) {
+void gameplay_new(Game* game) {
+ World* world;
+
+ world = &game->world;
+
+ seed_rng(platform_get_time());
+ init_world(&game->world);
+ init_map(&world->map, world);
+ init_player(&world->player, world);
+ init_waver(&world->waver);
+ world->gmemory = gmemory_max;
+}
+
+void gameplay_next_wave(Game* game) {
+ World* world;
+
+ world = &game->world;
+ next_wave(&world->waver);
+ game_change_state(game, game_state_game);
+}
+
+static void menu_start(Menu* menu) {
Game* game;
game = menu->ptr;
+ gameplay_new(game);
game_change_state(game, game_state_game);
}
@@ -17,6 +40,7 @@ static void menu_restart(Menu* menu) {
Game* game;
game = menu->ptr;
+ gameplay_new(game);
game_change_state(game, game_state_game);
}
@@ -45,7 +69,7 @@ static void menu_init(Game* game) {
font = get_default_font();
init_menu(&game->menu, game);
- menu_add(&game->menu, "Play", menu_new, font);
+ menu_add(&game->menu, "Play", menu_start, font);
menu_add(&game->menu, "Credits", menu_credits, font);
menu_add(&game->menu, "Quit", menu_quit, font);
}
@@ -95,17 +119,11 @@ static void menu_deinit(Game* game) {
}
static void gameplay_init(Game* game) {
- World* world;
-
- world = &game->world;
-
- seed_rng(500);
- init_world(&game->world);
- init_map(&world->map, world);
- init_player(&world->player, world);
- init_waver(&world->waver);
+ start_wave(&game->world);
- world->gmemory = gmemory_max;
+ game->want_next = 0;
+ game->wave_timer = 0;
+ game->display_wave_text = 100;
}
static void render_hud(Game* game) {
@@ -164,27 +182,73 @@ static void render_hud(Game* game) {
}
static void gameplay_update(Game* game) {
- int cx, cy;
+ int cx, cy, ec, l;
World* world;
Player* player;
- cx = game->world.cam_x;
- cy = game->world.cam_y;
+ const Waver* waver;
+ const BM_Font* font;
+ Colour col;
+ char buf[32];
world = &game->world;
player = &world->player;
+ waver = &world->waver;
+ cx = world->cam_x;
+ cy = world->cam_y;
+
+ font = get_default_font();
update_waver(&world->waver, world);
+ ec = wave_enemy_count(&world->waver);
+
+ if (
+ world->enemies_killed >= ec &&
+ !game->want_next
+ ) {
+ if (waver->idx >= get_wave_count() - 1) {
+ world->oom = -1;
+ game_change_state(game, game_state_dead);
+ }
+
+ game->wave_timer = 0;
+ game->want_next = 1;
+ }
+
+ if (game->want_next && game->wave_timer > 200) {
+ gameplay_next_wave(game);
+ }
update_player(player, world);
enemy_system(world);
debris_system(world);
bullet_system(world);
collision_system(world);
+ spawner_system(world);
animation_system(world);
update_camera(player, world);
render_map(&world->map, cx, cy);
sprite_system(world);
+ if (game->display_wave_text) {
+ col = make_colour(0x7f8dcf, 255);
+ buf[0] = 'W';
+ buf[1] = 'a';
+ buf[2] = 'v';
+ buf[3] = 'e';
+ buf[4] = ' ';
+ l = 5 + int_to_buf(world->waver.idx + 1, buf + 5);
+ rfont_text_col(
+ font,
+ renderer_w / 2 - (l * font->char_w) / 2,
+ renderer_h / 2,
+ buf,
+ col
+ );
+ game->display_wave_text--;
+ }
+
+ game->wave_timer++;
+
render_hud(game);
if (world->gmemory <= 0) {
@@ -202,18 +266,38 @@ static void credits_init(Game* game) {
}
static void credits_update(Game* game) {
+ Colour colour;
+ const BM_Font* font;
+ font = get_default_font();
+
+ if (
+ button_just_pressed(btn_shoot) ||
+ button_just_pressed(btn_jump)
+ ) {
+ game_change_state(game, game_state_menu);
+ }
+
+ rfont_text(font, 0, 0, "Programming: quou");
+ rfont_text(font, 0, 10, "Design: quou");
+ rfont_text(font, 0, 20, "Sound: quou");
+ rfont_text(font, 0, 30, "Graphics: quou");
+ rfont_text(font, 0, 40, "Music: drummyfish");
+ rfont_text(font, 0, 50, "Source Code: git.quou.xyz");
}
static void credits_deinit(Game* game) {
-
}
static void dead_init(Game* game) {
- const BM_Font* font = get_default_font();
- init_menu(&game->menu, game);
- menu_add(&game->menu, "Restart", menu_restart, font);
- menu_add(&game->menu, "Main Menu", menu_main_menu, font);
+ const BM_Font* font;
+ Menu* menu;
+
+ menu = &game->menu;
+ font = get_default_font();
+ init_menu(menu, game);
+ menu_add(menu, "Restart", menu_restart, font);
+ menu_add(menu, "Main Menu", menu_main_menu, font);
}
static void dead_update(Game* game) {
@@ -230,14 +314,22 @@ static void dead_update(Game* game) {
cy = game->world.cam_y;
render_map(&game->world.map, cx, cy);
sprite_system(&game->world);
+ render_hud(game);
- if (world->oom) {
+ if (world->oom == 1) {
rfont_text(
font,
renderer_w / 2 - 65,
game->menu.y - 15,
"Out of Memory"
);
+ } else if (world->oom == -1) {
+ rfont_text(
+ font,
+ renderer_w / 2 - 35,
+ game->menu.y - 15,
+ "You win"
+ );
} else {
rfont_text(
font,
diff --git a/game.h b/game.h
index 6562673..66d9574 100644
--- a/game.h
+++ b/game.h
@@ -25,6 +25,7 @@ struct Game {
Menu menu;
World world;
+ int wave_timer, want_next, display_wave_text;
};
void game_init(Game* game, Game_State state);
@@ -33,4 +34,7 @@ void game_deinit(Game* game);
void game_change_state(Game* game, Game_State state);
+void gameplay_next_wave(Game* menu);
+void gameplay_new(Game* game);
+
#endif
diff --git a/game_config.h b/game_config.h
index 3b0f9d3..d0adbac 100644
--- a/game_config.h
+++ b/game_config.h
@@ -6,13 +6,13 @@
#define player_max_hp 3
#define player_invul_frames 50
-#define enemy_hit_frames 10
-
#define skull_hp 3
#define skull_speed (1 << fbits)
#define skull_shoot_cooldown 15
#define enemy_bullet_speed 10
+#define enemy_hit_frames 10
+#define enemy_min_distance (10 << fbits)
#define map_width 32
#define map_height 32
diff --git a/menu.c b/menu.c
index e4e82f5..ab3f7de 100644
--- a/menu.c
+++ b/menu.c
@@ -69,15 +69,17 @@ void update_menu(Menu* menu) {
void render_menu(Menu* menu, const BM_Font* font) {
int i, x, y, cw, ch;
const Menu_Item* el;
+ Colour col;
y = menu->y;
cw = font->char_w;
ch = font->char_h;
+ col = make_colour(0xffde00, 255);
for (i = 0; i < menu->el_count; i++) {
el = &menu->els[i];
x = renderer_w / 2 - (cw * el->text_len) / 2;
- rfont_text(font, x, y, el->text);
+ rfont_text_col(font, x, y, el->text, col);
if (i == menu->selected) {
rfont_char(font, x - cw, y, '>');
}
diff --git a/platform.c b/platform.c
index 940e57f..9bd5300 100644
--- a/platform.c
+++ b/platform.c
@@ -187,6 +187,10 @@ static int ww, wh, bb_pitch, ntw, nth;
static int to_sleep, begin_time, end_time;
static SDL_Joystick* joysticks[max_joysticks];
+int platform_get_time() {
+ return SDL_GetTicks();
+}
+
static void fit_texture(int w, int h) {
ntw = renderer_w;
nth = renderer_h;
diff --git a/platform.h b/platform.h
index bd3bc21..0001f8b 100644
--- a/platform.h
+++ b/platform.h
@@ -7,4 +7,6 @@ void platform_log(const char* message, ...);
void platform_err(const char* message, ...);
void platform_abort(int code);
+int platform_get_time();
+
#endif
diff --git a/player.c b/player.c
index ff3f53b..9075048 100644
--- a/player.c
+++ b/player.c
@@ -87,7 +87,7 @@ void update_player(Player* player, World* world) {
if (dx || dy) {
vec_nrmise(&dx, &dy);
- if (dx) {
+ if (dx && !button_pressed(btn_shoot)) {
face = dx < 0 ? 0 : 1;
} else {
face = player->face;
@@ -117,13 +117,18 @@ void update_player(Player* player, World* world) {
animation_player_walk_left;
}
+ if (!button_pressed(btn_shoot)) {
+ player->sdx = player->ldx;
+ player->sdy = player->ldy;
+ }
+
if (button_pressed(btn_shoot) && player->shoot_countdown <= 0) {
new_player_bullet(
world,
pos->x,
pos->y,
- (player->ldx * player_bullet_speed) >> fbits,
- (player->ldy * player_bullet_speed) >> fbits,
+ (player->sdx * player_bullet_speed) >> fbits,
+ (player->sdy * player_bullet_speed) >> fbits,
100
);
diff --git a/player.h b/player.h
index 86a0426..1025eb8 100644
--- a/player.h
+++ b/player.h
@@ -6,7 +6,7 @@ struct World;
typedef struct {
int entity;
int face;
- int ldx, ldy;
+ int ldx, ldy, sdx, sdy;
int shoot_cooldown;
int shoot_countdown;
int hp;
diff --git a/spawner.c b/spawner.c
new file mode 100644
index 0000000..058a894
--- /dev/null
+++ b/spawner.c
@@ -0,0 +1,68 @@
+#include "animation.h"
+#include "components.h"
+#include "enemy.h"
+#include "world.h"
+
+int new_spawner(
+ World* world,
+ int x,
+ int y
+) {
+ Entity e;
+ CPosition* pos;
+ CSprite* sprite;
+ CAnimated* animated;
+
+ e = new_entity(world);
+ add_components(
+ world,
+ e,
+ ctype_sprite |
+ ctype_position |
+ ctype_animated |
+ ctype_spawner
+ );
+
+ pos = &world->positions[e];
+ sprite = &world->sprites[e];
+ animated = &world->animateds[e];
+
+ pos->x = x;
+ pos->y = y;
+
+ sprite->id = asset_id_usr;
+ sprite->rect = make_rect(0, 0, 16, 16);
+
+ animated->id = animation_spawn;
+ animated->frame = 0;
+ animated->timer = 0;
+
+ return e;
+}
+
+void spawner_system(World* world) {
+ int i;
+ const CPosition* pos;
+ const CAnimated* animated;
+ const Animation* animation;
+ unsigned bits;
+
+ for (i = 0; i < world->entity_count; i++) {
+ bits = world->bitmask[i];
+ if (
+ (bits & ctype_spawner) &&
+ (bits & ctype_position) &&
+ (bits & ctype_animated)
+ ) {
+ pos = &world->positions[i];
+ animated = &world->animateds[i];
+
+ animation = get_animation(animated->id);
+
+ if (animated->frame == animation->frame_count - 1) {
+ new_skull(world, pos->x, pos->y);
+ destroy_entity(world, i);
+ }
+ }
+ }
+}
diff --git a/spawner.h b/spawner.h
new file mode 100644
index 0000000..65633c5
--- /dev/null
+++ b/spawner.h
@@ -0,0 +1,12 @@
+#ifndef spawner_h
+#define spawner_h
+
+struct World;
+
+int new_spawner(
+ struct World* world,
+ int x,
+ int y
+);
+
+#endif
diff --git a/systems.h b/systems.h
index 672e704..5108b80 100644
--- a/systems.h
+++ b/systems.h
@@ -6,8 +6,9 @@
void animation_system(World* world);
void bullet_system(World* world);
void collision_system(World* world);
+void debris_system(World* world);
void enemy_system(World* world);
+void spawner_system(World* world);
void sprite_system(const World* world);
-void debris_system(World* world);
#endif
diff --git a/wave.c b/wave.c
index 93b43f4..e6f4e44 100644
--- a/wave.c
+++ b/wave.c
@@ -1,4 +1,4 @@
-#include "enemy.h"
+#include "spawner.h"
#include "standard.h"
#include "wave.h"
#include "world.h"
@@ -13,9 +13,34 @@ static const Wave waves[] = {
{ 3, 5 },
{ 15, 15 },
}
+ }
+ },
+ 1,
+ 2
+ },
+ {
+ {
+ {
+ 20,
+ 2,
+ {
+ { 3, 5 },
+ { 15, 15 },
+ }
+ },
+ {
+ 200,
+ 4,
+ {
+ { 30, 30 },
+ { 15, 20 },
+ { 23, 5 },
+ { 6, 4 },
+ }
},
},
- 1
+ 2,
+ 6
}
};
@@ -25,8 +50,18 @@ void init_waver(Waver* waver) {
waver->timer = 0;
}
+void start_wave(struct World* world) {
+ world->wave_started = 1;
+ world->enemies_killed = 0;
+}
+
+int wave_enemy_count(const Waver* waver) {
+ return waves[waver->idx].kill_requirement;
+}
+
void next_wave(Waver* waver) {
waver->idx++;
+ waver->sidx = 0;
}
void update_waver(Waver* waver, World* world) {
@@ -45,7 +80,7 @@ void update_waver(Waver* waver, World* world) {
if (waver->timer >= subwave->frame) {
for (i = 0; i < subwave->count; i++) {
spawn = &subwave->spawns[i];
- new_skull(
+ new_spawner(
world,
(spawn->x * map_tile_size) << fbits,
(spawn->y * map_tile_size) << fbits
@@ -54,3 +89,7 @@ void update_waver(Waver* waver, World* world) {
waver->sidx++;
}
}
+
+int get_wave_count() {
+ return sizeof waves / sizeof *waves;
+}
diff --git a/wave.h b/wave.h
index 3d40981..2f642fe 100644
--- a/wave.h
+++ b/wave.h
@@ -22,6 +22,7 @@ typedef struct {
typedef struct {
Subwave subwaves[wave_max_subwaves];
int subwave_count;
+ int kill_requirement;
} Wave;
struct Waver {
@@ -30,7 +31,10 @@ struct Waver {
};
void init_waver(Waver* waver);
+void start_wave(struct World* world);
+int wave_enemy_count(const Waver* waver);
void next_wave(Waver* waver);
void update_waver(Waver* waver, struct World* world);
+int get_wave_count();
#endif
diff --git a/world.h b/world.h
index 6749dbc..f6a4d07 100644
--- a/world.h
+++ b/world.h
@@ -32,7 +32,8 @@ struct World {
Waver waver;
int cam_x, cam_y;
- int enemy_count;
+ int enemy_count, wave_started, enemies_killed;
+ int has_less_collision, has_less_hud;
int gmemory, oom;
};