collision mechanics

This commit is contained in:
2025-09-13 14:13:27 -05:00
parent 8417f8855a
commit 56fa075716

115
main.c
View File

@@ -6,6 +6,7 @@
#include "stdlib.h" #include "stdlib.h"
#include "stdint.h" #include "stdint.h"
#include "rlgl.h" #include "rlgl.h"
#include <float.h> // for FLT_MAX
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Defines and Macros // Defines and Macros
@@ -36,6 +37,9 @@
#define FLOOR_EXTENT 25 #define FLOOR_EXTENT 25
#define TILE_SIZE 5.0f #define TILE_SIZE 5.0f
#define PLAYER_RADIUS 0.5f
#define PLAYER_HEIGHT 1.8f
enum game_state { enum game_state {
STATE_MENU, // 0 by default STATE_MENU, // 0 by default
STATE_GAME, // 1 STATE_GAME, // 1
@@ -109,6 +113,9 @@ int Random(int x);
static void RenderTrees(Master* g, Texture2D tree, Vector3 treepos, float treeSize); static void RenderTrees(Master* g, Texture2D tree, Vector3 treepos, float treeSize);
static void ApplyFogShaderToModel(Model *m, Shader fog); static void ApplyFogShaderToModel(Model *m, Shader fog);
static BoundingBox MakeModelWorldAABB(Model m, Vector3 pos, Vector3 scale, float yawDeg);
static BoundingBox PlayerAABB(Vector3 p);
static void ResolveAgainstBoxXZ(Master* g, BoundingBox box);
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Program main entry point // Program main entry point
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
@@ -356,6 +363,12 @@ int main(void)
bool crouching = IsKeyDown(KEY_LEFT_CONTROL); bool crouching = IsKeyDown(KEY_LEFT_CONTROL);
UpdateBody(&g, g.player.lookRotation.x, sideway, forward, IsKeyDown(KEY_SPACE), crouching); UpdateBody(&g, g.player.lookRotation.x, sideway, forward, IsKeyDown(KEY_SPACE), crouching);
// Build wall collider (scale must match your DrawModelEx scale)
BoundingBox wallBox = MakeModelWorldAABB(wall, wall_position, (Vector3){5,5,5}, wall_yaw);
// Collide player vs wall (XZ slide)
ResolveAgainstBoxXZ(&g, wallBox);
float delta = GetFrameTime(); float delta = GetFrameTime();
g.player.headLerp = Lerp(g.player.headLerp, (crouching ? CROUCH_HEIGHT : STAND_HEIGHT), 20.0f*delta); g.player.headLerp = Lerp(g.player.headLerp, (crouching ? CROUCH_HEIGHT : STAND_HEIGHT), 20.0f*delta);
g.player.camera.position = (Vector3){ g.player.camera.position = (Vector3){
@@ -830,3 +843,105 @@ static void ApplyFogShaderToModel(Model *m, Shader fog)
mat->shader = fog; mat->shader = fog;
} }
} }
// Build player's AABB from its position (XZ radius, fixed height)
static BoundingBox PlayerAABB(Vector3 p)
{
BoundingBox bb;
bb.min = (Vector3){ p.x - PLAYER_RADIUS, p.y, p.z - PLAYER_RADIUS };
bb.max = (Vector3){ p.x + PLAYER_RADIUS, p.y + PLAYER_HEIGHT, p.z + PLAYER_RADIUS };
return bb;
}
// Combine all mesh AABBs of a Model in LOCAL space
static BoundingBox ModelLocalAABB(Model m)
{
BoundingBox out;
out.min = (Vector3){ FLT_MAX, FLT_MAX, FLT_MAX };
out.max = (Vector3){ -FLT_MAX, -FLT_MAX, -FLT_MAX };
for (int i = 0; i < m.meshCount; ++i) {
BoundingBox b = GetMeshBoundingBox(m.meshes[i]); // local-space box of this mesh
if (b.min.x < out.min.x) out.min.x = b.min.x;
if (b.min.y < out.min.y) out.min.y = b.min.y;
if (b.min.z < out.min.z) out.min.z = b.min.z;
if (b.max.x > out.max.x) out.max.x = b.max.x;
if (b.max.y > out.max.y) out.max.y = b.max.y;
if (b.max.z > out.max.z) out.max.z = b.max.z;
}
return out;
}
// Transform a BoundingBox by a matrix and return its world AABB
static BoundingBox TransformAABB(BoundingBox bb, Matrix M)
{
Vector3 c[8] = {
{bb.min.x, bb.min.y, bb.min.z}, {bb.max.x, bb.min.y, bb.min.z},
{bb.min.x, bb.max.y, bb.min.z}, {bb.max.x, bb.max.y, bb.min.z},
{bb.min.x, bb.min.y, bb.max.z}, {bb.max.x, bb.min.y, bb.max.z},
{bb.min.x, bb.max.y, bb.max.z}, {bb.max.x, bb.max.y, bb.max.z},
};
BoundingBox out;
out.min = (Vector3){ FLT_MAX, FLT_MAX, FLT_MAX };
out.max = (Vector3){ -FLT_MAX, -FLT_MAX, -FLT_MAX };
for (int i = 0; i < 8; ++i) {
Vector3 t = Vector3Transform(c[i], M);
if (t.x < out.min.x) out.min.x = t.x;
if (t.y < out.min.y) out.min.y = t.y;
if (t.z < out.min.z) out.min.z = t.z;
if (t.x > out.max.x) out.max.x = t.x;
if (t.y > out.max.y) out.max.y = t.y;
if (t.z > out.max.z) out.max.z = t.z;
}
return out;
}
// Build world AABB for a model using the same T*R*S you render with
static BoundingBox MakeModelWorldAABB(Model m, Vector3 pos, Vector3 scale, float yawDeg)
{
BoundingBox local = ModelLocalAABB(m);
Matrix S = MatrixScale(scale.x, scale.y, scale.z);
Matrix R = MatrixRotateY(DEG2RAD * yawDeg);
Matrix T = MatrixTranslate(pos.x, pos.y, pos.z);
Matrix M = MatrixMultiply(MatrixMultiply(T, R), S); // T * R * S
return TransformAABB(local, M);
}
// Push player out of a box on the smallest X/Z overlap (slide) and zero that velocity axis
static void ResolveAgainstBoxXZ(Master* g, BoundingBox box)
{
BoundingBox p = PlayerAABB(g->player.position);
// Quick reject
if (!CheckCollisionBoxes(p, box)) return;
// Overlaps on X and Z
float ox = fminf(p.max.x, box.max.x) - fmaxf(p.min.x, box.min.x);
float oz = fminf(p.max.z, box.max.z) - fmaxf(p.min.z, box.min.z);
if (ox <= 0 || oz <= 0) return;
// Centers to know which way to push
float cxp = 0.5f * (p.min.x + p.max.x);
float czp = 0.5f * (p.min.z + p.max.z);
float cxb = 0.5f * (box.min.x + box.max.x);
float czb = 0.5f * (box.min.z + box.max.z);
// Resolve along the smallest axis
if (ox < oz) {
float push = (cxp < cxb) ? -ox : ox;
g->player.position.x += push;
g->player.velocity.x = 0.0f;
} else {
float push = (czp < czb) ? -oz : oz;
g->player.position.z += push;
g->player.velocity.z = 0.0f;
}
}