diff options
Diffstat (limited to 'collision.c')
| -rw-r--r-- | collision.c | 161 |
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); +} |
