Improve crushing response

Changelog:
- Fix incomplete line-AABB collision check
- Add line-AABB check for grid
- Change len_reduction to 0
- Set tiles to check once during edge checking
scene_man
En Yi 2023-06-22 22:19:39 +08:00
parent 5267c318f2
commit bb4a9a8f3c
2 changed files with 53 additions and 21 deletions

View File

@ -58,12 +58,14 @@ bool line_in_AABB(Vector2 p1, Vector2 p2, Rectangle box)
Vector2 corners[3] = Vector2 corners[3] =
{ {
{box.x + box.width - 1, box.y}, {box.x + box.width, box.y},
{box.x + box.width - 1, box.y + box.height - 1}, {box.x + box.width, box.y + box.height},
{box.x, box.y + box.height - 1}, {box.x, box.y + box.height},
}; };
float F = (A * box.x + B * box.y + C); float F = (A * box.x + B * box.y + C);
bool collide = false;
uint8_t last_mode = 0; uint8_t last_mode = 0;
if (fabs(F) < 1e-3) if (fabs(F) < 1e-3)
{ {
@ -86,8 +88,29 @@ bool line_in_AABB(Vector2 p1, Vector2 p2, Rectangle box)
{ {
mode = (F > 0) ? 1 : 2; mode = (F > 0) ? 1 : 2;
} }
if (mode != last_mode) return true; if (mode != last_mode)
{
collide = true;
break;
}
last_mode = mode; last_mode = mode;
} }
return false; if (!collide) return false;
//Projection check
Vector2 overlap = {0};
Vector2 l1, l2;
l1.x = p1.x;
l1.y = p2.x;
l2.x = box.x;
l2.y = box.x + box.width;
find_1D_overlap(l1, l2, &overlap.x);
l1.x = p1.y;
l1.y = p2.y;
l2.x = box.y;
l2.y = box.y + box.height;
find_1D_overlap(l1, l2, &overlap.y);
return (overlap.x != 0 && overlap.y != 0);
} }

View File

@ -107,7 +107,16 @@ static uint8_t check_collision_line(const CollideEntity_t* ent, TileGrid_t* grid
{ {
if (tile_x >= grid->width) return 0; if (tile_x >= grid->width) return 0;
unsigned int tile_idx = tile_y*grid->width + tile_x; unsigned int tile_idx = tile_y*grid->width + tile_x;
if (grid->tiles[tile_idx].solid == SOLID) return 1; if (grid->tiles[tile_idx].solid == SOLID)
{
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
};
if ( line_in_AABB(p1, p2, tile_rec) ) return 1;
}
if (check_oneway && grid->tiles[tile_idx].solid == ONE_WAY) if (check_oneway && grid->tiles[tile_idx].solid == ONE_WAY)
{ {
@ -241,7 +250,7 @@ static bool check_collision_and_move(
&& (p_ct->prev_position.y + p_bbox->size.y - 1 < other_pos->y)) && (p_ct->prev_position.y + p_bbox->size.y - 1 < other_pos->y))
) )
{ {
//if (!check_collision_at(ent, p_ct->position, p_bbox->size, tilemap, offset)) //if (!check_collision_offset(ent, p_ct->position, p_bbox->size, tilemap, offset))
{ {
p_ct->position = Vector2Add(p_ct->position, offset); p_ct->position = Vector2Add(p_ct->position, offset);
} }
@ -314,9 +323,9 @@ static uint8_t check_bbox_edges(
.prev_bbox = (Rectangle){pos.x, pos.y, bbox.x, bbox.y}, .prev_bbox = (Rectangle){pos.x, pos.y, bbox.x, bbox.y},
.area = (TileArea_t){ .area = (TileArea_t){
.tile_x1 = (pos.x - 1) / TILE_SIZE, .tile_x1 = (pos.x - 1) / TILE_SIZE,
.tile_y1 = (pos.y) / TILE_SIZE, .tile_y1 = (pos.y - 1) / TILE_SIZE,
.tile_x2 = (pos.x - 1) / TILE_SIZE, .tile_x2 = (pos.x + bbox.x) / TILE_SIZE,
.tile_y2 = (pos.y + bbox.y - 1) / TILE_SIZE, .tile_y2 = (pos.y + bbox.y) / TILE_SIZE,
} }
}; };
@ -326,9 +335,9 @@ static uint8_t check_bbox_edges(
detected |= (check_collision_line(&ent, tilemap, false) ? 1 : 0) << 3; detected |= (check_collision_line(&ent, tilemap, false) ? 1 : 0) << 3;
//Right //Right
ent.bbox.x = pos.x + bbox.x; // 2 to account for the previous subtraction ent.bbox.x = pos.x + bbox.x + 1; // 2 to account for the previous subtraction
ent.area.tile_x1 = (pos.x + bbox.x) / TILE_SIZE; //ent.area.tile_x1 = (pos.x + bbox.x) / TILE_SIZE;
ent.area.tile_x2 = ent.area.tile_x1; //ent.area.tile_x2 = ent.area.tile_x1;
detected |= (check_collision_line(&ent, tilemap, false) ? 1 : 0) << 2; detected |= (check_collision_line(&ent, tilemap, false) ? 1 : 0) << 2;
// Up // Up
@ -336,16 +345,16 @@ static uint8_t check_bbox_edges(
ent.bbox.y = pos.y - 1; ent.bbox.y = pos.y - 1;
ent.bbox.width = bbox.x; ent.bbox.width = bbox.x;
ent.bbox.height = 1; ent.bbox.height = 1;
ent.area.tile_x1 = (pos.x) / TILE_SIZE, //ent.area.tile_x1 = (pos.x) / TILE_SIZE,
ent.area.tile_x2 = (pos.x + bbox.x - 1) / 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_y1 = (pos.y - 1) / TILE_SIZE,
ent.area.tile_y2 = ent.area.tile_y1; //ent.area.tile_y2 = ent.area.tile_y1;
detected |= (check_collision_line(&ent, tilemap, false) ? 1 : 0) << 1; detected |= (check_collision_line(&ent, tilemap, false) ? 1 : 0) << 1;
// Down // Down
ent.bbox.y = pos.y + bbox.y; ent.bbox.y = pos.y + bbox.y + 1;
ent.area.tile_y1 = (pos.y + bbox.y) / TILE_SIZE, //ent.area.tile_y1 = (pos.y + bbox.y) / TILE_SIZE,
ent.area.tile_y2 = ent.area.tile_y1; //ent.area.tile_y2 = ent.area.tile_y1;
detected |= (check_collision_line(&ent, tilemap, true) ? 1 : 0); detected |= (check_collision_line(&ent, tilemap, true) ? 1 : 0);
return detected; return detected;
} }
@ -686,7 +695,7 @@ void player_crushing_system(Scene_t* scene)
uint8_t edges = check_bbox_edges( uint8_t edges = check_bbox_edges(
&data->tilemap, p_player, &data->tilemap, p_player,
p_ctransform->position, p_ctransform->prev_position, p_bbox->size, 2 p_ctransform->position, p_ctransform->prev_position, p_bbox->size, 0
); );
if ((edges & 0b1100) == 0b1100 || (edges & 0b0011) == 0b0011) if ((edges & 0b1100) == 0b1100 || (edges & 0b0011) == 0b0011)