Add framework for SAT collision detection

This commit is contained in:
Doyle Thai 2016-11-18 17:42:11 +11:00
parent a4e5025dd4
commit 01f99dd0ca
2 changed files with 128 additions and 5 deletions

View File

@ -218,6 +218,79 @@ v2 *createAsteroidVertexList(MemoryArena_ *arena, i32 iterations,
return result;
}
v2 *createEntityEdgeList(MemoryArena_ *transientArena, Entity *entity)
{
v2 *result = memory_pushBytes(transientArena,
sizeof(v2) * entity->numVertexPoints);
i32 numVertexes = entity->numVertexPoints;
for (i32 i = 0; i < numVertexes - 1; i++)
{
ASSERT((i + 1) < numVertexes);
result[i] =
v2_sub(entity->vertexPoints[i + 1], entity->vertexPoints[i]);
}
// NOTE(doyle): Creating the last edge requires using the first
// vertex point which is at index 0
result[numVertexes - 1] =
v2_sub(entity->vertexPoints[0], entity->vertexPoints[numVertexes - 1]);
return result;
}
b32 checkEntityProjectionOverlap(Entity *entity, Entity *checkEntity,
v2 *entityEdges)
{
b32 result = TRUE;
for (i32 edgeIndex = 0; edgeIndex < entity->numVertexPoints && result;
edgeIndex++)
{
v2 entityProjectionRange = {0};
entityProjectionRange.max =
v2_dot(entity->vertexPoints[0], entityEdges[0]);
entityProjectionRange.max = entityProjectionRange.min;
for (i32 vertexIndex = 0; vertexIndex < entity->numVertexPoints;
vertexIndex++)
{
f32 dist = v2_dot(entity->vertexPoints[vertexIndex],
entityEdges[edgeIndex]);
if (dist < entityProjectionRange.min)
entityProjectionRange.min = dist;
else if (dist > entityProjectionRange.max)
entityProjectionRange.max = dist;
}
v2 checkEntityProjectionRange = {0};
checkEntityProjectionRange.min =
v2_dot(entity->vertexPoints[0], entityEdges[0]);
checkEntityProjectionRange.max = checkEntityProjectionRange.min;
for (i32 vertexIndex = 0; vertexIndex < checkEntity->numVertexPoints;
vertexIndex++)
{
f32 dist = v2_dot(checkEntity->vertexPoints[vertexIndex],
entityEdges[edgeIndex]);
if (dist < checkEntityProjectionRange.min)
checkEntityProjectionRange.min = dist;
else if (dist > checkEntityProjectionRange.max)
checkEntityProjectionRange.max = dist;
}
if (!v2_intervalsOverlap(entityProjectionRange,
checkEntityProjectionRange))
{
result = FALSE;
return result;
}
}
return result;
}
void moveEntity(GameState *state, Entity *entity, v2 ddP, f32 dt, f32 ddPSpeed)
{
ASSERT(ABS(ddP.x) <= 1.0f && ABS(ddP.y) <= 1.0f);
@ -242,15 +315,52 @@ void moveEntity(GameState *state, Entity *entity, v2 ddP, f32 dt, f32 ddPSpeed)
v2 newPos = v2_add(v2_add(ddPHalfDtSquared, oldDpDt), oldPos);
for (i32 i = 0; i < state->entityIndex; i++)
b32 willCollide = FALSE;
#if 0
if (entity->renderMode == rendermode_polygon && entity->collides)
{
Entity *checkEntity = &state->entityList[i];
if (checkEntity->id == entity->id) continue;
for (i32 i = 0; i < state->entityIndex; i++)
{
Entity *checkEntity = &state->entityList[i];
if (checkEntity->id == entity->id) continue;
if (checkEntity->renderMode == rendermode_polygon &&
checkEntity->collides)
{
i32 numEntityEdges = entity->numVertexPoints;
i32 numCheckEntityEdges = checkEntity->numVertexPoints;
v2 *entityEdges =
createEntityEdgeList(&state->transientArena, entity);
v2 *checkEntityEdges =
createEntityEdgeList(&state->transientArena, entity);
// Convert inplace the vector normal of the edges
for (i32 i = 0; i < numEntityEdges; i++)
{
entityEdges[i] = V2(entityEdges[i].y, -entityEdges[i].x);
}
for (i32 i = 0; i < numCheckEntityEdges; i++)
{
checkEntityEdges[i] =
V2(entityEdges[i].y, -entityEdges[i].x);
}
if ((checkEntityProjectionOverlap(entity, checkEntity,
entityEdges) &&
checkEntityProjectionOverlap(entity, checkEntity,
checkEntityEdges)))
{
willCollide = TRUE;
}
}
if (willCollide) break;
}
}
#endif
b32 moveValid = TRUE;
if (moveValid)
if (!willCollide)
{
entity->dP = newDp;
entity->pos = newPos;

View File

@ -50,6 +50,7 @@ typedef union v2
{
struct { f32 x, y; };
struct { f32 w, h; };
struct { f32 min, max; };
f32 e[2];
} v2;
@ -190,6 +191,18 @@ INTERNAL inline v2 v2_normalise(const v2 a)
return result;
}
INTERNAL inline b32 v2_intervalsOverlap(const v2 a, const v2 b)
{
b32 result = FALSE;
if ((a.min >= b.min && a.min <= b.max) ||
(a.max >= b.min && a.max <= b.max))
{
result = TRUE;
}
return result;
}
INTERNAL inline v3 v3_cross(const v3 a, const v3 b)
{
/*