Add framework for SAT collision detection
This commit is contained in:
		
							parent
							
								
									a4e5025dd4
								
							
						
					
					
						commit
						01f99dd0ca
					
				
							
								
								
									
										120
									
								
								src/Asteroid.c
									
									
									
									
									
								
							
							
						
						
									
										120
									
								
								src/Asteroid.c
									
									
									
									
									
								
							| @ -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; | ||||
|  | ||||
| @ -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) | ||||
| { | ||||
| 	/*
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user