mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-17 11:35:08 -04:00
optimise collision detection a bit
This commit is contained in:
parent
cc85c297ee
commit
468e958e36
@ -30,24 +30,22 @@ namespace ClassicalSharp.Entities {
|
||||
// TODO: test for corner cases, and refactor this.
|
||||
internal void MoveAndWallSlide() {
|
||||
if (entity.Velocity == Vector3.Zero) return;
|
||||
Vector3 size = entity.Size;
|
||||
AABB entityBB, entityExtentBB;
|
||||
|
||||
AABB entityBB, entityExtentBB;
|
||||
int count = Searcher.FindReachableBlocks(game, entity,
|
||||
out entityBB, out entityExtentBB);
|
||||
CollideWithReachableBlocks(count, ref size, ref entityBB, ref entityExtentBB);
|
||||
CollideWithReachableBlocks(count, ref entityBB, ref entityExtentBB);
|
||||
}
|
||||
|
||||
void CollideWithReachableBlocks(int count, ref Vector3 size,
|
||||
ref AABB entityBB, ref AABB entityExtentBB) {
|
||||
void CollideWithReachableBlocks(int count, ref AABB entityBB, ref AABB extentBB) {
|
||||
// Reset collision detection states
|
||||
bool wasOn = entity.onGround;
|
||||
entity.onGround = false;
|
||||
hitXMin = false; hitYMin = false; hitZMin = false;
|
||||
hitXMax = false; hitYMax = false; hitZMax = false;
|
||||
AABB blockBB = default(AABB);
|
||||
Vector3 bPos;
|
||||
|
||||
|
||||
AABB blockBB;
|
||||
Vector3 bPos, size = entity.Size;
|
||||
for (int i = 0; i < count; i++) {
|
||||
// Unpack the block and coordinate data
|
||||
State state = Searcher.stateCache[i];
|
||||
@ -63,10 +61,10 @@ namespace ClassicalSharp.Entities {
|
||||
blockBB.Min.X += bPos.X; blockBB.Min.Y += bPos.Y; blockBB.Min.Z += bPos.Z;
|
||||
blockBB.Max = BlockInfo.MaxBB[block];
|
||||
blockBB.Max.X += bPos.X; blockBB.Max.Y += bPos.Y; blockBB.Max.Z += bPos.Z;
|
||||
if (!entityExtentBB.Intersects(blockBB)) continue;
|
||||
if (!extentBB.Intersects(blockBB)) continue;
|
||||
|
||||
// Recheck time to collide with block (as colliding with blocks modifies this)
|
||||
float tx = 0, ty = 0, tz = 0;
|
||||
float tx, ty, tz;
|
||||
Searcher.CalcTime(ref entity.Velocity, ref entityBB, ref blockBB, out tx, out ty, out tz);
|
||||
if (tx > 1 || ty > 1 || tz > 1)
|
||||
Utils.LogDebug("t > 1 in physics calculation.. this shouldn't have happened.");
|
||||
@ -80,91 +78,84 @@ namespace ClassicalSharp.Entities {
|
||||
// if we have hit the bottom of a block, we need to change the axis we test first.
|
||||
if (!hitYMin) {
|
||||
if (finalBB.Min.Y + Adjustment >= blockBB.Max.Y) {
|
||||
ClipYMax(ref blockBB, ref entityBB, ref entityExtentBB, ref size);
|
||||
ClipYMax(ref blockBB, ref entityBB, ref extentBB, ref size);
|
||||
} else if (finalBB.Max.Y - Adjustment <= blockBB.Min.Y) {
|
||||
ClipYMin(ref blockBB, ref entityBB, ref entityExtentBB, ref size);
|
||||
ClipYMin(ref blockBB, ref entityBB, ref extentBB, ref size);
|
||||
} else if (finalBB.Min.X + Adjustment >= blockBB.Max.X) {
|
||||
ClipXMax(ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size);
|
||||
ClipXMax(ref blockBB, ref entityBB, wasOn, ref finalBB, ref extentBB, ref size);
|
||||
} else if (finalBB.Max.X - Adjustment <= blockBB.Min.X) {
|
||||
ClipXMin(ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size);
|
||||
ClipXMin(ref blockBB, ref entityBB, wasOn, ref finalBB, ref extentBB, ref size);
|
||||
} else if (finalBB.Min.Z + Adjustment >= blockBB.Max.Z) {
|
||||
ClipZMax(ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size);
|
||||
ClipZMax(ref blockBB, ref entityBB, wasOn, ref finalBB, ref extentBB, ref size);
|
||||
} else if (finalBB.Max.Z - Adjustment <= blockBB.Min.Z) {
|
||||
ClipZMin(ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size);
|
||||
ClipZMin(ref blockBB, ref entityBB, wasOn, ref finalBB, ref extentBB, ref size);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// if flying or falling, test the horizontal axes first.
|
||||
if (finalBB.Min.X + Adjustment >= blockBB.Max.X) {
|
||||
ClipXMax(ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size);
|
||||
ClipXMax(ref blockBB, ref entityBB, wasOn, ref finalBB, ref extentBB, ref size);
|
||||
} else if (finalBB.Max.X - Adjustment <= blockBB.Min.X) {
|
||||
ClipXMin(ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size);
|
||||
ClipXMin(ref blockBB, ref entityBB, wasOn, ref finalBB, ref extentBB, ref size);
|
||||
} else if (finalBB.Min.Z + Adjustment >= blockBB.Max.Z) {
|
||||
ClipZMax(ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size);
|
||||
ClipZMax(ref blockBB, ref entityBB, wasOn, ref finalBB, ref extentBB, ref size);
|
||||
} else if (finalBB.Max.Z - Adjustment <= blockBB.Min.Z) {
|
||||
ClipZMin(ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size);
|
||||
ClipZMin(ref blockBB, ref entityBB, wasOn, ref finalBB, ref extentBB, ref size);
|
||||
} else if (finalBB.Min.Y + Adjustment >= blockBB.Max.Y) {
|
||||
ClipYMax(ref blockBB, ref entityBB, ref entityExtentBB, ref size);
|
||||
ClipYMax(ref blockBB, ref entityBB, ref extentBB, ref size);
|
||||
} else if (finalBB.Max.Y - Adjustment <= blockBB.Min.Y) {
|
||||
ClipYMin(ref blockBB, ref entityBB, ref entityExtentBB, ref size);
|
||||
ClipYMin(ref blockBB, ref entityBB, ref extentBB, ref size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClipXMin(ref AABB blockBB, ref AABB entityBB, bool wasOn,
|
||||
AABB finalBB, ref AABB entityExtentBB, ref Vector3 size) {
|
||||
if (!wasOn || !DidSlide(blockBB, ref size, finalBB, ref entityBB, ref entityExtentBB)) {
|
||||
void ClipXMin(ref AABB blockBB, ref AABB entityBB, bool wasOn, ref AABB finalBB, ref AABB extentBB, ref Vector3 size) {
|
||||
if (!wasOn || !DidSlide(blockBB, ref size, ref finalBB, ref entityBB, ref extentBB)) {
|
||||
entity.Position.X = blockBB.Min.X - size.X / 2 - Adjustment;
|
||||
ClipX(ref size, ref entityBB, ref entityExtentBB);
|
||||
ClipX(ref size, ref entityBB, ref extentBB);
|
||||
hitXMin = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ClipXMax(ref AABB blockBB, ref AABB entityBB, bool wasOn,
|
||||
AABB finalBB, ref AABB entityExtentBB, ref Vector3 size) {
|
||||
if (!wasOn || !DidSlide(blockBB, ref size, finalBB, ref entityBB, ref entityExtentBB)) {
|
||||
void ClipXMax(ref AABB blockBB, ref AABB entityBB, bool wasOn, ref AABB finalBB, ref AABB extentBB, ref Vector3 size) {
|
||||
if (!wasOn || !DidSlide(blockBB, ref size, ref finalBB, ref entityBB, ref extentBB)) {
|
||||
entity.Position.X = blockBB.Max.X + size.X / 2 + Adjustment;
|
||||
ClipX(ref size, ref entityBB, ref entityExtentBB);
|
||||
ClipX(ref size, ref entityBB, ref extentBB);
|
||||
hitXMax = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ClipZMax(ref AABB blockBB, ref AABB entityBB, bool wasOn,
|
||||
AABB finalBB, ref AABB entityExtentBB, ref Vector3 size) {
|
||||
if (!wasOn || !DidSlide(blockBB, ref size, finalBB, ref entityBB, ref entityExtentBB)) {
|
||||
void ClipZMax(ref AABB blockBB, ref AABB entityBB, bool wasOn, ref AABB finalBB, ref AABB extentBB, ref Vector3 size) {
|
||||
if (!wasOn || !DidSlide(blockBB, ref size, ref finalBB, ref entityBB, ref extentBB)) {
|
||||
entity.Position.Z = blockBB.Max.Z + size.Z / 2 + Adjustment;
|
||||
ClipZ(ref size, ref entityBB, ref entityExtentBB);
|
||||
ClipZ(ref size, ref entityBB, ref extentBB);
|
||||
hitZMax = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ClipZMin(ref AABB blockBB, ref AABB entityBB, bool wasOn,
|
||||
AABB finalBB, ref AABB extentBB, ref Vector3 size) {
|
||||
if (!wasOn || !DidSlide(blockBB, ref size, finalBB, ref entityBB, ref extentBB)) {
|
||||
void ClipZMin(ref AABB blockBB, ref AABB entityBB, bool wasOn, ref AABB finalBB, ref AABB extentBB, ref Vector3 size) {
|
||||
if (!wasOn || !DidSlide(blockBB, ref size, ref finalBB, ref entityBB, ref extentBB)) {
|
||||
entity.Position.Z = blockBB.Min.Z - size.Z / 2 - Adjustment;
|
||||
ClipZ(ref size, ref entityBB, ref extentBB);
|
||||
hitZMin = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ClipYMin(ref AABB blockBB, ref AABB entityBB,
|
||||
ref AABB extentBB, ref Vector3 size) {
|
||||
void ClipYMin(ref AABB blockBB, ref AABB entityBB, ref AABB extentBB, ref Vector3 size) {
|
||||
entity.Position.Y = blockBB.Min.Y - size.Y - Adjustment;
|
||||
ClipY(ref size, ref entityBB, ref extentBB);
|
||||
hitYMin = true;
|
||||
}
|
||||
|
||||
void ClipYMax(ref AABB blockBB, ref AABB entityBB,
|
||||
ref AABB extentBB, ref Vector3 size) {
|
||||
void ClipYMax(ref AABB blockBB, ref AABB entityBB, ref AABB extentBB, ref Vector3 size) {
|
||||
entity.Position.Y = blockBB.Max.Y + Adjustment;
|
||||
entity.onGround = true;
|
||||
ClipY(ref size, ref entityBB, ref extentBB);
|
||||
hitYMax = true;
|
||||
}
|
||||
|
||||
bool DidSlide(AABB blockBB, ref Vector3 size, AABB finalBB,
|
||||
ref AABB entityBB, ref AABB entityExtentBB) {
|
||||
bool DidSlide(AABB blockBB, ref Vector3 size, ref AABB finalBB, ref AABB entityBB, ref AABB extentBB) {
|
||||
float yDist = blockBB.Max.Y - entityBB.Min.Y;
|
||||
if (yDist > 0 && yDist <= entity.StepSize + 0.01f) {
|
||||
float blockXMin = blockBB.Min.X, blockZMin = blockBB.Min.Z;
|
||||
@ -173,7 +164,7 @@ namespace ClassicalSharp.Entities {
|
||||
blockBB.Min.Z = Math.Max(blockBB.Min.Z, blockBB.Max.Z - size.Z / 2);
|
||||
blockBB.Max.Z = Math.Min(blockBB.Max.Z, blockZMin + size.Z / 2);
|
||||
|
||||
AABB adjBB = finalBB;
|
||||
AABB adjBB;
|
||||
adjBB.Min.X = Math.Min(finalBB.Min.X, blockBB.Min.X + Adjustment);
|
||||
adjBB.Max.X = Math.Max(finalBB.Max.X, blockBB.Max.X - Adjustment);
|
||||
adjBB.Min.Y = blockBB.Max.Y + Adjustment;
|
||||
@ -181,11 +172,11 @@ namespace ClassicalSharp.Entities {
|
||||
adjBB.Min.Z = Math.Min(finalBB.Min.Z, blockBB.Min.Z + Adjustment);
|
||||
adjBB.Max.Z = Math.Max(finalBB.Max.Z, blockBB.Max.Z - Adjustment);
|
||||
|
||||
if (!CanSlideThrough(ref adjBB))
|
||||
return false;
|
||||
if (!CanSlideThrough(ref adjBB)) return false;
|
||||
|
||||
entity.Position.Y = blockBB.Max.Y + Adjustment;
|
||||
entity.onGround = true;
|
||||
ClipY(ref size, ref entityBB, ref entityExtentBB);
|
||||
ClipY(ref size, ref entityBB, ref extentBB);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -194,40 +185,38 @@ namespace ClassicalSharp.Entities {
|
||||
bool CanSlideThrough(ref AABB adjFinalBB) {
|
||||
Vector3I bbMin = Vector3I.Floor(adjFinalBB.Min);
|
||||
Vector3I bbMax = Vector3I.Floor(adjFinalBB.Max);
|
||||
AABB blockBB;
|
||||
|
||||
for (int y = bbMin.Y; y <= bbMax.Y; y++)
|
||||
for (int z = bbMin.Z; z <= bbMax.Z; z++)
|
||||
for (int x = bbMin.X; x <= bbMax.X; x++)
|
||||
{
|
||||
BlockID block = game.World.GetPhysicsBlock(x, y, z);
|
||||
Vector3 min = new Vector3(x, y, z) + BlockInfo.MinBB[block];
|
||||
Vector3 max = new Vector3(x, y, z) + BlockInfo.MaxBB[block];
|
||||
blockBB.Min = new Vector3(x, y, z) + BlockInfo.MinBB[block];
|
||||
blockBB.Max = new Vector3(x, y, z) + BlockInfo.MaxBB[block];
|
||||
|
||||
AABB blockBB = new AABB(min, max);
|
||||
if (!blockBB.Intersects(adjFinalBB))
|
||||
continue;
|
||||
if (BlockInfo.Collide[block] == CollideType.Solid)
|
||||
return false;
|
||||
if (!blockBB.Intersects(adjFinalBB)) continue;
|
||||
if (BlockInfo.Collide[block] == CollideType.Solid) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ClipX(ref Vector3 size, ref AABB entityBB, ref AABB entityExtentBB) {
|
||||
void ClipX(ref Vector3 size, ref AABB entityBB, ref AABB extentBB) {
|
||||
entity.Velocity.X = 0;
|
||||
entityBB.Min.X = entity.Position.X - size.X / 2; entityExtentBB.Min.X = entityBB.Min.X;
|
||||
entityBB.Max.X = entity.Position.X + size.X / 2; entityExtentBB.Max.X = entityBB.Max.X;
|
||||
entityBB.Min.X = entity.Position.X - size.X / 2; extentBB.Min.X = entityBB.Min.X;
|
||||
entityBB.Max.X = entity.Position.X + size.X / 2; extentBB.Max.X = entityBB.Max.X;
|
||||
}
|
||||
|
||||
void ClipY(ref Vector3 size, ref AABB entityBB, ref AABB entityExtentBB) {
|
||||
void ClipY(ref Vector3 size, ref AABB entityBB, ref AABB extentBB) {
|
||||
entity.Velocity.Y = 0;
|
||||
entityBB.Min.Y = entity.Position.Y; entityExtentBB.Min.Y = entityBB.Min.Y;
|
||||
entityBB.Max.Y = entity.Position.Y + size.Y; entityExtentBB.Max.Y = entityBB.Max.Y;
|
||||
entityBB.Min.Y = entity.Position.Y; extentBB.Min.Y = entityBB.Min.Y;
|
||||
entityBB.Max.Y = entity.Position.Y + size.Y; extentBB.Max.Y = entityBB.Max.Y;
|
||||
}
|
||||
|
||||
void ClipZ(ref Vector3 size, ref AABB entityBB, ref AABB entityExtentBB) {
|
||||
void ClipZ(ref Vector3 size, ref AABB entityBB, ref AABB extentBB) {
|
||||
entity.Velocity.Z = 0;
|
||||
entityBB.Min.Z = entity.Position.Z - size.Z / 2; entityExtentBB.Min.Z = entityBB.Min.Z;
|
||||
entityBB.Max.Z = entity.Position.Z + size.Z / 2; entityExtentBB.Max.Z = entityBB.Max.Z;
|
||||
entityBB.Min.Z = entity.Position.Z - size.Z / 2; extentBB.Min.Z = entityBB.Min.Z;
|
||||
entityBB.Max.Z = entity.Position.Z + size.Z / 2; extentBB.Max.Z = entityBB.Max.Z;
|
||||
}
|
||||
}
|
||||
}
|
@ -7,25 +7,7 @@ using BlockID = System.UInt16;
|
||||
|
||||
namespace ClassicalSharp.Physics {
|
||||
|
||||
public struct State {
|
||||
public int X, Y, Z;
|
||||
public float tSquared;
|
||||
|
||||
public State(int x, int y, int z, BlockID block, float tSquared) {
|
||||
#if !ONLY_8BIT
|
||||
X = x << 3; Y = y << 4; Z = z << 3;
|
||||
X |= (block & 0x007);
|
||||
Y |= (block & 0x078) >> 3;
|
||||
Z |= (block & 0x380) >> 7;
|
||||
#else
|
||||
X = x << 3; Y = y << 3; Z = z << 3;
|
||||
X |= (block & 0x007);
|
||||
Y |= (block & 0x038) >> 3;
|
||||
Z |= (block & 0x1C0) >> 6;
|
||||
#endif
|
||||
this.tSquared = tSquared;
|
||||
}
|
||||
}
|
||||
public struct State { public int X, Y, Z; public float tSquared; }
|
||||
|
||||
/// <summary> Calculates all possible blocks that a moving entity can intersect with. </summary>
|
||||
public sealed class Searcher {
|
||||
@ -52,9 +34,10 @@ namespace ClassicalSharp.Physics {
|
||||
int elements = (max.X + 1 - min.X) * (max.Y + 1 - min.Y) * (max.Z + 1 - min.Z);
|
||||
if (elements > stateCache.Length) {
|
||||
stateCache = new State[elements];
|
||||
}
|
||||
}
|
||||
|
||||
AABB blockBB = default(AABB);
|
||||
AABB blockBB;
|
||||
State state;
|
||||
int count = 0;
|
||||
|
||||
// Order loops so that we minimise cache misses
|
||||
@ -72,11 +55,22 @@ namespace ClassicalSharp.Physics {
|
||||
|
||||
if (!entityExtentBB.Intersects(blockBB)) continue; // necessary for non whole blocks. (slabs)
|
||||
|
||||
float tx = 0, ty = 0, tz = 0;
|
||||
float tx, ty, tz;
|
||||
CalcTime(ref vel, ref entityBB, ref blockBB, out tx, out ty, out tz);
|
||||
if (tx > 1 || ty > 1 || tz > 1) continue;
|
||||
float tSquared = tx * tx + ty * ty + tz * tz;
|
||||
stateCache[count++] = new State(x, y, z, block, tSquared);
|
||||
|
||||
#if !ONLY_8BIT
|
||||
state.X = (x << 3) | (block & 0x007);
|
||||
state.Y = (y << 4) | ((block & 0x078) >> 3);
|
||||
state.Z = (z << 3) | ((block & 0x380) >> 7);
|
||||
#else
|
||||
state.X = (x << 3) | (block & 0x007);
|
||||
state.Y = (y << 3) | ((block & 0x038) >> 3);
|
||||
state.Z = (z << 3) | ((block & 0x1C0) >> 6);
|
||||
#endif
|
||||
state.tSquared = tx * tx + ty * ty + tz * tz;
|
||||
|
||||
stateCache[count++] = state;
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
|
@ -15,6 +15,10 @@
|
||||
#include "Physics.h"
|
||||
#include "IModel.h"
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*----------------------------------------------------AnimatedComponent----------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
#define ANIM_MAX_ANGLE (110 * MATH_DEG2RAD)
|
||||
#define ANIM_ARM_MAX (60.0f * MATH_DEG2RAD)
|
||||
#define ANIM_LEG_MAX (80.0f * MATH_DEG2RAD)
|
||||
@ -107,6 +111,9 @@ void AnimatedComp_GetCurrent(AnimatedComp* anim, Real32 t, bool calcHumanAnims)
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*------------------------------------------------------TiltComponent------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
void TiltComp_Init(TiltComp* anim) {
|
||||
anim->TiltX = 0.0f; anim->TiltY = 0.0f; anim->VelTiltStrength = 1.0f;
|
||||
anim->VelTiltStrengthO = 1.0f; anim->VelTiltStrengthN = 1.0f;
|
||||
@ -133,6 +140,9 @@ void TiltComp_GetCurrent(TiltComp* anim, Real32 t) {
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-----------------------------------------------------HacksComponent------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
void HacksComp_SetAll(HacksComp* hacks, bool allowed) {
|
||||
hacks->CanAnyHacks = allowed; hacks->CanFly = allowed;
|
||||
hacks->CanNoclip = allowed; hacks->CanRespawn = allowed;
|
||||
@ -282,6 +292,9 @@ void HacksComp_UpdateState(HacksComp* hacks) {
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*--------------------------------------------------InterpolationComponent-------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
void InterpComp_RemoveOldestRotY(InterpComp* interp) {
|
||||
Int32 i;
|
||||
for (i = 0; i < Array_Elems(interp->RotYStates); i++) {
|
||||
@ -323,6 +336,10 @@ void InterpComp_SetPos(InterpState* state, LocationUpdate* update) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*----------------------------------------------NetworkInterpolationComponent----------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
Real32 NetInterpComp_Next(Real32 next, Real32 cur) {
|
||||
if (next == MATH_POS_INF) return cur;
|
||||
return next;
|
||||
@ -386,6 +403,10 @@ void NetInterpComp_AdvanceState(NetInterpComp* interp) {
|
||||
InterpComp_AdvanceRotY(&interp->Base);
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-----------------------------------------------LocalInterpolationComponent-----------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
Real32 LocalInterpComp_Next(Real32 next, Real32 cur, Real32* last, bool interpolate) {
|
||||
if (next == MATH_POS_INF) return cur;
|
||||
if (!interpolate) *last = next;
|
||||
@ -440,6 +461,9 @@ void LocalInterpComp_AdvanceState(InterpComp* interp) {
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-----------------------------------------------------ShadowComponent-----------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
Real32 ShadowComponent_radius = 7.0f;
|
||||
typedef struct ShadowData_ { Real32 Y; BlockID Block; UInt8 A; } ShadowData;
|
||||
|
||||
@ -638,4 +662,208 @@ void ShadowComponent_Draw(Entity* entity) {
|
||||
|
||||
UInt32 vCount = (UInt32)(ptr - vertices) / (UInt32)sizeof(VertexP3fT2fC4b);
|
||||
GfxCommon_UpdateDynamicVb_IndexedTris(vb, vertices, vCount);
|
||||
}
|
||||
|
||||
|
||||
typedef struct CollisionsComponent_ {
|
||||
Entity* Entity;
|
||||
bool HitXMin, HitYMin, HitZMin, HitXMax, HitYMax, HitZMax, WasOn;
|
||||
} CollisionsComponent;
|
||||
|
||||
/* Whether a collision occurred with any horizontal sides of any blocks */
|
||||
bool Collisions_HitHorizontal(CollisionsComponent* comp) {
|
||||
return comp->HitXMin || comp->HitXMax || comp->HitZMin || comp->HitZMax;
|
||||
}
|
||||
|
||||
|
||||
/* TODO: test for corner cases, and refactor this */
|
||||
void Collisions_MoveAndWallSlide(CollisionsComponent* comp) {
|
||||
Vector3 zero = Vector3_Zero;
|
||||
Entity* entity = comp->Entity;
|
||||
if (Vector3_Equals(&entity->Velocity, &zero)) return;
|
||||
|
||||
AABB entityBB, entityExtentBB;
|
||||
UInt32 count = Searcher_FindReachableBlocks(entity, &entityBB, &entityExtentBB);
|
||||
CollideWithReachableBlocks(comp, count, &entityBB, &entityExtentBB);
|
||||
}
|
||||
|
||||
void Collisions_CollideWithReachableBlocks(CollisionsComponent* comp, UInt32 count, AABB* entityBB, AABB* extentBB) {
|
||||
Entity* entity = comp->Entity;
|
||||
/* Reset collision detection states */
|
||||
bool wasOn = entity->OnGround;
|
||||
entity->OnGround = false;
|
||||
comp->HitXMin = false; comp->HitYMin = false; comp->HitZMin = false;
|
||||
comp->HitXMax = false; comp->HitYMax = false; comp->HitZMax = false;
|
||||
|
||||
AABB blockBB;
|
||||
Vector3 bPos, size = entity->Size;
|
||||
UInt32 i;
|
||||
for (i = 0; i < count; i++) {
|
||||
/* Unpack the block and coordinate data */
|
||||
SearcherState state = Searcher_States[i];
|
||||
bPos.X = state.X >> 3; bPos.Y = state.Y >> 3; bPos.Z = state.Z >> 3;
|
||||
Int32 block = (state.X & 0x7) | (state.Y & 0x7) << 3 | (state.Z & 0x7) << 6;
|
||||
|
||||
Vector3_Add(&blockBB.Min, &Block_MinBB[block], &bPos);
|
||||
Vector3_Add(&blockBB.Max, &Block_MaxBB[block], &bPos);
|
||||
if (!AABB_Intersects(extentBB, &blockBB)) continue;
|
||||
|
||||
/* Recheck time to collide with block (as colliding with blocks modifies this) */
|
||||
Real32 tx, ty, tz;
|
||||
Searcher_CalcTime(&entity->Velocity, entityBB, &blockBB, &tx, &ty, &tz);
|
||||
if (tx > 1.0f || ty > 1.0f || tz > 1.0f) {
|
||||
Utils.LogDebug("t > 1 in physics calculation.. this shouldn't have happened.");
|
||||
}
|
||||
|
||||
/* Calculate the location of the entity when it collides with this block */
|
||||
Vector3 v = entity->Velocity;
|
||||
v.X *= tx; v.Y *= ty; v.Z *= tz;
|
||||
AABB finalBB; /* Inlined ABBB_Offset */
|
||||
Vector3_Add(&finalBB.Min, &entityBB->Min, &v);
|
||||
Vector3_Add(&finalBB.Min, &entityBB->Max, &v);
|
||||
|
||||
// if we have hit the bottom of a block, we need to change the axis we test first.
|
||||
if (!hitYMin) {
|
||||
if (finalBB.Min.Y + Adjustment >= blockBB.Max.Y) {
|
||||
ClipYMax(&blockBB, entityBB, extentBB, size);
|
||||
} else if (finalBB.Max.Y - Adjustment <= blockBB.Min.Y) {
|
||||
ClipYMin(&blockBB, entityBB, extentBB, size);
|
||||
} else if (finalBB.Min.X + Adjustment >= blockBB.Max.X) {
|
||||
ClipXMax(&blockBB, entityBB, wasOn, finalBB, extentBB, size);
|
||||
} else if (finalBB.Max.X - Adjustment <= blockBB.Min.X) {
|
||||
ClipXMin(&blockBB, entityBB, wasOn, finalBB, extentBB, size);
|
||||
} else if (finalBB.Min.Z + Adjustment >= blockBB.Max.Z) {
|
||||
ClipZMax(&blockBB, entityBB, wasOn, finalBB, extentBB, size);
|
||||
} else if (finalBB.Max.Z - Adjustment <= blockBB.Min.Z) {
|
||||
ClipZMin(&blockBB, entityBB, wasOn, finalBB, extentBB, size);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// if flying or falling, test the horizontal axes first.
|
||||
if (finalBB.Min.X + Adjustment >= blockBB.Max.X) {
|
||||
ClipXMax(&blockBB, entityBB, wasOn, finalBB, extentBB, size);
|
||||
} else if (finalBB.Max.X - Adjustment <= blockBB.Min.X) {
|
||||
ClipXMin(&blockBB, entityBB, wasOn, finalBB, extentBB, size);
|
||||
} else if (finalBB.Min.Z + Adjustment >= blockBB.Max.Z) {
|
||||
ClipZMax(&blockBB, entityBB, wasOn, finalBB, extentBB, size);
|
||||
} else if (finalBB.Max.Z - Adjustment <= blockBB.Min.Z) {
|
||||
ClipZMin(&blockBB, entityBB, wasOn, finalBB, extentBB, size);
|
||||
} else if (finalBB.Min.Y + Adjustment >= blockBB.Max.Y) {
|
||||
ClipYMax(&blockBB, entityBB, extentBB, size);
|
||||
} else if (finalBB.Max.Y - Adjustment <= blockBB.Min.Y) {
|
||||
ClipYMin(&blockBB, entityBB, extentBB, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Collisions_ClipXMin(AABB* blockBB, AABB* entityBB, bool wasOn, AABB* finalBB, AABB* extentBB, Vector3* size) {
|
||||
if (!wasOn || !DidSlide(blockBB, size, finalBB, entityBB, extentBB)) {
|
||||
entity.Position.X = blockBB.Min.X - size.X / 2 - Adjustment;
|
||||
ClipX(size, entityBB, extentBB);
|
||||
hitXMin = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Collisions_ClipXMax(AABB* blockBB, AABB* entityBB, bool wasOn, AABB* finalBB, AABB* extentBB, Vector3* size) {
|
||||
if (!wasOn || !DidSlide(blockBB, size, finalBB, entityBB, extentBB)) {
|
||||
entity.Position.X = blockBB.Max.X + size.X / 2 + Adjustment;
|
||||
ClipX(size, entityBB, extentBB);
|
||||
hitXMax = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Collisions_ClipZMax(AABB* blockBB, AABB* entityBB, bool wasOn, AABB* finalBB, AABB* extentBB, Vector3* size) {
|
||||
if (!wasOn || !DidSlide(blockBB, size, finalBB, entityBB, extentBB)) {
|
||||
entity.Position.Z = blockBB.Max.Z + size.Z / 2 + Adjustment;
|
||||
ClipZ(size, entityBB, extentBB);
|
||||
hitZMax = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Collisions_ClipZMin(AABB* blockBB, AABB* entityBB, bool wasOn, AABB* finalBB, AABB* extentBB, Vector3* size) {
|
||||
if (!wasOn || !DidSlide(blockBB, size, finalBB, entityBB, extentBB)) {
|
||||
entity.Position.Z = blockBB.Min.Z - size.Z / 2 - Adjustment;
|
||||
ClipZ(size, entityBB, extentBB);
|
||||
hitZMin = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Collisions_ClipYMin(AABB* blockBB, AABB* entityBB, AABB* extentBB, Vector3* size) {
|
||||
entity.Position.Y = blockBB.Min.Y - size.Y - Adjustment;
|
||||
ClipY(size, entityBB, ref extentBB);
|
||||
hitYMin = true;
|
||||
}
|
||||
|
||||
void Collisions_ClipYMax(AABB* blockBB, AABB* entityBB, AABB* extentBB, Vector3* size) {
|
||||
entity.Position.Y = blockBB.Max.Y + Adjustment;
|
||||
entity.onGround = true;
|
||||
ClipY(size, entityBB, ref extentBB);
|
||||
hitYMax = true;
|
||||
}
|
||||
|
||||
bool Collisions_DidSlide(AABB blockBB, Vector3* size, AABB* finalBB, AABB* entityBB, AABB* extentBB) {
|
||||
Real32 yDist = blockBB.Max.Y - entityBB.Min.Y;
|
||||
if (yDist > 0 && yDist <= entity.StepSize + 0.01f) {
|
||||
float blockXMin = blockBB.Min.X, blockZMin = blockBB.Min.Z;
|
||||
blockBB.Min.X = Math.Max(blockBB.Min.X, blockBB.Max.X - size.X / 2);
|
||||
blockBB.Max.X = Math.Min(blockBB.Max.X, blockXMin + size.X / 2);
|
||||
blockBB.Min.Z = Math.Max(blockBB.Min.Z, blockBB.Max.Z - size.Z / 2);
|
||||
blockBB.Max.Z = Math.Min(blockBB.Max.Z, blockZMin + size.Z / 2);
|
||||
|
||||
AABB adjBB;
|
||||
adjBB.Min.X = min(finalBB->Min.X, blockBB.Min.X + Adjustment);
|
||||
adjBB.Max.X = max(finalBB->Max.X, blockBB.Max.X - Adjustment);
|
||||
adjBB.Min.Y = blockBB.Max.Y + Adjustment;
|
||||
adjBB.Max.Y = adjBB.Min.Y + size->Y;
|
||||
adjBB.Min.Z = min(finalBB->Min.Z, blockBB.Min.Z + Adjustment);
|
||||
adjBB.Max.Z = max(finalBB->Max.Z, blockBB.Max.Z - Adjustment);
|
||||
|
||||
if (!Collisions_CanSlideThrough(&adjBB)) return false;
|
||||
|
||||
entity.Position.Y = blockBB.Max.Y + Adjustment;
|
||||
entity.onGround = true;
|
||||
ClipY(size, entityBB, extentBB);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Collisions_CanSlideThrough(AABB* adjFinalBB) {
|
||||
Vector3I bbMin; Vector3I_Floor(&bbMin, &adjFinalBB->Min);
|
||||
Vector3I bbMax; Vector3I_Floor(&bbMax, &adjFinalBB->Max);
|
||||
AABB blockBB;
|
||||
Int32 x, y, z;
|
||||
|
||||
for (y = bbMin.Y; y <= bbMax.Y; y++) {
|
||||
for (z = bbMin.Z; z <= bbMax.Z; z++) {
|
||||
for (x = bbMin.X; x <= bbMax.X; x++) {
|
||||
BlockID block = World_GetPhysicsBlock(x, y, z);
|
||||
blockBB.Min = new Vector3(x, y, z) + Block_MinBB[block];
|
||||
blockBB.Max = new Vector3(x, y, z) + Block_MaxBB[block];
|
||||
|
||||
if (!AABB_Intersects(&blockBB, adjFinalBB)) continue;
|
||||
if (Block_Collide[block] == COLLIDE_SOLID) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Collisions_ClipX(Entity* entity, Vector3* size, AABB* entityBB, AABB* extentBB) {
|
||||
entity->Velocity.X = 0.0f;
|
||||
entityBB->Min.X = entity->Position.X - size->X / 2; extentBB->Min.X = entityBB->Min.X;
|
||||
entityBB->Max.X = entity->Position.X + size->X / 2; extentBB->Max.X = entityBB->Max.X;
|
||||
}
|
||||
|
||||
void Collisions_ClipY(Entity* entity, Vector3* size, AABB* entityBB, AABB* extentBB) {
|
||||
entity->Velocity.Y = 0.0f;
|
||||
entityBB->Min.Y = entity->Position.Y; extentBB->Min.Y = entityBB->Min.Y;
|
||||
entityBB->Max.Y = entity->Position.Y + size->Y; extentBB->Max.Y = entityBB->Max.Y;
|
||||
}
|
||||
|
||||
void Collisions_ClipZ(Entity* entity, Vector3* size, AABB* entityBB, AABB* extentBB) {
|
||||
entity->Velocity.Z = 0.0f;
|
||||
entityBB->Min.Z = entity->Position.Z - size->Z / 2; extentBB->Min.Z = entityBB->Min.Z;
|
||||
entityBB->Max.Z = entity->Position.Z + size->Z / 2; extentBB->Max.Z = entityBB->Max.Z;
|
||||
}
|
@ -123,14 +123,6 @@ bool Intersection_RayIntersectsBox(Vector3 origin, Vector3 dir, Vector3 min, Vec
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SearcherState_Init(SearcherState* state, Int32 x, Int32 y, Int32 z, BlockID block, Real32 tSquared) {
|
||||
state->X = (x << 3) | (block & 0x07);
|
||||
state->Y = (y << 3) | (block & 0x38) >> 3;
|
||||
state->Z = (z << 3) | (block & 0xC0) >> 6;
|
||||
state->tSquared = tSquared;
|
||||
}
|
||||
|
||||
#define SEARCHER_STATES_MIN 64
|
||||
SearcherState Searcher_StatesInitial[SEARCHER_STATES_MIN];
|
||||
extern SearcherState* Searcher_States = Searcher_StatesInitial;
|
||||
@ -206,9 +198,11 @@ UInt32 Searcher_FindReachableBlocks(Entity* entity, AABB* entityBB, AABB* entity
|
||||
Real32 tx, ty, tz;
|
||||
Searcher_CalcTime(&vel, entityBB, &blockBB, &tx, &ty, &tz);
|
||||
if (tx > 1.0f || ty > 1.0f || tz > 1.0f) continue;
|
||||
Real32 tSquared = tx * tx + ty * ty + tz * tz;
|
||||
|
||||
SearcherState_Init(curState, x, y, z, block, tSquared);
|
||||
curState->X = (x << 3) | (block & 0x07);
|
||||
curState->Y = (y << 3) | ((block & 0x38) >> 3);
|
||||
curState->Z = (z << 3) | ((block & 0xC0) >> 6);
|
||||
curState->tSquared = tx * tx + ty * ty + tz * tz;
|
||||
curState++;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user