Improve collision system
Changelog: - Add handling for complete overlap - It will attempt to move into an empty space near the checked entity. If no free space, it will move up. Ripe for exploit! - Move boundary collision check into movement update - AABB check now returns overlap mode: - 0: no overlap - 1: partial overlap - 2: complete overlapscene_man
parent
dbf80508ec
commit
57cb3ef07a
|
@ -1,55 +1,29 @@
|
|||
#include "AABB.h"
|
||||
|
||||
bool find_1D_overlap(Vector2 l1, Vector2 l2, float* overlap)
|
||||
uint8_t find_1D_overlap(Vector2 l1, Vector2 l2, float* overlap)
|
||||
{
|
||||
// No Overlap
|
||||
if (l1.y < l2.x || l2.y < l1.x) return false;
|
||||
if (l1.y < l2.x || l2.y < l1.x) return 0;
|
||||
|
||||
if (l1.x >= l2.x && l1.y <= l2.y)
|
||||
{
|
||||
// Complete Overlap, not sure what to do tbh
|
||||
//*overlap = l2.y-l2.x + l1.y-l1.x;
|
||||
float l1_mag = l1.y - l2.x;
|
||||
float l2_mag = l2.y - l2.x;
|
||||
float c1 = l2.y - l1.y;
|
||||
float c2 = l1.x - l2.x;
|
||||
float len_to_add = l1_mag;
|
||||
if (l1_mag > l2_mag)
|
||||
{
|
||||
len_to_add = l2_mag;
|
||||
c1 *= -1;
|
||||
c2 *= -1;
|
||||
// Complete Overlap, any direction is possible
|
||||
// Cannot give a singular value, but return something anyways
|
||||
*overlap = l2.y-l2.x + l1.y-l1.x;
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (c1 < c2)
|
||||
{
|
||||
*overlap = -len_to_add - c1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*overlap = len_to_add + c2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Partial overlap
|
||||
// x is p1, y is p2
|
||||
*overlap = (l2.y >= l1.y)? l2.x - l1.y : l2.y - l1.x;
|
||||
}
|
||||
//if (fabs(*overlap) < 0.01) // Use 2 dp precision
|
||||
//{
|
||||
// *overlap = 0;
|
||||
// return false;
|
||||
//}
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool find_AABB_overlap(const Vector2 tl1, const Vector2 sz1, const Vector2 tl2, const Vector2 sz2, Vector2* overlap)
|
||||
uint8_t find_AABB_overlap(const Vector2 tl1, const Vector2 sz1, const Vector2 tl2, const Vector2 sz2, Vector2* overlap)
|
||||
{
|
||||
// Note that we include one extra pixel for checking
|
||||
// This avoid overlapping on the border
|
||||
Vector2 l1, l2;
|
||||
bool overlap_x, overlap_y;
|
||||
uint8_t overlap_x, overlap_y;
|
||||
l1.x = tl1.x;
|
||||
l1.y = tl1.x + sz1.x;
|
||||
l2.x = tl2.x;
|
||||
|
@ -62,7 +36,8 @@ bool find_AABB_overlap(const Vector2 tl1, const Vector2 sz1, const Vector2 tl2,
|
|||
l2.y = tl2.y + sz2.y;
|
||||
overlap_y = find_1D_overlap(l1, l2, &overlap->y);
|
||||
|
||||
return overlap_x && overlap_y;
|
||||
if (overlap_x == 2 && overlap_y == 2) return 2;
|
||||
return (overlap_x < overlap_y) ? overlap_x : overlap_y;
|
||||
}
|
||||
|
||||
bool point_in_AABB(Vector2 point, Rectangle box)
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
#define __AABB_H
|
||||
#include "raylib.h"
|
||||
#include "raymath.h"
|
||||
bool find_1D_overlap(Vector2 l1, Vector2 l2, float* overlap);
|
||||
bool find_AABB_overlap(const Vector2 tl1, const Vector2 sz1, const Vector2 tl2, const Vector2 sz2, Vector2* overlap);
|
||||
#include <stdint.h>
|
||||
uint8_t find_1D_overlap(Vector2 l1, Vector2 l2, float* overlap);
|
||||
uint8_t find_AABB_overlap(const Vector2 tl1, const Vector2 sz1, const Vector2 tl2, const Vector2 sz2, Vector2* overlap);
|
||||
bool point_in_AABB(Vector2 point, Rectangle box);
|
||||
#endif // __AABB_H
|
||||
|
|
|
@ -42,6 +42,7 @@ typedef struct CollideEntity {
|
|||
} CollideEntity_t;
|
||||
|
||||
// ------------------------- Collision functions ------------------------------------
|
||||
// Do not subtract one for the size for any collision check, just pass normally. The extra one is important for AABB test
|
||||
static bool check_collision(const CollideEntity_t* ent, TileGrid_t* grid, bool check_oneway)
|
||||
{
|
||||
for(unsigned int tile_y = ent->area.tile_y1; tile_y <= ent->area.tile_y2; tile_y++)
|
||||
|
@ -92,7 +93,6 @@ static bool check_collision(const CollideEntity_t* ent, TileGrid_t* grid, bool c
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
// TODO: This should be a point collision check, not an AABB check
|
||||
static bool check_collision_at(
|
||||
Entity_t* p_ent, Vector2 pos, Vector2 bbox_sz,
|
||||
|
@ -146,7 +146,8 @@ static bool check_collision_and_move(
|
|||
CBBox_t* p_bbox = get_component(ent, CBBOX_COMP_T);
|
||||
Vector2 overlap = {0,0};
|
||||
Vector2 prev_overlap = {0,0};
|
||||
if (find_AABB_overlap(p_ct->position, p_bbox->size, *other_pos, other_bbox, &overlap))
|
||||
uint8_t overlap_mode = find_AABB_overlap(p_ct->position, p_bbox->size, *other_pos, other_bbox, &overlap);
|
||||
if (overlap_mode == 1)
|
||||
{
|
||||
// If there is collision, use previous overlap to determine direction
|
||||
find_AABB_overlap(p_ct->prev_position, p_bbox->size, *other_pos, other_bbox, &prev_overlap);
|
||||
|
@ -191,9 +192,49 @@ static bool check_collision_and_move(
|
|||
//*other_pos = Vector2Subtract(*other_pos, offset);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
else if (overlap_mode == 2)
|
||||
{
|
||||
if ( other_solid != SOLID ) goto collision_end;
|
||||
// On complete overlap, find a free space in this order: top, left, right, bottom
|
||||
Vector2 point_to_test = {0};
|
||||
point_to_test.x = p_ct->position.x;
|
||||
point_to_test.y = other_pos->y - p_bbox->size.y;
|
||||
if (!check_collision_at(ent, point_to_test, p_bbox->size, tilemap, (Vector2){0}))
|
||||
{
|
||||
p_ct->position = point_to_test;
|
||||
goto collision_end;
|
||||
}
|
||||
|
||||
point_to_test.x = other_pos->x - p_bbox->size.x;
|
||||
point_to_test.y = p_ct->position.y;
|
||||
if (!check_collision_at(ent, point_to_test, p_bbox->size, tilemap, (Vector2){0}))
|
||||
{
|
||||
p_ct->position = point_to_test;
|
||||
goto collision_end;
|
||||
}
|
||||
|
||||
point_to_test.x = other_pos->x + other_bbox.x;
|
||||
point_to_test.y = p_ct->position.y;
|
||||
if (!check_collision_at(ent, point_to_test, p_bbox->size, tilemap, (Vector2){0}))
|
||||
{
|
||||
p_ct->position = point_to_test;
|
||||
goto collision_end;
|
||||
}
|
||||
|
||||
point_to_test.x = p_ct->position.x;
|
||||
point_to_test.y = other_pos->y + other_bbox.y;
|
||||
if (!check_collision_at(ent, point_to_test, p_bbox->size, tilemap, (Vector2){0}))
|
||||
{
|
||||
p_ct->position = point_to_test;
|
||||
goto collision_end;
|
||||
}
|
||||
// If no free space, Move up no matter what
|
||||
p_ct->position.x = p_ct->position.x;
|
||||
p_ct->position.y = other_pos->y - p_bbox->size.y;
|
||||
}
|
||||
collision_end:
|
||||
return overlap_mode > 0;
|
||||
}
|
||||
|
||||
static uint8_t check_bbox_edges(
|
||||
|
@ -676,36 +717,6 @@ void tile_collision_system(Scene_t* scene)
|
|||
if (p_ctransform->velocity.y > 0) p_ctransform->velocity.y = 0;
|
||||
}
|
||||
|
||||
// Level boundary collision
|
||||
unsigned int level_width = tilemap.width * TILE_SIZE;
|
||||
if(p_ctransform->position.x < 0 || p_ctransform->position.x + p_bbox->size.x > level_width)
|
||||
{
|
||||
p_ctransform->position.x = (p_ctransform->position.x < 0) ? 0 : p_ctransform->position.x;
|
||||
if (p_ctransform->position.x + p_bbox->size.x > level_width)
|
||||
{
|
||||
p_ctransform->position.x = level_width - p_bbox->size.x;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_ctransform->position.x = p_ctransform->position.x;
|
||||
}
|
||||
p_ctransform->velocity.x *= -1;
|
||||
}
|
||||
|
||||
unsigned int level_height = tilemap.height * TILE_SIZE;
|
||||
if(p_ctransform->position.y < 0 || p_ctransform->position.y + p_bbox->size.y > level_height)
|
||||
{
|
||||
p_ctransform->position.y = (p_ctransform->position.y < 0) ? 0 : p_ctransform->position.y;
|
||||
if (p_ctransform->position.y + p_bbox->size.y > level_height)
|
||||
{
|
||||
p_ctransform->position.y = level_height - p_bbox->size.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_ctransform->position.y = p_ctransform->position.y;
|
||||
}
|
||||
p_ctransform->velocity.y *= -1;
|
||||
}
|
||||
// Deal with float precision, by rounding when it is near to an integer enough by 2 dp
|
||||
float decimal;
|
||||
float fractional = modff(p_ctransform->position.x, &decimal);
|
||||
|
@ -1052,10 +1063,13 @@ void player_pushing_system(Scene_t* scene)
|
|||
|
||||
void movement_update_system(Scene_t* scene)
|
||||
{
|
||||
LevelSceneData_t* data = &(CONTAINER_OF(scene, LevelScene_t, scene)->data);
|
||||
TileGrid_t tilemap = data->tilemap;
|
||||
// Update movement
|
||||
float delta_time = 0.017; // TODO: Will need to think about delta time handling
|
||||
CTransform_t * p_ctransform;
|
||||
sc_map_foreach_value(&scene->ent_manager.component_map[CTRANSFORM_COMP_T], p_ctransform)
|
||||
unsigned long ent_idx;
|
||||
sc_map_foreach(&scene->ent_manager.component_map[CTRANSFORM_COMP_T], ent_idx, p_ctransform)
|
||||
{
|
||||
p_ctransform->prev_velocity = p_ctransform->velocity;
|
||||
p_ctransform->velocity =
|
||||
|
@ -1082,6 +1096,39 @@ void movement_update_system(Scene_t* scene)
|
|||
);
|
||||
p_ctransform->accel.x = 0;
|
||||
p_ctransform->accel.y = 0;
|
||||
|
||||
// Level boundary collision
|
||||
Entity_t* p_ent = get_entity(&scene->ent_manager, ent_idx);
|
||||
CBBox_t* p_bbox = get_component(p_ent, CBBOX_COMP_T);
|
||||
unsigned int level_width = tilemap.width * TILE_SIZE;
|
||||
if(p_ctransform->position.x < 0 || p_ctransform->position.x + p_bbox->size.x > level_width)
|
||||
{
|
||||
p_ctransform->position.x = (p_ctransform->position.x < 0) ? 0 : p_ctransform->position.x;
|
||||
if (p_ctransform->position.x + p_bbox->size.x > level_width)
|
||||
{
|
||||
p_ctransform->position.x = level_width - p_bbox->size.x;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_ctransform->position.x = p_ctransform->position.x;
|
||||
}
|
||||
p_ctransform->velocity.x = 0;
|
||||
}
|
||||
|
||||
unsigned int level_height = tilemap.height * TILE_SIZE;
|
||||
if(p_ctransform->position.y < 0 || p_ctransform->position.y + p_bbox->size.y > level_height)
|
||||
{
|
||||
p_ctransform->position.y = (p_ctransform->position.y < 0) ? 0 : p_ctransform->position.y;
|
||||
if (p_ctransform->position.y + p_bbox->size.y > level_height)
|
||||
{
|
||||
p_ctransform->position.y = level_height - p_bbox->size.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_ctransform->position.y = p_ctransform->position.y;
|
||||
}
|
||||
p_ctransform->velocity.y = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue