aboutsummaryrefslogtreecommitdiff
path: root/collision.c
diff options
context:
space:
mode:
Diffstat (limited to 'collision.c')
-rw-r--r--collision.c161
1 files changed, 161 insertions, 0 deletions
diff --git a/collision.c b/collision.c
new file mode 100644
index 0000000..828dea7
--- /dev/null
+++ b/collision.c
@@ -0,0 +1,161 @@
+/*
+ * collision.c -- Comntiene funciones de detección de colisiones.
+ * Copyright (C) 2018 Juan Marín Noguera
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+#include <math.h>
+#include "block.h"
+#include "block_list.h"
+#include "collision.h"
+#include "collision_type.h"
+#include "item.h"
+#include "item_list.h"
+#include "player.h"
+
+CollisionType collision_data(double x1, double y1, double w1, double h1,
+ double x2, double y2, double w2, double h2)
+{
+ double dw = (w1+w2)/2, dh = (h1+h2)/2;
+ double dx = x1 - x2 + dw - w2, dy = y1 - y2 + dh - h2;
+ double dxp, dyp;
+ CollisionType c = 0;
+ if (dx < dw && -dx < dw && dy < dh && -dy < dh) {
+ dxp = dx * 0.75 - dy;
+ dyp = dx * 0.75 + dy;
+ if (dxp > 0) {
+ if (dyp > 0)
+ c |= COLLISION_RIGHT;
+ else
+ c |= COLLISION_BOTTOM;
+ } else {
+ if (dyp > 0)
+ c |= COLLISION_TOP;
+ else
+ c |= COLLISION_LEFT;
+ }
+ }
+ return c;
+}
+
+void collision_hit_if_top_and_advance(Player p, BlockNode *bn,
+ CollisionType c, ItemList il)
+{
+ Item i = NULL;
+ if (c & COLLISION_TOP) {
+ if (block_hit(p, block_list_current(*bn), &i))
+ block_list_delete(*bn);
+ else
+ *bn = block_list_next(*bn);
+
+ if (i != NULL)
+ item_list_append(il, i);
+ } else {
+ *bn = block_list_next(*bn);
+ }
+}
+
+void collision_player_with_blocks(Player p, BlockList bl, ItemList il)
+{
+ BlockNode bn = block_list_begin(bl);
+ Block b;
+ double px = player_x(p), py = player_y(p), ph = player_height(p);
+ int pxb = (int)player_x(p) / BLOCK_SIZE;
+ CollisionType total_collisions = 0, c;
+
+ while (!block_list_isend(bn) &&
+ block_x(block_list_current(bn)) < pxb)
+ bn = block_list_next(bn);
+
+ while (!block_list_isend(bn) &&
+ block_x(b = block_list_current(bn)) < pxb + 2)
+ if (!block_can_pass_through(b) &&
+ (c = collision_data(
+ block_x(b) * BLOCK_SIZE,
+ block_y(b) * BLOCK_SIZE,
+ BLOCK_SIZE,
+ BLOCK_SIZE,
+ px,
+ py,
+ PLAYER_WIDTH,
+ ph))
+ != 0) {
+ collision_hit_if_top_and_advance(p, &bn, c, il);
+ total_collisions |= c;
+ } else {
+ bn = block_list_next(bn);
+ }
+
+ player_correct_on_collision(p, total_collisions);
+}
+
+void collision_player_with_items(Player p, ItemList il)
+{
+ ItemNode in = item_list_begin(il);
+ Item i;
+ double px = player_x(p), py = player_y(p), ph = player_height(p);
+ CollisionType c;
+
+ while (!item_list_isend(in)) {
+ i = item_list_current(in);
+ c = collision_data(
+ item_x(i), item_y(i), item_width(i), item_height(i),
+ px, py, PLAYER_WIDTH, ph);
+
+ if (c != 0 && item_player_collide(i, p, c))
+ item_list_delete(in);
+ else
+ item_list_advance(in);
+ }
+
+ item_list_free_node(in);
+}
+
+void collision_blocks_with_items(BlockList bl, ItemList il)
+{
+ ItemNode in;
+ Item i;
+ BlockNode bn;
+ Block b;
+ CollisionType c;
+ double ix, iy, iw, ih;
+
+ for (in = item_list_begin(il); !item_list_isend(in);
+ item_list_advance(in)) {
+ i = item_list_current(in);
+ ix = item_x(i);
+ iy = item_y(i);
+ iw = item_width(i);
+ ih = item_height(i);
+ c = 0;
+ for (bn = block_list_begin(bl); !block_list_isend(bn);
+ bn = block_list_next(bn)) {
+ b = block_list_current(bn);
+ if (!block_can_pass_through(b))
+ c |= collision_data(
+ block_x(b) * BLOCK_SIZE,
+ block_y(b) * BLOCK_SIZE,
+ BLOCK_SIZE,
+ BLOCK_SIZE,
+ ix,
+ iy,
+ iw,
+ ih);
+ }
+ if (c != 0)
+ item_correct_on_block_collision(i, c);
+ }
+
+ item_list_free_node(in);
+}