aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorquou <quou@disroot.org>2023-05-06 12:22:50 +1000
committerquou <quou@disroot.org>2023-05-06 12:22:50 +1000
commit937edea9599718e959f8ed135e97c68728855975 (patch)
treeea5d5551b470603d2d907dba4869ff52e742d9de
parent91aef268319a77ee8f5a082ca89264bf2671e212 (diff)
Add solid environment collisions.
-rw-r--r--Makefile1
-rw-r--r--collision_system.c172
-rw-r--r--components.h4
-rw-r--r--enemy.c3
-rw-r--r--game.c3
-rw-r--r--map.c40
-rw-r--r--map.h4
-rw-r--r--player.c24
-rw-r--r--player.h1
-rw-r--r--solid.c27
-rw-r--r--solid.h8
11 files changed, 261 insertions, 26 deletions
diff --git a/Makefile b/Makefile
index c4c00e2..25e0cec 100644
--- a/Makefile
+++ b/Makefile
@@ -101,6 +101,7 @@ sources = \
player.c \
rect.c \
render.c \
+ solid.c \
sprite.c \
sprite_system.c \
standard.c \
diff --git a/collision_system.c b/collision_system.c
index 68e3b09..2a1ac03 100644
--- a/collision_system.c
+++ b/collision_system.c
@@ -1,11 +1,43 @@
#ifndef systems_h
#define systems_h
+#include <stdint.h>
+
+#include "components.h"
#include "config.h"
#include "fx.h"
#include "rect.h"
+#include "standard.h"
#include "world.h"
+#ifdef DEBUG
+#include "error.h"
+#include "platform.h"
+#endif
+
+typedef enum {
+ collision_side_left = 0,
+ collision_side_right,
+ collision_side_top,
+ collision_side_bottom
+} Collision_Side;
+
+static Collision_Side invert_side(Collision_Side side) {
+ switch (side) {
+ case collision_side_left: return collision_side_right;
+ case collision_side_right: return collision_side_left;
+ case collision_side_bottom: return collision_side_top;
+ case collision_side_top: return collision_side_bottom;
+ }
+
+#if DEBUG
+ platform_err("Invalid collision side.\n");
+ platform_abort(error_gameplay_error);
+#endif
+
+ return -1;
+}
+
static void handle_bullet_vs_player(
World* world,
Entity bullet,
@@ -32,7 +64,66 @@ static void handle_bullet_vs_enemy(
destroy_entity(world, bullet);
}
-static void handle(World* world, Entity a, Entity b) {
+static void handle_bullet_vs_solid(
+ World* world,
+ Entity bullet,
+ Entity solid
+) {
+ const CPosition* pos;
+ unsigned bbits;
+
+ bbits = world->bitmask[bullet];
+
+ if (bbits & ctype_enemy_bullet) {
+ pos = &world->positions[bullet];
+ new_enemy_bullet_explosion(world, pos->x, pos->y);
+ }
+
+ destroy_entity(world, bullet);
+}
+
+static void handle_moveable_vs_solid(
+ World* world,
+ Entity moveable,
+ Entity solid,
+ Collision_Side side
+) {
+ const CCollider* scol, * mcol;
+ const CPosition* spos;
+ CPosition* mpos;
+
+ scol = &world->colliders[solid];
+ mcol = &world->colliders[moveable];
+ spos = &world->positions[solid];
+ mpos = &world->positions[moveable];
+
+ switch (side) {
+ case collision_side_top:
+ mpos->y = spos->y + scol->y + scol->h - mcol->y;
+ return;
+ case collision_side_bottom:
+ mpos->y = (spos->y + scol->y) - (mcol->y + mcol->h);
+ return;
+ case collision_side_left:
+ mpos->x = spos->x + scol->x + scol->w - mcol->x;
+ return;
+ case collision_side_right:
+ mpos->x = (spos->x + scol->x) - (mcol->x + mcol->w);
+ return;
+ }
+
+#if DEBUG
+ platform_err("Invalid collision side.\n");
+ platform_abort(error_gameplay_error);
+#endif
+}
+
+static void handle(
+ World* world,
+ Entity a,
+ Entity b,
+ Collision_Side side
+) {
unsigned ab, bb;
ab = world->bitmask[a];
@@ -42,7 +133,6 @@ static void handle(World* world, Entity a, Entity b) {
handle_bullet_vs_player(world, a, b);
return;
}
-
if ((ab & ctype_player) && (bb & ctype_enemy_bullet)) {
handle_bullet_vs_player(world, b, a);
return;
@@ -52,18 +142,39 @@ static void handle(World* world, Entity a, Entity b) {
handle_bullet_vs_enemy(world, a, b);
return;
}
-
if ((ab & ctype_enemy) && (bb & ctype_player_bullet)) {
handle_bullet_vs_enemy(world, b, a);
return;
}
+
+ if ((ab & ctype_bullet) && (bb & ctype_solid)) {
+ handle_bullet_vs_solid(world, a, b);
+ return;
+ }
+ if ((ab & ctype_solid) && (bb & ctype_bullet)) {
+ handle_bullet_vs_solid(world, b, a);
+ return;
+ }
+
+ if ((ab & ctype_moveable) && (bb & ctype_solid)) {
+ handle_moveable_vs_solid(world, a, b, side);
+ return;
+ }
+ if ((ab & ctype_solid) && (bb & ctype_moveable)) {
+ side = invert_side(side);
+ handle_moveable_vs_solid(world, b, a, side);
+ return;
+ }
}
void collision_system(World* world) {
- int i, j, p0x, p0y;
+ int i, j, k, s, s2, p0x, p0y, r, l, t, b;
+ int ax, ay, aw, ah, bx, by, bw, bh;
+ int overlap[4];
unsigned bits;
const CPosition* pos0, * pos1;
const CCollider* col0, * col1;
+ Collision_Side side;
for (i = 0; i < world->entity_count; i++) {
bits = world->bitmask[i];
@@ -87,17 +198,52 @@ void collision_system(World* world) {
pos1 = &world->positions[j];
col1 = &world->colliders[j];
+ ax = p0x;
+ ay = p0y;
+ aw = col0->w;
+ ah = col0->h;
+ bx = pos1->x + col1->x;
+ by = pos1->y + col1->y;
+ bw = col1->w;
+ bh = col1->h;
+
+ /* Can you tell I made this while I had a migraine? */
if (rects_overlap2(
- p0x,
- p0y,
- col0->w,
- col0->h,
- pos1->x + col1->x,
- pos1->y + col1->y,
- col1->w,
- col1->h
+ ax,
+ ay,
+ aw,
+ ah,
+ bx,
+ by,
+ bw,
+ bh
)) {
- handle(world, i, j);
+ r = (ax + aw) - bx;
+ l = (bx + bw) - ax;
+ t = (by + bh) - ay;
+ b = (ay + ah) - by;
+
+ overlap[0] = r;
+ overlap[1] = l;
+ overlap[2] = t;
+ overlap[3] = b;
+ s = INT32_MAX;
+ for (k = 0; k < 4; k++) {
+ s2 = overlap[k];
+ if (s2 < s) { s = s2; }
+ }
+
+ if (s == absolute(r)) {
+ side = collision_side_right;
+ } else if (s == absolute(l)) {
+ side = collision_side_left;
+ } else if (s == absolute(b)) {
+ side = collision_side_bottom;
+ } else if (s == absolute(t)) {
+ side = collision_side_top;
+ }
+
+ handle(world, i, j, side);
}
}
}
diff --git a/components.h b/components.h
index f23b35e..63a62c5 100644
--- a/components.h
+++ b/components.h
@@ -55,7 +55,9 @@ typedef enum {
ctype_debris = 1 << 8,
ctype_collider = 1 << 9,
ctype_player = 1 << 10,
- ctype_destroy_on_anim_done = 1 << 11
+ ctype_destroy_on_anim_done = 1 << 11,
+ ctype_solid = 1 << 12,
+ ctype_moveable = 1 << 13
} CType;
#endif
diff --git a/enemy.c b/enemy.c
index 6729862..8b2642f 100644
--- a/enemy.c
+++ b/enemy.c
@@ -20,7 +20,8 @@ Entity new_skull(World* world, int x, int y) {
ctype_sprite |
ctype_enemy |
ctype_skull |
- ctype_collider
+ ctype_collider |
+ ctype_moveable
);
pos = &world->positions[e];
sprite = &world->sprites[e];
diff --git a/game.c b/game.c
index 00e4265..b3d40fb 100644
--- a/game.c
+++ b/game.c
@@ -87,7 +87,7 @@ static void menu_deinit(Game* game) {
static void gameplay_init(Game* game) {
init_world(&game->world);
- init_map(&game->world.map);
+ init_map(&game->world.map, &game->world);
init_player(&game->world.player, &game->world);
new_skull(&game->world, 0, 0);
}
@@ -103,6 +103,7 @@ static void gameplay_update(Game* game) {
collision_system(&game->world);
animation_system(&game->world);
render_map(&game->world.map, cx, cy);
+ update_camera(&game->world.player, &game->world);
sprite_system(&game->world);
}
diff --git a/map.c b/map.c
index 2b10abd..d8b6e1c 100644
--- a/map.c
+++ b/map.c
@@ -1,8 +1,9 @@
#include "map.h"
#include "sprite.h"
#include "standard.h"
+#include "solid.h"
-void init_map(Map* map) {
+void init_map(Map* map, World* world) {
const Sprite* floor, * bricks;
const Bitmap* fbmp, * bbmp;
Bitmap bitmap;
@@ -67,6 +68,36 @@ void init_map(Map* map) {
);
}
+ /* Bounds */
+ new_solid(
+ world,
+ 0,
+ 0,
+ (map_width * map_tile_size) << fbits,
+ map_tile_size << fbits
+ );
+ new_solid(
+ world,
+ 0,
+ ((map_height - 1) * map_tile_size) << fbits,
+ (map_width * map_tile_size) << fbits,
+ map_tile_size << fbits
+ );
+ new_solid(
+ world,
+ 0,
+ 0,
+ map_tile_size << fbits,
+ (map_height * map_tile_size) << fbits
+ );
+ new_solid(
+ world,
+ ((map_width - 1) * map_tile_size) << fbits,
+ 0,
+ map_tile_size << fbits,
+ (map_height * map_tile_size) << fbits
+ );
+
for (i = 0; i < 20; i++) {
x = rand_range(0, map_width - 1) * map_tile_size;
y = rand_range(0, map_height - 1) * map_tile_size;
@@ -77,6 +108,13 @@ void init_map(Map* map) {
y,
&bricks->rect
);
+ new_solid(
+ world,
+ x << fbits,
+ y << fbits,
+ map_tile_size << fbits,
+ map_tile_size << fbits
+ );
}
}
diff --git a/map.h b/map.h
index 35e97f2..5b79195 100644
--- a/map.h
+++ b/map.h
@@ -4,6 +4,8 @@
#include "game_config.h"
#include "render.h"
+struct World;
+
typedef struct {
Colour pixels[
map_width *
@@ -13,7 +15,7 @@ typedef struct {
];
} Map;
-void init_map(Map* map);
+void init_map(Map* map, struct World* world);
void render_map(Map* map, int cx, int cy);
#endif
diff --git a/player.c b/player.c
index d79beed..4a82cff 100644
--- a/player.c
+++ b/player.c
@@ -26,7 +26,8 @@ void init_player(Player* player, World* world) {
ctype_position |
ctype_animated |
ctype_collider |
- ctype_player
+ ctype_player |
+ ctype_moveable
);
pos = &world->positions[e];
sprite = &world->sprites[e];
@@ -55,7 +56,7 @@ void init_player(Player* player, World* world) {
}
void update_player(Player* player, World* world) {
- int dx, dy, cbx, cby;
+ int dx, dy;
int face, moving = 0;
Entity e;
CPosition* pos;
@@ -132,6 +133,19 @@ void update_player(Player* player, World* world) {
game_change_state(&game, game_state_dead);
}
+ player->shoot_countdown--;
+}
+
+void player_take_damage(Player* player, int dmg) {
+ player->hp -= dmg;
+}
+
+void update_camera(Player* player, World* world) {
+ const CPosition* pos;
+ int cbx, cby;
+
+ pos = &world->positions[player->entity];
+
world->cam_x = pos->x - ((renderer_w / 2) << fbits);
world->cam_y = pos->y - ((renderer_h / 2) << fbits);
@@ -151,10 +165,4 @@ void update_player(Player* player, World* world) {
if (world->cam_y > cby) {
world->cam_y = cby;
}
-
- player->shoot_countdown--;
-}
-
-void player_take_damage(Player* player, int dmg) {
- player->hp -= dmg;
}
diff --git a/player.h b/player.h
index 0e84b9e..0fb3e4d 100644
--- a/player.h
+++ b/player.h
@@ -15,5 +15,6 @@ typedef struct {
void init_player(Player* player, struct World* world);
void update_player(Player* player, struct World* world);
void player_take_damage(Player* player, int dmg);
+void update_camera(Player* player, struct World* world);
#endif
diff --git a/solid.c b/solid.c
new file mode 100644
index 0000000..40c3656
--- /dev/null
+++ b/solid.c
@@ -0,0 +1,27 @@
+#include "solid.h"
+
+Entity new_solid(World* world, int x, int y, int w, int h) {
+ Entity e;
+ CCollider* col;
+ CPosition* pos;
+
+ e = new_entity(world);
+ add_components(
+ world,
+ e,
+ ctype_position |
+ ctype_collider |
+ ctype_solid
+ );
+ pos = &world->positions[e];
+ col = &world->colliders[e];
+
+ pos->x = x;
+ pos->y = y;
+ col->x = 0;
+ col->y = 0;
+ col->w = w;
+ col->h = h;
+
+ return e;
+}
diff --git a/solid.h b/solid.h
new file mode 100644
index 0000000..e861e6d
--- /dev/null
+++ b/solid.h
@@ -0,0 +1,8 @@
+#ifndef solid_h
+#define solid_h
+
+#include "world.h"
+
+Entity new_solid(World* world, int x, int y, int w, int h);
+
+#endif