aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornathan <nathansmith@disroot.org>2026-01-05 09:30:25 +0000
committernathan <nathansmith@disroot.org>2026-01-05 09:30:25 +0000
commita8d803916883e49790981beed6438726406e0995 (patch)
treecc354d1231c94dbfdb67268f57a3819e03949dce
parente507ecbb95a2c7a1ffb8c13f1bd39433d6c49ba3 (diff)
downloadFindThings-a8d803916883e49790981beed6438726406e0995.tar.gz
FindThings-a8d803916883e49790981beed6438726406e0995.tar.bz2
FindThings-a8d803916883e49790981beed6438726406e0995.zip
Collision with buildings working
-rw-r--r--src/entity.c29
-rw-r--r--src/entity.h3
-rw-r--r--src/player.c95
-rw-r--r--src/player.h2
4 files changed, 116 insertions, 13 deletions
diff --git a/src/entity.c b/src/entity.c
index 4895d9e..f094f8d 100644
--- a/src/entity.c
+++ b/src/entity.c
@@ -326,10 +326,10 @@ BoundingBox entityBoxFromScale(float scale, float width, float height)
EntityBuilding* createEntityBuilding(Image heightmap)
{
- EntityBuilding* entityBuilding =
+ EntityBuilding* building =
(EntityBuilding*)FT_MALLOC(sizeof(EntityBuilding));
- if (entityBuilding == NULL)
+ if (building == NULL)
{
ALLOCATION_ERROR;
return NULL;
@@ -338,7 +338,7 @@ EntityBuilding* createEntityBuilding(Image heightmap)
float widthInWorld = heightmap.width * ENTITY_BUILDING_CUBE_SIZE.x;
float heightInWorld = heightmap.height * ENTITY_BUILDING_CUBE_SIZE.z;
- *entityBuilding = (EntityBuilding){
+ *building = (EntityBuilding){
.model = LoadModelFromMesh(GenMeshCubicmap(heightmap,
ENTITY_BUILDING_CUBE_SIZE)),
.pixelMap = LoadImageColors(heightmap),
@@ -354,19 +354,30 @@ EntityBuilding* createEntityBuilding(Image heightmap)
}
};
- return entityBuilding;
+ return building;
}
-void freeEntityBuilding(EntityBuilding* entityBuilding)
+void freeEntityBuilding(EntityBuilding* building)
{
- if (entityBuilding != NULL)
+ if (building != NULL)
{
- UnloadModel(entityBuilding->model);
- UnloadImageColors(entityBuilding->pixelMap);
- FT_FREE(entityBuilding);
+ UnloadModel(building->model);
+ UnloadImageColors(building->pixelMap);
+ FT_FREE(building);
}
}
+bool isBuildingBlockWall(const EntityBuilding* building, int x, int y)
+{
+ if (x < 0 || x >= building->width ||
+ y < 0 || y >= building->height)
+ {
+ return false;
+ }
+
+ return building->pixelMap[y * building->width + x].r == 255;
+}
+
void drawBuildingRoof(const EntityBuilding* building, Vector3 position,
Color color)
{
diff --git a/src/entity.h b/src/entity.h
index e92fbb2..8cfcad6 100644
--- a/src/entity.h
+++ b/src/entity.h
@@ -119,7 +119,8 @@ int getInteractionMenuIndex(Selection selection);
BoundingBox entityBoxFromScale(float scale, float width, float height);
EntityBuilding* createEntityBuilding(Image heightmap);
-void freeEntityBuilding(EntityBuilding* entityBuilding);
+void freeEntityBuilding(EntityBuilding* building);
+bool isBuildingBlockWall(const EntityBuilding* building, int x, int y);
void drawBuildingRoof(const EntityBuilding* building, Vector3 position,
Color color);
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(
diff --git a/src/player.h b/src/player.h
index 7755ef9..3dac500 100644
--- a/src/player.h
+++ b/src/player.h
@@ -12,7 +12,9 @@
typedef struct {
Vector3 position;
Vector3 direction;
+
Vector3 velocity;
+ float speed;
BoundingBox relativeBox;
BoundingBox box;