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 ) { public bool ZIntersects( BoundingBox box ) {
return Max.Z >= box.Min.Z && Min.Z <= box.Max.Z; 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; 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. // TODO: test for corner cases, and refactor this.
static State[] stateCache = new State[0]; static State[] stateCache = new State[0];
class StateComparer : IComparer<State> { class StateComparer : IComparer<State> {
@ -139,22 +130,22 @@ namespace ClassicalSharp {
ClipY( ref size, ref entityBB, ref entityExtentBB ); ClipY( ref size, ref entityBB, ref entityExtentBB );
} else { } else {
if( finalBB.Min.X >= blockBB.Max.X ) { 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; Position.X = blockBB.Max.X + size.X / 2 + 0.001f;
ClipX( ref size, ref entityBB, ref entityExtentBB ); ClipX( ref size, ref entityBB, ref entityExtentBB );
} }
} else if( finalBB.Max.X <= blockBB.Min.X ) { } 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; Position.X = blockBB.Min.X - size.X / 2 - 0.001f;
ClipX( ref size, ref entityBB, ref entityExtentBB ); ClipX( ref size, ref entityBB, ref entityExtentBB );
} }
} else if( finalBB.Min.Z >= blockBB.Max.Z ) { } 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; Position.Z = blockBB.Max.Z + size.Z / 2 + 0.001f;
ClipZ( ref size, ref entityBB, ref entityExtentBB ); ClipZ( ref size, ref entityBB, ref entityExtentBB );
} }
} else if( finalBB.Max.Z <= blockBB.Min.Z ) { } 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; Position.Z = blockBB.Min.Z - size.Z / 2 - 0.001f;
ClipZ( ref size, ref entityBB, ref entityExtentBB ); 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 ) { ref BoundingBox entityBB, ref BoundingBox entityExtentBB ) {
float yDist = blockBB.Max.Y - entityBB.Min.Y; float yDist = blockBB.Max.Y - entityBB.Min.Y;
Vector3 blockOffsetMin = blockBB.Min + new Vector3( x, 0, z ); if( yDist > 0 && yDist <= StepSize + 0.01f ) {
if( yDist > 0 && yDist <= StepSize + 0.01f && wasOnGround &&
IsFreeYForStep( blockBB.Min ) && IsFreeYForStep( blockOffsetMin ) ) { // 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; Position.Y = blockBB.Max.Y + 0.001f;
onGround = true; onGround = true;
ClipY( ref size, ref entityBB, ref entityExtentBB ); ClipY( ref size, ref entityBB, ref entityExtentBB );