Improve slab collision detection, should fix #65.

This commit is contained in:
UnknownShadow200 2015-09-15 06:27:52 +10:00
parent 4facc54b47
commit 13c456c7c5
2 changed files with 36 additions and 22 deletions

View File

@ -48,5 +48,9 @@ namespace ClassicalSharp {
public bool ZIntersects( BoundingBox box ) {
return Max.Z >= box.Min.Z && Min.Z <= box.Max.Z;
}
public override string ToString() {
return Min + " : " + Max;
}
}
}

View File

@ -41,15 +41,6 @@ namespace ClassicalSharp {
return block == 0 || info.IsSprite( block ) || info.IsLiquid( block ) || block == (byte)Block.Snow;
}
bool IsFreeYForStep( Vector3 pos ) {
// NOTE: if non whole blocks are added, use a proper AABB test.
int x = Utils.Floor( pos.X );
int y = Utils.Floor( pos.Y );
int z = Utils.Floor( pos.Z );
return CanWalkThrough( GetPhysicsBlockId( x, y + 1, z ) ) &&
CanWalkThrough( GetPhysicsBlockId( x, y + 2, z ) );
}
// TODO: test for corner cases, and refactor this.
static State[] stateCache = new State[0];
class StateComparer : IComparer<State> {
@ -139,22 +130,22 @@ namespace ClassicalSharp {
ClipY( ref size, ref entityBB, ref entityExtentBB );
} else {
if( finalBB.Min.X >= blockBB.Max.X ) {
if( !DidSlide( ref blockBB, ref size, wasOn, 1, 0, ref entityBB, ref entityExtentBB ) ) {
if( !wasOn || !DidSlide( ref blockBB, ref size, ref finalBB, ref entityBB, ref entityExtentBB ) ) {
Position.X = blockBB.Max.X + size.X / 2 + 0.001f;
ClipX( ref size, ref entityBB, ref entityExtentBB );
}
} else if( finalBB.Max.X <= blockBB.Min.X ) {
if( !DidSlide( ref blockBB, ref size, wasOn, -1, 0, ref entityBB, ref entityExtentBB ) ) {
if( !wasOn || !DidSlide( ref blockBB, ref size, ref finalBB, ref entityBB, ref entityExtentBB ) ) {
Position.X = blockBB.Min.X - size.X / 2 - 0.001f;
ClipX( ref size, ref entityBB, ref entityExtentBB );
}
} else if( finalBB.Min.Z >= blockBB.Max.Z ) {
if( !DidSlide( ref blockBB, ref size, wasOn, 0, 1, ref entityBB, ref entityExtentBB ) ) {
if( !wasOn || !DidSlide( ref blockBB, ref size, ref finalBB, ref entityBB, ref entityExtentBB ) ) {
Position.Z = blockBB.Max.Z + size.Z / 2 + 0.001f;
ClipZ( ref size, ref entityBB, ref entityExtentBB );
}
} else if( finalBB.Max.Z <= blockBB.Min.Z ) {
if( !DidSlide( ref blockBB, ref size, wasOn, 0, -1, ref entityBB, ref entityExtentBB ) ) {
if( !wasOn || !DidSlide( ref blockBB, ref size, ref finalBB, ref entityBB, ref entityExtentBB ) ) {
Position.Z = blockBB.Min.Z - size.Z / 2 - 0.001f;
ClipZ( ref size, ref entityBB, ref entityExtentBB );
}
@ -163,12 +154,31 @@ namespace ClassicalSharp {
}
}
bool DidSlide( ref BoundingBox blockBB, ref Vector3 size, bool wasOnGround, float x, float z,
bool DidSlide( ref BoundingBox blockBB, ref Vector3 size, ref BoundingBox finalBB,
ref BoundingBox entityBB, ref BoundingBox entityExtentBB ) {
float yDist = blockBB.Max.Y - entityBB.Min.Y;
Vector3 blockOffsetMin = blockBB.Min + new Vector3( x, 0, z );
if( yDist > 0 && yDist <= StepSize + 0.01f && wasOnGround &&
IsFreeYForStep( blockBB.Min ) && IsFreeYForStep( blockOffsetMin ) ) {
if( yDist > 0 && yDist <= StepSize + 0.01f ) {
// Adjust entity bounding box to include the block being tested
BoundingBox adjFinalBB = finalBB;
adjFinalBB.Min.X = Math.Min( finalBB.Min.X, blockBB.Min.X + 0.01f );
adjFinalBB.Max.X = Math.Max( finalBB.Max.X, blockBB.Max.X - 0.01f );
adjFinalBB.Min.Y = (float)Math.Ceiling( blockBB.Max.Y ) + 0.01f;
adjFinalBB.Max.Y = adjFinalBB.Min.Y + size.Y;
adjFinalBB.Min.Z = Math.Min( finalBB.Min.Z, blockBB.Min.Z + 0.01f );
adjFinalBB.Max.Z = Math.Max( finalBB.Max.Z, blockBB.Max.Z - 0.01f );
Vector3I min = Vector3I.Floor( adjFinalBB.Min );
Vector3I max = Vector3I.Floor( adjFinalBB.Max );
for( int x = min.X; x <= max.X; x++ ) {
for( int y = min.Y; y <= max.Y; y++ ) {
for( int z = min.Z; z <= max.Z; z++ ) {
if( !CanWalkThrough( GetPhysicsBlockId( x, y, z ) ) )
return false;
}
}
}
Position.Y = blockBB.Max.Y + 0.001f;
onGround = true;
ClipY( ref size, ref entityBB, ref entityExtentBB );