From 5f341eacdf0d75a4b334969a2d8a4701d61e4d9e Mon Sep 17 00:00:00 2001 From: quou Date: Sun, 7 May 2023 12:53:46 +1000 Subject: Add waves and stuff. --- Makefile | 1 + animation.c | 15 ++++++ animation.h | 3 +- collision_system.c | 38 ++++++++++++++- components.h | 3 +- enemy.c | 3 +- game.c | 134 ++++++++++++++++++++++++++++++++++++++++++++--------- game.h | 4 ++ game_config.h | 4 +- menu.c | 4 +- platform.c | 4 ++ platform.h | 2 + player.c | 11 +++-- player.h | 2 +- spawner.c | 68 +++++++++++++++++++++++++++ spawner.h | 12 +++++ systems.h | 3 +- wave.c | 45 ++++++++++++++++-- wave.h | 4 ++ world.h | 3 +- 20 files changed, 325 insertions(+), 38 deletions(-) create mode 100644 spawner.c create mode 100644 spawner.h 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,9 +1,23 @@ -#include "enemy.h" +#include "spawner.h" #include "standard.h" #include "wave.h" #include "world.h" static const Wave waves[] = { + { + { + { + 20, + 2, + { + { 3, 5 }, + { 15, 15 }, + } + } + }, + 1, + 2 + }, { { { @@ -14,8 +28,19 @@ static const Wave waves[] = { { 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; }; -- cgit v1.2.3-54-g00ecf