/* * 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 . */ #include #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); }