using System; using Microsoft.Xna.Framework; using Xunit; namespace MonoGame.Extended.Collisions.Tests { /// /// Test collision of actors with various shapes. /// /// /// Uses the fact that moves itself away from /// on collision. /// public class CollisionComponentTests { private CollisionComponent collisionComponent; private GameTime _gameTime = new GameTime(TimeSpan.Zero, TimeSpan.FromMilliseconds(16)); public CollisionComponentTests() { collisionComponent = new CollisionComponent(new RectangleF(Point2.Zero, new Point2(10, 10))); } #region Circle Circle [Fact] public void PenetrationVectorSameCircleTest() { Point2 pos1 = Point2.Zero; Point2 pos2 = Point2.Zero; IShapeF shape1 = new CircleF(pos1, 2.0f); IShapeF shape2 = new CircleF(pos2, 2.0f); var actor1 = new BasicActor() { Position = pos1, Bounds = shape1 }; var actor2 = new BasicWall() { Position = pos2, Bounds = shape2 }; Assert.True(shape1.Intersects(shape2)); collisionComponent.Insert(actor1); collisionComponent.Insert(actor2); collisionComponent.Update(_gameTime); Assert.True(Math.Abs(actor1.Position.Y - -4f) < float.Epsilon); } [Fact] public void PenetrationVectorSlightlyOverlappingCircleTest() { Point2 pos1 = new Point2(0, 1.5f); Point2 pos2 = Point2.Zero; IShapeF shape1 = new CircleF(pos1, 2.0f); IShapeF shape2 = new CircleF(pos2, 2.0f); var actor1 = new BasicActor() { Position = pos1, Bounds = shape1 }; var actor2 = new BasicWall() { Position = pos2, Bounds = shape2 }; Assert.True(shape1.Intersects(shape2)); collisionComponent.Insert(actor1); collisionComponent.Insert(actor2); collisionComponent.Update(_gameTime); // Actor should have moved up because the distance is shorter. Assert.True(actor1.Position.Y > actor2.Position.Y); // The circle centers should be about 4 units away after moving Assert.True(Math.Abs(actor1.Position.Y - 4.0f) < float.Epsilon); } [Fact] public void PenetrationVectorSlightlyOverlappingOffAxisTest() { Point2 pos1 = new Point2(2, 2.5f); Point2 pos2 = new Point2(2, 1); IShapeF shape1 = new CircleF(pos1, 2.0f); IShapeF shape2 = new CircleF(pos2, 2.0f); var actor1 = new BasicActor() { Position = pos1, Bounds = shape1 }; var actor2 = new BasicWall() { Position = pos2, Bounds = shape2 }; Assert.True(shape1.Intersects(shape2)); collisionComponent.Insert(actor1); collisionComponent.Insert(actor2); collisionComponent.Update(_gameTime); // Actor should have moved up because the distance is shorter. Assert.True(actor1.Position.Y > actor2.Position.Y); // The circle centers should be about 4 units away after moving Assert.True(Math.Abs(actor1.Position.Y - 5.0f) < float.Epsilon); Assert.True(Math.Abs(actor1.Position.X - 2.0f) < float.Epsilon); } [Fact] public void PenetrationZeroRadiusCircleCircleTest() { Point2 pos1 = new Point2(0, 1.5f); Point2 pos2 = Point2.Zero; IShapeF shape1 = new CircleF(pos1, 0); IShapeF shape2 = new CircleF(pos2, 2.0f); var actor1 = new BasicActor() { Position = pos1, Bounds = shape1 }; var actor2 = new BasicWall() { Position = pos2, Bounds = shape2 }; Assert.True(shape1.Intersects(shape2)); collisionComponent.Insert(actor1); collisionComponent.Insert(actor2); collisionComponent.Update(_gameTime); // Actor should have moved up because the distance is shorter. Assert.True(actor1.Position.Y > actor2.Position.Y); // The circle centers should be about 4 units away after moving Assert.True(Math.Abs(actor1.Position.Y - 2.0f) < float.Epsilon); } #endregion #region Circle Rectangle [Fact] public void PenetrationVectorCircleRectangleTest() { Point2 pos1 = new Point2(0, 1); Point2 pos2 = new Point2(-2, -1); IShapeF shape1 = new CircleF(pos1, 2.0f); IShapeF shape2 = new RectangleF(pos2, new Size2(4, 2)); var actor1 = new BasicActor() { Position = pos1, Bounds = shape1 }; var actor2 = new BasicWall() { Position = pos2, Bounds = shape2 }; Assert.True(shape1.Intersects(shape2)); collisionComponent.Insert(actor1); collisionComponent.Insert(actor2); collisionComponent.Update(_gameTime); Assert.True(Math.Abs(actor1.Position.X - 0.0f) < float.Epsilon); Assert.True(Math.Abs(actor1.Position.Y - 3.0f) < float.Epsilon); } [Fact] public void PenetrationVectorCircleContainedInRectangleTest() { Point2 pos1 = new Point2(0, 0); Point2 pos2 = new Point2(-2, -1); IShapeF shape1 = new CircleF(pos1, 1.0f); IShapeF shape2 = new RectangleF(pos2, new Size2(4, 2)); var actor1 = new BasicActor() { Position = pos1, Bounds = shape1 }; var actor2 = new BasicWall() { Position = pos2, Bounds = shape2 }; Assert.True(shape1.Intersects(shape2)); collisionComponent.Insert(actor1); collisionComponent.Insert(actor2); collisionComponent.Update(_gameTime); Assert.True(Math.Abs(actor1.Position.X - 0.0f) < float.Epsilon); Assert.True(Math.Abs(actor1.Position.Y - -2.0f) < float.Epsilon); } [Fact] public void PenetrationVectorCircleOffAxisRectangleTest() { Point2 pos1 = new Point2(2, 1); Point2 pos2 = new Point2(-2, -1); IShapeF shape1 = new CircleF(pos1, 2.0f); IShapeF shape2 = new RectangleF(pos2, new Size2(4, 2)); var actor1 = new BasicActor() { Position = pos1, Bounds = shape1 }; var actor2 = new BasicWall() { Position = pos2, Bounds = shape2 }; Assert.True(shape1.Intersects(shape2)); collisionComponent.Insert(actor1); collisionComponent.Insert(actor2); collisionComponent.Update(_gameTime); Assert.True(Math.Abs(actor1.Position.X - 2.0f) < float.Epsilon); Assert.True(Math.Abs(actor1.Position.Y - 3.0f) < float.Epsilon); } #endregion #region Rectangle Rectangle [Fact] public void PenetrationVectorRectangleRectangleTest() { Point2 pos1 = new Point2(0, 0); Point2 pos2 = new Point2(-2, -1); IShapeF shape1 = new RectangleF(pos1, new Size2(4, 2)); IShapeF shape2 = new RectangleF(pos2, new Size2(4, 2)); var actor1 = new BasicActor() { Position = pos1, Bounds = shape1 }; var actor2 = new BasicWall() { Position = pos2, Bounds = shape2 }; Assert.True(shape1.Intersects(shape2)); collisionComponent.Insert(actor1); collisionComponent.Insert(actor2); collisionComponent.Update(_gameTime); Assert.True(Math.Abs(actor1.Position.X - 0.0f) < float.Epsilon); Assert.True(Math.Abs(actor1.Position.Y - 1.0f) < float.Epsilon); } [Fact] public void PenetrationVectorRectangleRectangleOffAxisTest() { Point2 pos1 = new Point2(4, 2); Point2 pos2 = new Point2(3, 1); IShapeF shape1 = new RectangleF(pos1, new Size2(4, 2)); IShapeF shape2 = new RectangleF(pos2, new Size2(4, 2)); var actor1 = new BasicActor() { Position = pos1, Bounds = shape1 }; var actor2 = new BasicWall() { Position = pos2, Bounds = shape2 }; Assert.True(shape1.Intersects(shape2)); collisionComponent.Insert(actor1); collisionComponent.Insert(actor2); collisionComponent.Update(_gameTime); Assert.True(Math.Abs(actor1.Position.X - 4.0f) < float.Epsilon); Assert.True(Math.Abs(actor1.Position.Y - 3.0f) < float.Epsilon); } #endregion } }