mirror of
https://github.com/AlexMacocian/MonoGame.Extended.git
synced 2026-07-24 03:56:31 +00:00
862b64ac7b
* Added CircleF and RectangleF intersection method * Simplified shape implementation * Docs * Collision system uses shapes * QuadTree collision allows circles * ICollisionActor remove setter +semver: patch * Added position to IShapeF +semver: patch * Added CollisionComponent contains * Fix penetration vector between circles * Circle Rectangle penetration vector * Added test for Rectangle Rectangle Collision * Add docs, fix test
443 lines
11 KiB
C#
443 lines
11 KiB
C#
using System.Collections.Generic;
|
|
using Xunit;
|
|
|
|
namespace MonoGame.Extended.Collisions.Tests
|
|
{
|
|
public class QuadTreeTests
|
|
{
|
|
private Quadtree MakeTree()
|
|
{
|
|
// Bounds set to ensure actors will fit inside the tree with default bounds.
|
|
var bounds = _quadTreeArea;
|
|
var tree = new Quadtree(bounds);
|
|
|
|
return tree;
|
|
}
|
|
|
|
private readonly RectangleF _quadTreeArea = new RectangleF(-10f, -15, 20.0f, 30.0f);
|
|
|
|
[Fact]
|
|
public void ConstructorTest()
|
|
{
|
|
var bounds = new RectangleF(-10f, -15, 20.0f, 30.0f);
|
|
var tree = new Quadtree(bounds);
|
|
|
|
Assert.Equal(bounds, tree.NodeBounds);
|
|
Assert.True(tree.IsLeaf);
|
|
}
|
|
|
|
[Fact]
|
|
public void NumTargetsEmptyTest()
|
|
{
|
|
var tree = MakeTree();
|
|
|
|
Assert.Equal(0, tree.NumTargets());
|
|
}
|
|
|
|
[Fact]
|
|
public void NumTargetsOneTest()
|
|
{
|
|
var tree = MakeTree();
|
|
var actor = new BasicActor();
|
|
|
|
tree.Insert(new QuadtreeData(actor));
|
|
|
|
Assert.Equal(1, tree.NumTargets());
|
|
}
|
|
|
|
|
|
[Fact]
|
|
public void NumTargetsMultipleTest()
|
|
{
|
|
var tree = MakeTree();
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
tree.Insert(new QuadtreeData(new BasicActor()));
|
|
}
|
|
|
|
Assert.Equal(5, tree.NumTargets());
|
|
}
|
|
|
|
[Fact]
|
|
public void NumTargetsManyTest()
|
|
{
|
|
var tree = MakeTree();
|
|
for (int i = 0; i < 1000; i++)
|
|
{
|
|
tree.Insert(new QuadtreeData(new BasicActor()));
|
|
Assert.Equal(i + 1, tree.NumTargets());
|
|
}
|
|
|
|
Assert.Equal(1000, tree.NumTargets());
|
|
}
|
|
|
|
[Fact]
|
|
public void InsertOneTest()
|
|
{
|
|
var tree = MakeTree();
|
|
var actor = new BasicActor();
|
|
|
|
tree.Insert(new QuadtreeData(actor));
|
|
|
|
Assert.Equal(1, tree.NumTargets());
|
|
}
|
|
|
|
[Fact]
|
|
public void InsertOneOverlappingQuadrantsTest()
|
|
{
|
|
var tree = MakeTree();
|
|
var actor = new BasicActor
|
|
{
|
|
Bounds = new RectangleF(-2.5f, -2.5f, 5f, 5f)
|
|
};
|
|
|
|
tree.Insert(new QuadtreeData(actor));
|
|
|
|
Assert.Equal(1, tree.NumTargets());
|
|
}
|
|
|
|
[Fact]
|
|
public void InsertMultipleTest()
|
|
{
|
|
var tree = MakeTree();
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
{
|
|
tree.Insert(new QuadtreeData(new BasicActor()
|
|
{
|
|
Bounds = new RectangleF(0, 0, 1, 1)
|
|
}));
|
|
}
|
|
|
|
Assert.Equal(10, tree.NumTargets());
|
|
}
|
|
|
|
[Fact]
|
|
public void InsertManyTest()
|
|
{
|
|
var tree = MakeTree();
|
|
|
|
for (int i = 0; i < 1000; i++)
|
|
{
|
|
tree.Insert(new QuadtreeData(new BasicActor()
|
|
{
|
|
Bounds = new RectangleF(0, 0, 1, 1)
|
|
}));
|
|
}
|
|
|
|
Assert.Equal(1000, tree.NumTargets());
|
|
}
|
|
|
|
[Fact]
|
|
public void InsertMultipleOverlappingQuadrantsTest()
|
|
{
|
|
var tree = MakeTree();
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
{
|
|
var actor = new BasicActor()
|
|
{
|
|
Bounds = new RectangleF(-10f, -15, 20.0f, 30.0f)
|
|
};
|
|
tree.Insert(new QuadtreeData(actor));
|
|
}
|
|
|
|
Assert.Equal(10, tree.NumTargets());
|
|
}
|
|
|
|
[Fact]
|
|
public void RemoveToEmptyTest()
|
|
{
|
|
var actor = new BasicActor()
|
|
{
|
|
Bounds = new RectangleF(-5f, -7f, 10.0f, 15.0f)
|
|
};
|
|
var data = new QuadtreeData(actor);
|
|
|
|
var tree = MakeTree();
|
|
tree.Insert(data);
|
|
|
|
tree.Remove(data);
|
|
|
|
Assert.Equal(0, tree.NumTargets());
|
|
}
|
|
|
|
[Fact]
|
|
public void RemoveTwoTest()
|
|
{
|
|
var tree = MakeTree();
|
|
var inserted = new List<QuadtreeData>();
|
|
var numTargets = 2;
|
|
|
|
for (int i = 0; i < numTargets; i++)
|
|
{
|
|
var data = new QuadtreeData(new BasicActor()
|
|
{
|
|
Bounds = new RectangleF(0, 0, 1, 1)
|
|
});
|
|
tree.Insert(data);
|
|
inserted.Add(data);
|
|
}
|
|
|
|
|
|
var inTree = numTargets;
|
|
Assert.Equal(inTree, tree.NumTargets());
|
|
|
|
foreach (var data in inserted)
|
|
{
|
|
tree.Remove(data);
|
|
Assert.Equal(--inTree, tree.NumTargets());
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void RemoveThreeTest()
|
|
{
|
|
var tree = MakeTree();
|
|
var inserted = new List<QuadtreeData>();
|
|
var numTargets = 3;
|
|
|
|
for (int i = 0; i < numTargets; i++)
|
|
{
|
|
var data = new QuadtreeData(new BasicActor()
|
|
{
|
|
Bounds = new RectangleF(0, 0, 1, 1)
|
|
});
|
|
tree.Insert(data);
|
|
inserted.Add(data);
|
|
}
|
|
|
|
|
|
var inTree = numTargets;
|
|
Assert.Equal(inTree, tree.NumTargets());
|
|
|
|
foreach (var data in inserted)
|
|
{
|
|
tree.Remove(data);
|
|
Assert.Equal(--inTree, tree.NumTargets());
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void RemoveManyTest()
|
|
{
|
|
var tree = MakeTree();
|
|
var inserted = new List<QuadtreeData>();
|
|
var numTargets = 1000;
|
|
|
|
for (int i = 0; i < numTargets; i++)
|
|
{
|
|
var data = new QuadtreeData(new BasicActor()
|
|
{
|
|
Bounds = new RectangleF(0, 0, 1, 1)
|
|
});
|
|
tree.Insert(data);
|
|
inserted.Add(data);
|
|
}
|
|
|
|
|
|
var inTree = numTargets;
|
|
Assert.Equal(inTree, tree.NumTargets());
|
|
|
|
foreach (var data in inserted)
|
|
{
|
|
tree.Remove(data);
|
|
Assert.Equal(--inTree, tree.NumTargets());
|
|
}
|
|
}
|
|
|
|
|
|
[Fact]
|
|
public void ShakeWhenEmptyTest()
|
|
{
|
|
var tree = MakeTree();
|
|
tree.Shake();
|
|
|
|
Assert.Equal(0, tree.NumTargets());
|
|
}
|
|
|
|
[Fact]
|
|
public void ShakeAfterSplittingWhenEmptyTest()
|
|
{
|
|
var tree = MakeTree();
|
|
|
|
tree.Split();
|
|
tree.Shake();
|
|
Assert.Equal(0, tree.NumTargets());
|
|
}
|
|
|
|
[Fact]
|
|
public void ShakeAfterSplittingNotEmptyTest()
|
|
{
|
|
var tree = MakeTree();
|
|
|
|
tree.Split();
|
|
var data = new QuadtreeData(new BasicActor());
|
|
tree.Insert(data);
|
|
tree.Shake();
|
|
Assert.Equal(1, tree.NumTargets());
|
|
}
|
|
|
|
[Fact]
|
|
public void ShakeWhenContainingOneTest()
|
|
{
|
|
var tree = MakeTree();
|
|
var numTargets = 1;
|
|
|
|
for (int i = 0; i < numTargets; i++)
|
|
{
|
|
var data = new QuadtreeData(new BasicActor());
|
|
tree.Insert(data);
|
|
}
|
|
|
|
tree.Shake();
|
|
Assert.Equal(numTargets, tree.NumTargets());
|
|
}
|
|
|
|
[Fact]
|
|
public void ShakeWhenContainingTwoTest()
|
|
{
|
|
var tree = MakeTree();
|
|
var numTargets = 2;
|
|
|
|
for (int i = 0; i < numTargets; i++)
|
|
{
|
|
var data = new QuadtreeData(new BasicActor());
|
|
tree.Insert(data);
|
|
}
|
|
|
|
tree.Shake();
|
|
Assert.Equal(numTargets, tree.NumTargets());
|
|
}
|
|
|
|
[Fact]
|
|
public void ShakeWhenContainingThreeTest()
|
|
{
|
|
var tree = MakeTree();
|
|
var numTargets = 3;
|
|
|
|
for (int i = 0; i < numTargets; i++)
|
|
{
|
|
var data = new QuadtreeData(new BasicActor());
|
|
tree.Insert(data);
|
|
}
|
|
|
|
tree.Shake();
|
|
Assert.Equal(numTargets, tree.NumTargets());
|
|
}
|
|
|
|
[Fact]
|
|
public void ShakeWhenContainingManyTest()
|
|
{
|
|
var tree = MakeTree();
|
|
var numTargets = Quadtree.DefaultMaxObjectsPerNode + 1;
|
|
|
|
for (int i = 0; i < numTargets; i++)
|
|
{
|
|
var data = new QuadtreeData(new BasicActor());
|
|
tree.Insert(data);
|
|
}
|
|
|
|
tree.Shake();
|
|
Assert.Equal(numTargets, tree.NumTargets());
|
|
}
|
|
|
|
[Fact]
|
|
public void QueryWhenEmptyTest()
|
|
{
|
|
var tree = MakeTree();
|
|
|
|
var query = tree.Query(_quadTreeArea);
|
|
|
|
Assert.Empty(query);
|
|
Assert.Equal(0, tree.NumTargets());
|
|
}
|
|
|
|
[Fact]
|
|
public void QueryNotOverlappingTest()
|
|
{
|
|
var tree = MakeTree();
|
|
|
|
var query = tree.Query(new RectangleF(100f, 100f, 1f, 1f));
|
|
|
|
Assert.Empty(query);
|
|
Assert.Equal(0, tree.NumTargets());
|
|
}
|
|
|
|
[Fact]
|
|
public void QueryLeafNodeNotEmptyTest()
|
|
{
|
|
var tree = MakeTree();
|
|
var actor = new BasicActor();
|
|
tree.Insert(new QuadtreeData(actor));
|
|
|
|
var query = tree.Query(_quadTreeArea);
|
|
Assert.Single(query);
|
|
Assert.Equal(tree.NumTargets(), query.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void QueryLeafNodeNoOverlapTest()
|
|
{
|
|
var tree = MakeTree();
|
|
var actor = new BasicActor();
|
|
tree.Insert(new QuadtreeData(actor));
|
|
|
|
var query = tree.Query(new RectangleF(100f, 100f, 1f, 1f));
|
|
Assert.Empty(query);
|
|
}
|
|
|
|
[Fact]
|
|
public void QueryLeafNodeMultipleTest()
|
|
{
|
|
var tree = MakeTree();
|
|
var numTargets = Quadtree.DefaultMaxObjectsPerNode;
|
|
for (int i = 0; i < numTargets; i++)
|
|
{
|
|
var data = new QuadtreeData(new BasicActor());
|
|
tree.Insert(data);
|
|
}
|
|
|
|
|
|
var query = tree.Query(_quadTreeArea);
|
|
Assert.Equal(numTargets, query.Count);
|
|
Assert.Equal(tree.NumTargets(), query.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void QueryNonLeafManyTest()
|
|
{
|
|
var tree = MakeTree();
|
|
var numTargets = 2*Quadtree.DefaultMaxObjectsPerNode;
|
|
for (int i = 0; i < numTargets; i++)
|
|
{
|
|
var data = new QuadtreeData(new BasicActor());
|
|
tree.Insert(data);
|
|
}
|
|
|
|
|
|
var query = tree.Query(_quadTreeArea);
|
|
Assert.Equal(numTargets, query.Count);
|
|
Assert.Equal(tree.NumTargets(), query.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void QueryTwiceConsecutiveTest()
|
|
{
|
|
var tree = MakeTree();
|
|
var numTargets = 2 * Quadtree.DefaultMaxObjectsPerNode;
|
|
for (int i = 0; i < numTargets; i++)
|
|
{
|
|
var data = new QuadtreeData(new BasicActor());
|
|
tree.Insert(data);
|
|
}
|
|
|
|
|
|
var query1 = tree.Query(_quadTreeArea);
|
|
var query2 = tree.Query(_quadTreeArea);
|
|
Assert.Equal(numTargets, query1.Count);
|
|
Assert.Equal(tree.NumTargets(), query1.Count);
|
|
Assert.Equal(query1.Count, query2.Count);
|
|
}
|
|
}
|
|
} |