collision mechanics
This commit is contained in:
115
main.c
115
main.c
@@ -6,6 +6,7 @@
|
||||
#include "stdlib.h"
|
||||
#include "stdint.h"
|
||||
#include "rlgl.h"
|
||||
#include <float.h> // for FLT_MAX
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Defines and Macros
|
||||
@@ -36,6 +37,9 @@
|
||||
#define FLOOR_EXTENT 25
|
||||
#define TILE_SIZE 5.0f
|
||||
|
||||
#define PLAYER_RADIUS 0.5f
|
||||
#define PLAYER_HEIGHT 1.8f
|
||||
|
||||
enum game_state {
|
||||
STATE_MENU, // 0 by default
|
||||
STATE_GAME, // 1
|
||||
@@ -109,6 +113,9 @@ int Random(int x);
|
||||
static void RenderTrees(Master* g, Texture2D tree, Vector3 treepos, float treeSize);
|
||||
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
|
||||
//------------------------------------------------------------------------------------
|
||||
@@ -356,6 +363,12 @@ int main(void)
|
||||
bool crouching = IsKeyDown(KEY_LEFT_CONTROL);
|
||||
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();
|
||||
g.player.headLerp = Lerp(g.player.headLerp, (crouching ? CROUCH_HEIGHT : STAND_HEIGHT), 20.0f*delta);
|
||||
g.player.camera.position = (Vector3){
|
||||
@@ -830,3 +843,105 @@ static void ApplyFogShaderToModel(Model *m, 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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user