aboutsummaryrefslogtreecommitdiff
path: root/collision_system.c
diff options
context:
space:
mode:
Diffstat (limited to 'collision_system.c')
-rw-r--r--collision_system.c172
1 files changed, 159 insertions, 13 deletions
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);
}
}
}