From 4b91ab5667bf5d3f230bd37c19eba439a0f98993 Mon Sep 17 00:00:00 2001 From: En Yi Date: Wed, 21 Jun 2023 21:13:02 +0800 Subject: [PATCH] Integrate line check into edge check function Internal Changelog: - Weird issue when using the new AABB functions, revert the off-by-one fix --- scenes/engine/AABB.c | 10 +++--- scenes/game_systems.c | 74 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 71 insertions(+), 13 deletions(-) diff --git a/scenes/engine/AABB.c b/scenes/engine/AABB.c index 7f03951..1837598 100644 --- a/scenes/engine/AABB.c +++ b/scenes/engine/AABB.c @@ -14,7 +14,7 @@ uint8_t find_1D_overlap(Vector2 l1, Vector2 l2, float* overlap) } //Partial overlap // x is p1, y is p2 - *overlap = (l2.y >= l1.y)? l2.x - l1.y - 1 : l2.y - l1.x + 1; + *overlap = (l2.y >= l1.y)? l2.x - l1.y : l2.y - l1.x; return 1; } @@ -25,15 +25,15 @@ uint8_t find_AABB_overlap(const Vector2 tl1, const Vector2 sz1, const Vector2 tl Vector2 l1, l2; uint8_t overlap_x, overlap_y; l1.x = tl1.x; - l1.y = tl1.x + sz1.x - 1; + l1.y = tl1.x + sz1.x; l2.x = tl2.x; - l2.y = tl2.x + sz2.x - 1; + l2.y = tl2.x + sz2.x; overlap_x = find_1D_overlap(l1, l2, &overlap->x); l1.x = tl1.y; - l1.y = tl1.y + sz1.y - 1; + l1.y = tl1.y + sz1.y; l2.x = tl2.y; - l2.y = tl2.y + sz2.y - 1; + l2.y = tl2.y + sz2.y; overlap_y = find_1D_overlap(l1, l2, &overlap->y); if (overlap_x == 2 && overlap_y == 2) return 2; diff --git a/scenes/game_systems.c b/scenes/game_systems.c index 621f045..6ea31d2 100644 --- a/scenes/game_systems.c +++ b/scenes/game_systems.c @@ -96,6 +96,62 @@ static uint8_t check_collision(const CollideEntity_t* ent, TileGrid_t* grid, boo return 0; } +static uint8_t check_collision_line(const CollideEntity_t* ent, TileGrid_t* grid, bool check_oneway) +{ + Vector2 p1 = {ent->bbox.x, ent->bbox.y}; + Vector2 p2 = {ent->bbox.x + ent->bbox.width - 1, ent->bbox.y + ent->bbox.height - 1}; + for(unsigned int tile_y = ent->area.tile_y1; tile_y <= ent->area.tile_y2; tile_y++) + { + if (tile_y >= grid->height) return 0; + for(unsigned int tile_x = ent->area.tile_x1; tile_x <= ent->area.tile_x2; tile_x++) + { + if (tile_x >= grid->width) return 0; + unsigned int tile_idx = tile_y*grid->width + tile_x; + if (grid->tiles[tile_idx].solid == SOLID) return 1; + + if (check_oneway && grid->tiles[tile_idx].solid == ONE_WAY) + { + Rectangle tile_rec = { + .x = tile_x * TILE_SIZE + grid->tiles[tile_idx].offset.x, + .y = tile_y * TILE_SIZE + grid->tiles[tile_idx].offset.y, + .width = grid->tiles[tile_idx].size.x, + .height = grid->tiles[tile_idx].size.y + }; + bool collide = line_in_AABB(p1, p2, tile_rec); + + //For one-way platform, check for vectical collision, only return true for up direction + if (collide && ent->prev_bbox.y + ent->prev_bbox.height - 1 < tile_y * TILE_SIZE) return 1; + } + + Entity_t* p_other_ent; + sc_map_foreach_value(&grid->tiles[tile_idx].entities_set, p_other_ent) + { + if (ent->p_ent->m_id == p_other_ent->m_id) continue; + if (!ent->p_ent->m_alive) continue; + CTransform_t *p_ctransform = get_component(p_other_ent, CTRANSFORM_COMP_T); + CBBox_t *p_bbox = get_component(p_other_ent, CBBOX_COMP_T); + if (p_bbox == NULL || p_ctransform == NULL) continue; + //if (p_bbox->solid && !p_bbox->fragile) + if (p_bbox->solid) + { + Rectangle box = { + .x = p_ctransform->position.x, + .y = p_ctransform->position.y, + .width = p_bbox->size.x, + .height = p_bbox->size.y, + }; + if ( line_in_AABB(p1, p2, box) ) + { + return (p_bbox->fragile) ? 2 : 1; + } + } + } + } + } + return 0; +} + + // TODO: This should be a point collision check, not an AABB check static bool check_collision_offset( Entity_t* p_ent, Vector2 pos, Vector2 bbox_sz, @@ -249,7 +305,7 @@ static uint8_t check_bbox_edges( CollideEntity_t ent = { .p_ent = p_ent, - .bbox = (Rectangle){pos.x - 1, pos.y, bbox.x, bbox.y}, + .bbox = (Rectangle){pos.x - 1, pos.y, 1, bbox.y}, .prev_bbox = (Rectangle){pos.x, pos.y, bbox.x, bbox.y}, .area = (TileArea_t){ .tile_x1 = (pos.x - 1) / TILE_SIZE, @@ -262,28 +318,30 @@ static uint8_t check_bbox_edges( // TODO: Handle one-way platform // Left - detected |= (check_collision(&ent, tilemap, false) ? 1 : 0) << 3; + detected |= (check_collision_line(&ent, tilemap, false) ? 1 : 0) << 3; //Right - ent.bbox.x += 2; // 2 to account for the previous subtraction + ent.bbox.x = pos.x + bbox.x; // 2 to account for the previous subtraction ent.area.tile_x1 = (pos.x + bbox.x) / TILE_SIZE; ent.area.tile_x2 = ent.area.tile_x1; - detected |= (check_collision(&ent, tilemap, false) ? 1 : 0) << 2; + detected |= (check_collision_line(&ent, tilemap, false) ? 1 : 0) << 2; // Up - ent.bbox.x -= 2; + ent.bbox.x = pos.x; ent.bbox.y--; + ent.bbox.width = bbox.x; + ent.bbox.height = 1; ent.area.tile_x1 = (pos.x) / TILE_SIZE, ent.area.tile_x2 = (pos.x + bbox.x - 1) / TILE_SIZE, ent.area.tile_y1 = (pos.y - 1) / TILE_SIZE, ent.area.tile_y2 = ent.area.tile_y1; - detected |= (check_collision(&ent, tilemap, false) ? 1 : 0) << 1; + detected |= (check_collision_line(&ent, tilemap, false) ? 1 : 0) << 1; // Down - ent.bbox.y += 2; + ent.bbox.y = pos.y + bbox.y; ent.area.tile_y1 = (pos.y + bbox.y) / TILE_SIZE, ent.area.tile_y2 = ent.area.tile_y1; - detected |= (check_collision(&ent, tilemap, true) ? 1 : 0); + detected |= (check_collision_line(&ent, tilemap, true) ? 1 : 0); return detected; }