diff options
author | quou <quou@disroot.org> | 2024-10-05 12:13:47 +1000 |
---|---|---|
committer | quou <quou@disroot.org> | 2024-10-05 12:13:47 +1000 |
commit | 0e75a2949678cb8a68fb0819355864aa6db2cb43 (patch) | |
tree | abeb4ecb53649e520e4fcc1652ad870e3d7175fa | |
parent | 6cab1d56ad2b29a2556090f1f0ce7e2b72d5460a (diff) |
Level transitions and main menu
-rw-r--r-- | 1bitjam.c | 16 | ||||
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | game.c | 172 | ||||
-rw-r--r-- | game.h | 35 | ||||
-rw-r--r-- | intermediate/fade_in.anm | 11 | ||||
-rw-r--r-- | intermediate/fade_out.anm | 11 | ||||
-rw-r--r-- | intermediate/hud.bmp | bin | 9906 -> 40538 bytes | |||
-rw-r--r-- | intermediate/map.bmp | bin | 41098 -> 41098 bytes | |||
-rw-r--r-- | map.c | 27 | ||||
-rw-r--r-- | map.h | 6 | ||||
-rw-r--r-- | render.c | 28 | ||||
-rw-r--r-- | render.h | 7 |
12 files changed, 302 insertions, 14 deletions
@@ -1,18 +1,17 @@ #include "asset.h" #include "config.h" +#include "game.h" #include "maths.h" #include "memory.h" #include "plat.h" -#include "rect.h" #include "render.h" -#include "world.h" int entrypoint(int argc, const char** argv, Arena* m) { Heap h; App* a; FPS f; Renderer r; - World* world; + Game* game; (void)argc; (void)argv; init_maths(); @@ -24,19 +23,16 @@ int entrypoint(int argc, const char** argv, Arena* m) { a = new_app(&h, game_name); init_audio(); init_fps(&f, default_mpf); - world = arena_alloc(m, sizeof world); - init_world(world); - generate_floor(&world->map, world); + game = arena_alloc(m, sizeof *game); + init_game(game, game_state_menu); while (a->o) { fps_begin(&f); while (f.now >= f.next && a->o) { app_begin(a); - - update_world(world, a); - + update_game(game, a); ren_begin(&r, a->fb, viewport_w, viewport_h); ren_clear(&r); - ren_world(world, &r); + ren_game(game, &r); ren_end(&r); app_end(a); fps_update(&f); @@ -49,6 +49,7 @@ sources = \ deathzone.c \ effect.c \ enemy.c \ + game.c \ hud.c \ map.c \ maths.c \ @@ -80,6 +81,8 @@ anim_sources = \ $(int_dir)/demon_jump_right.anm \ $(int_dir)/demon_walk_left.anm \ $(int_dir)/demon_walk_right.anm \ + $(int_dir)/fade_in.anm \ + $(int_dir)/fade_out.anm \ $(int_dir)/guy_fall_left.anm \ $(int_dir)/guy_fall_right.anm \ $(int_dir)/guy_idle_left.anm \ @@ -0,0 +1,172 @@ +#include "animation.h" +#include "asset.h" +#include "game.h" +#include "plat.h" +#include "render.h" + +const Rect logo_rect = { 47, 0, 54, 16 }; + +void init_game(Game* g, Game_State s) { + World* w = &g->w; + g->st = s; + g->frame = 0; + g->want_next = 0; + init_world(w); +} + +void update_menu(Game* g, App* a) { + int i; + for (i = 0; i < btn_count; i++) + if (a->btn_states[i] & btn_state_pressed) { + queue_gs(g, game_state_fade_out); + queue_gs(g, game_state_generate); + queue_gs(g, game_state_fade_in); + queue_gs(g, game_state_play); + g->want_next = 1; + return; + } +} + +void queue_gs(Game* g, Game_State s) { + assert(g->qt < game_max_state_queue); + g->sq[g->qt++] = s; +} + +void on_transition(Game* g) { + g->ff = 0; +} + +void next_gs(Game* g) { + int i, e = --g->qt; + g->ps = g->st; + g->st = g->sq[0]; + for (i = 0; i < e; i++) + g->sq[i] = g->sq[i + 1]; + on_transition(g); +} + +void detect_next(Game* g, const World* w) { + const Player* p = &w->player; + if (p->y < 0) /* next level */ { + queue_gs(g, game_state_fade_out); + queue_gs(g, game_state_generate); + queue_gs(g, game_state_fade_in); + queue_gs(g, game_state_play); + g->want_next = 1; + } +} + +void update_game(Game* g, App* a) { + const Animation* fa; + if (g->want_next) { + next_gs(g); + g->want_next = 0; + } + switch (g->st) { + case game_state_menu: + update_menu(g, a); + break; + case game_state_over: + break; + case game_state_fade_in: + fa = get_animation(asset_id_fade_in_anm); + if (g->ff < fa->fc * fa->s - 1) + update_anim(fa, &g->ff, &g->fr); + else + g->want_next = 1; + break; + case game_state_fade_out: + fa = get_animation(asset_id_fade_out_anm); + if (g->ff < fa->fc * fa->s - 1) + update_anim(fa, &g->ff, &g->fr); + else + g->want_next = 1; + break; + case game_state_generate: + generate_floor(&g->w.map, &g->w); + g->want_next = 1; + break; + case game_state_play: + update_world(&g->w, a); + detect_next(g, &g->w); + break; + } + g->frame++; +} + +void ren_menu(const Game* g, Renderer* r) { + const Bitmap* bm = get_bitmap(asset_id_hud_img); + const int hv = viewport_w >> 1; + ren_map( + r, + hv - (logo_rect.w >> 1), + 100, + &logo_rect, + bm + ); + if (g->frame & 3) + ren_text( + r, + hv - 38, + 155, + "ANY BUTTON TO START" + ); + ren_text( + r, + hv - 24, + 200, + "made by quou" + ); + ren_text( + r, + hv - 44, + 205, + "public domain software" + ); + ren_text( + r, + hv - 16, + 210, + "quou.xyz" + ); +} + +void ren_state(const Game* g, Game_State s, Renderer* r) { + switch (s) { + case game_state_menu: + ren_menu(g, r); + break; + case game_state_over: + break; + case game_state_generate: + break; + case game_state_play: + ren_world(&g->w, r); + break; + default: break; + } +} + +void ren_fade(const Game* g, Renderer* r) { + const Bitmap* bm = get_bitmap(asset_id_hud_img); + const Rect* re = &g->fr; + int x, y; + for (y = 0; y < viewport_h; y += re->h) + for (x = 0; x < viewport_w; x += re->w) + ren_cmap(r, x, y, re, bm); +} + +void ren_game(const Game* g, Renderer* r) { + switch (g->st) { + case game_state_fade_in: + ren_state(g, g->sq[1], r); + ren_fade(g, r); + break; + case game_state_fade_out: + ren_state(g, g->ps, r); + ren_fade(g, r); + break; + default: + ren_state(g, g->st, r); + } +} @@ -0,0 +1,35 @@ +#ifndef game_h +#define game_h + +#include "world.h" + +struct Renderer; +struct App; + +#define game_max_state_queue 8 + +typedef enum { + game_state_menu, + game_state_play, + game_state_generate, + game_state_fade_in, + game_state_fade_out, + game_state_over +} Game_State; + +typedef struct { + World w; + Game_State st, ps; + Game_State sq[game_max_state_queue]; + Rect fr; + int want_next; + int qt, frame, ff; +} Game; + +void init_game(Game* g, Game_State s); +void update_game(Game* g, struct App* a); +void ren_game(const Game* g, struct Renderer* r); +void queue_gs(Game* g, Game_State s); +void next_gs(Game* g); + +#endif diff --git a/intermediate/fade_in.anm b/intermediate/fade_in.anm new file mode 100644 index 0000000..d417eca --- /dev/null +++ b/intermediate/fade_in.anm @@ -0,0 +1,11 @@ +2 +{ 37, 90, 10, 10 } +{ 37, 80, 10, 10 } +{ 37, 70, 10, 10 } +{ 37, 60, 10, 10 } +{ 37, 50, 10, 10 } +{ 37, 40, 10, 10 } +{ 37, 30, 10, 10 } +{ 37, 20, 10, 10 } +{ 37, 10, 10, 10 } +{ 37, 0, 10, 10 } diff --git a/intermediate/fade_out.anm b/intermediate/fade_out.anm new file mode 100644 index 0000000..b6af0f4 --- /dev/null +++ b/intermediate/fade_out.anm @@ -0,0 +1,11 @@ +2 +{ 37, 0, 10, 10 } +{ 37, 10, 10, 10 } +{ 37, 20, 10, 10 } +{ 37, 30, 10, 10 } +{ 37, 40, 10, 10 } +{ 37, 50, 10, 10 } +{ 37, 60, 10, 10 } +{ 37, 70, 10, 10 } +{ 37, 80, 10, 10 } +{ 37, 90, 10, 10 } diff --git a/intermediate/hud.bmp b/intermediate/hud.bmp Binary files differindex e2793ab..20dc791 100644 --- a/intermediate/hud.bmp +++ b/intermediate/hud.bmp diff --git a/intermediate/map.bmp b/intermediate/map.bmp Binary files differindex fd32c56..588a13d 100644 --- a/intermediate/map.bmp +++ b/intermediate/map.bmp @@ -18,7 +18,7 @@ void generate_room(Map* m) { const Bitmap* b = get_bitmap(asset_id_rooms_img); const unsigned* p = (const unsigned*)&b[1]; const int max_rooms = b->h / map_h; - const int r = /*get_r() % max_rooms;*/ 1; + const int r = get_r() % max_rooms; int o = r * map_w * map_h; int e = map_w * map_h, i; for (i = 0; i < e; i++, o++) { @@ -39,6 +39,8 @@ unsigned short get_collider(Map_Tile t) { case tile_window_mid: case tile_window_bot: case tile_brick_floor: + case tile_trapdoor1: + case tile_trapdoor2: case tile_brick: return 1; case tile_brick_ramp5: case tile_stone_ramp5: return 2; @@ -74,6 +76,8 @@ int imp_check(Map* m, Map_Tile t, int x, int y) { m->tiles[x + y * map_w] = t #define place_o(t, ox, oy) \ m->tiles[x + ox + (y + oy) * map_w] = t +#define place_a(t, x, y) \ + m->tiles[x + y * map_w] = t void generate_ramps(Map* m) { int x, y; @@ -130,16 +134,33 @@ void generate_floors(Map* m) { } } +void generate_doors(Map* m) { + const int hx = map_w >> 1; + const int t = 0; + const int b = map_h - 1; + place_a(tile_trapdoor1, hx, b); + place_a(tile_trapdoor2, hx + 1, b); + place_a(tile_trapdoor3, hx, t); + place_a(tile_trapdoor4, hx + 1, t); +} + #undef check #undef place void generate_floor(Map* m, World* w) { + Player* p = &w->player; generate_room(m); generate_ramps(m); + generate_doors(m); generate_floors(m); generate_collision(m); - w->player.x = 16 << fbits; - w->player.y = 16 << fbits; + p->x = (map_w >> 1) << fbits; + p->y = (map_h - 2) << fbits; + p->x *= map_tile_size; + p->y *= map_tile_size; + p->x += (map_tile_size >> 1) << fbits; + p->vx = 0; + p->vy = 0; } void render_map(const Map* m, Renderer* r) { @@ -39,7 +39,11 @@ struct World; x(tile_window_top, 0, 48) \ x(tile_window_mid, 16, 48) \ x(tile_window_bot, 32, 48) \ - x(tile_brick_floor, 48, 48) + x(tile_brick_floor, 48, 48) \ + x(tile_trapdoor1, 64, 48) \ + x(tile_trapdoor2, 80, 48) \ + x(tile_trapdoor3, 96, 48) \ + x(tile_trapdoor4, 112, 48) typedef enum { #define x(n, x, y) \ @@ -114,6 +114,34 @@ void ren_map( } } +void ren_cmap( + Renderer* r, + int x, + int y, + const struct Rect* re, + const Bitmap* bm +) { + Rect rect, su = *re; + const unsigned* data = (const unsigned*)&bm[1]; + int i, j, sx, sy, ex, ey; + rect.x = x; + rect.y = y; + rect.w = re->w; + rect.h = re->h; + rect_clipsr(&rect, &su, r->clip); + ex = rect.x + rect.w; + ey = rect.y + rect.h; + for (j = rect.y, sy = su.y; j < ey; j++, sy++) { + for (i = rect.x, sx = su.x; i < ex; i++, sx++) { + int di = (i + j * r->w); + int si = (sx + sy * bm->w); + int bit = (1 << (si & 0x1f)); + bit &= data[si >> 5]; + r->t[di >> 5] &= ~((1 << (di & 0x1f)) * (bit != 0)); + } + } +} + void ren_rect( Renderer* r, const struct Rect* re @@ -27,6 +27,13 @@ void ren_map( const struct Rect* re, const Bitmap* bm ); +void ren_cmap( + Renderer* r, + int x, + int y, + const struct Rect* re, + const Bitmap* bm +); void ren_rect( Renderer* r, const struct Rect* re |