From 13c456c7c5830cfe01c9e849585e3dd77f6a2de8 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Tue, 15 Sep 2015 06:27:52 +1000 Subject: [PATCH] Improve slab collision detection, should fix #65. --- ClassicalSharp/Physics/BoundingBox.cs | 4 ++ ClassicalSharp/Physics/Entity.Physics.cs | 54 ++++++++++++++---------- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/ClassicalSharp/Physics/BoundingBox.cs b/ClassicalSharp/Physics/BoundingBox.cs index d2bf156e3..c4569f62c 100644 --- a/ClassicalSharp/Physics/BoundingBox.cs +++ b/ClassicalSharp/Physics/BoundingBox.cs @@ -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; + } } } \ No newline at end of file diff --git a/ClassicalSharp/Physics/Entity.Physics.cs b/ClassicalSharp/Physics/Entity.Physics.cs index c29d01464..1e2dd347e 100644 --- a/ClassicalSharp/Physics/Entity.Physics.cs +++ b/ClassicalSharp/Physics/Entity.Physics.cs @@ -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 { @@ -59,8 +50,8 @@ namespace ClassicalSharp { } static StateComparer comparer = new StateComparer(); protected void MoveAndWallSlide() { - if( Velocity == Vector3.Zero ) - return; + if( Velocity == Vector3.Zero ) + return; Vector3 size = CollisionSize; BoundingBox entityBB, entityExtentBB; int count = 0; @@ -68,7 +59,7 @@ namespace ClassicalSharp { CollideWithReachableBlocks( count, ref size, ref entityBB, ref entityExtentBB ); } - void FindReachableBlocks( ref int count, ref Vector3 size, + void FindReachableBlocks( ref int count, ref Vector3 size, out BoundingBox entityBB, out BoundingBox entityExtentBB ) { Vector3 vel = Velocity; Vector3 pos = Position; @@ -112,7 +103,7 @@ namespace ClassicalSharp { } } - void CollideWithReachableBlocks( int count, ref Vector3 size, + void CollideWithReachableBlocks( int count, ref Vector3 size, ref BoundingBox entityBB, ref BoundingBox entityExtentBB ) { bool wasOn = onGround; onGround = false; @@ -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 ); @@ -187,7 +197,7 @@ namespace ClassicalSharp { Velocity.Y = 0; entityBB.Min.Y = entityExtentBB.Min.Y = Position.Y; entityBB.Max.Y = entityExtentBB.Max.Y = Position.Y + size.Y; - } + } void ClipZ( ref Vector3 size, ref BoundingBox entityBB, ref BoundingBox entityExtentBB ) { Velocity.Z = 0;