aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorquou <quou@disroot.org>2024-10-05 12:13:47 +1000
committerquou <quou@disroot.org>2024-10-05 12:13:47 +1000
commit0e75a2949678cb8a68fb0819355864aa6db2cb43 (patch)
treeabeb4ecb53649e520e4fcc1652ad870e3d7175fa
parent6cab1d56ad2b29a2556090f1f0ce7e2b72d5460a (diff)
Level transitions and main menu
-rw-r--r--1bitjam.c16
-rw-r--r--Makefile3
-rw-r--r--game.c172
-rw-r--r--game.h35
-rw-r--r--intermediate/fade_in.anm11
-rw-r--r--intermediate/fade_out.anm11
-rw-r--r--intermediate/hud.bmpbin9906 -> 40538 bytes
-rw-r--r--intermediate/map.bmpbin41098 -> 41098 bytes
-rw-r--r--map.c27
-rw-r--r--map.h6
-rw-r--r--render.c28
-rw-r--r--render.h7
12 files changed, 302 insertions, 14 deletions
diff --git a/1bitjam.c b/1bitjam.c
index 547eee7..1b903c1 100644
--- a/1bitjam.c
+++ b/1bitjam.c
@@ -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);
diff --git a/Makefile b/Makefile
index 2b6252e..b7582d1 100644
--- a/Makefile
+++ b/Makefile
@@ -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 \
diff --git a/game.c b/game.c
new file mode 100644
index 0000000..07b0264
--- /dev/null
+++ b/game.c
@@ -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);
+ }
+}
diff --git a/game.h b/game.h
new file mode 100644
index 0000000..590cc56
--- /dev/null
+++ b/game.h
@@ -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
index e2793ab..20dc791 100644
--- a/intermediate/hud.bmp
+++ b/intermediate/hud.bmp
Binary files differ
diff --git a/intermediate/map.bmp b/intermediate/map.bmp
index fd32c56..588a13d 100644
--- a/intermediate/map.bmp
+++ b/intermediate/map.bmp
Binary files differ
diff --git a/map.c b/map.c
index 9566aa2..41d224a 100644
--- a/map.c
+++ b/map.c
@@ -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) {
diff --git a/map.h b/map.h
index 6a3021d..62263f5 100644
--- a/map.h
+++ b/map.h
@@ -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) \
diff --git a/render.c b/render.c
index 07af8cf..ff7670b 100644
--- a/render.c
+++ b/render.c
@@ -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
diff --git a/render.h b/render.h
index e41572e..ca06ca3 100644
--- a/render.h
+++ b/render.h
@@ -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