collision mechanics
This commit is contained in:
115
main.c
115
main.c
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user