aboutsummaryrefslogtreecommitdiffstats
path: root/src/player.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/player.c')
-rw-r--r--src/player.c95
1 files changed, 92 insertions, 3 deletions
diff --git a/src/player.c b/src/player.c
index 11bc307..7917545 100644
--- a/src/player.c
+++ b/src/player.c
@@ -7,6 +7,7 @@ Player createPlayer()
.position = Vector3Zero(),
.direction = (Vector3){0.0, 0.0, 0.0},
.velocity = Vector3Zero(),
+ .speed = 0.0,
.relativeBox = (BoundingBox){
.min = (Vector3){-PLAYER_WIDTH / 2.0, -PLAYER_HEIGHT / 2.0,
-PLAYER_WIDTH / 2.0},
@@ -71,6 +72,72 @@ WorldUID playerCheckCollisionWithBuildings(Player* player, Game* game)
return ENTITY_NONE;
}
+// Returns true if collision detection should end.
+bool playerHandleCollisionWithBuildingBlock(Player* player,
+ EntityBuilding* building,
+ BoundingBox block,
+ Vector3 blockPosition,
+ int x,
+ int y,
+ bool* isFirstCollision,
+ Vector3* lastNormal)
+{
+ int normalsCount = 4;
+
+ Vector3 normals[] = {
+ (Vector3){1.0, 0.0, 0.0},
+ (Vector3){-1.0, 0.0, 0.0},
+ (Vector3){0.0, 0.0, 1.0},
+ (Vector3){0.0, 0.0, -1.0}
+ };
+
+ int closestNormalIndex = 0;
+ float closestDistance = WORLD_SIZE.x;
+
+ // Get closest normal.
+ for (int index = 0; index < normalsCount; ++index)
+ {
+ float distance = Vector3Distance(
+ player->position,
+ Vector3Add(normals[index], blockPosition));
+
+ // Avoid issues with neighboring blocks.
+ bool isNormalBlocked = isBuildingBlockWall(building,
+ x + normals[index].x,
+ y + normals[index].z);
+
+ if (!isNormalBlocked && distance < closestDistance)
+ {
+ closestDistance = distance;
+ closestNormalIndex = index;
+ }
+ }
+
+ Vector3 normal = normals[closestNormalIndex];
+
+ // Is facing wall.
+ if (Vector3DotProduct(player->velocity, normal) < 0.0)
+ {
+ // Handle collision.
+ float dotProduct = Vector3DotProduct(player->direction, normal);
+ player->velocity = Vector3Subtract(player->direction,
+ Vector3Scale(normal, dotProduct));
+ player->velocity = Vector3Scale(player->velocity, player->speed);
+
+ // Is at a corner.
+ if (!*isFirstCollision && !Vector3Equals(*lastNormal, normal))
+ {
+ player->velocity = (Vector3){0.0, 0.0, 0.0};
+ return true;
+ }
+
+ *isFirstCollision = false;
+ *lastNormal = normal;
+ }
+
+ return false;
+}
+
// TODO: Make this fucker speedy quick
void playerHandleCollisionWithBuilding(Player* player, Game* game,
WorldUID uid)
@@ -87,6 +154,9 @@ void playerHandleCollisionWithBuilding(Player* player, Game* game,
ENTITY_BUILDING_CUBE_SIZE.z / 2.0}
};
+ bool isFirstCollision = true;
+ Vector3 lastNormal = (Vector3){0.0, 0.0, 0.0};
+
for (int y = 0; y < building->height; ++y)
{
for (int x = 0; x < building->width; ++x)
@@ -105,8 +175,20 @@ void playerHandleCollisionWithBuilding(Player* player, Game* game,
};
BoundingBox box = wallBox;
- box.min = Vector3Add(box.min, place->position);
- box.max = Vector3Add(box.max, place->position);
+ box.min = Vector3Add(box.min, wallPosition);
+ box.max = Vector3Add(box.max, wallPosition);
+
+ if (CheckCollisionBoxes(player->box, box))
+ {
+ DrawBoundingBox(box, PURPLE);
+ if (playerHandleCollisionWithBuildingBlock(player, building, box,
+ wallPosition, x, y,
+ &isFirstCollision,
+ &lastNormal))
+ {
+ return;
+ }
+ }
}
}
}
@@ -147,8 +229,15 @@ void updatePlayerMovement(Player* player, Game* game)
}
player->velocity = Vector3Scale(player->velocity, PLAYER_SPEED);
+ player->speed = Vector3Length(player->velocity);
- printf("%d\n", playerCheckCollisionWithBuildings(player, game));
+ // Check collision with buildings.
+ WorldUID buildingUID = playerCheckCollisionWithBuildings(player, game);
+
+ if (buildingUID != ENTITY_NONE)
+ {
+ playerHandleCollisionWithBuilding(player, game, buildingUID);
+ }
// Apply velocity.
player->position = Vector3Add(