From 937edea9599718e959f8ed135e97c68728855975 Mon Sep 17 00:00:00 2001 From: quou Date: Sat, 6 May 2023 12:22:50 +1000 Subject: Add solid environment collisions. --- collision_system.c | 172 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 159 insertions(+), 13 deletions(-) (limited to 'collision_system.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 + +#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); } } } -- cgit v1.2.3-54-g00ecf