mirror of
https://github.com/AlexMacocian/MonoGame.Extended.git
synced 2026-07-15 23:19:29 +00:00
Merge pull request #795 from toore/bug-update-bounds-collision-manager
OnCollision are called even after objects involved are moved and not intersecting
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace MonoGame.Extended.Collisions
|
||||
@@ -12,8 +11,7 @@ namespace MonoGame.Extended.Collisions
|
||||
/// </summary>
|
||||
public class CollisionComponent : SimpleGameComponent
|
||||
{
|
||||
private readonly Dictionary<ICollisionActor, QuadtreeData> _targetDataDictionary =
|
||||
new Dictionary<ICollisionActor, QuadtreeData>();
|
||||
private readonly Dictionary<ICollisionActor, QuadtreeData> _targetDataDictionary = new();
|
||||
|
||||
private readonly Quadtree _collisionTree;
|
||||
|
||||
@@ -47,14 +45,13 @@ namespace MonoGame.Extended.Collisions
|
||||
// Generate list of collision Infos
|
||||
foreach (var other in collisions)
|
||||
{
|
||||
var collisionInfo = new CollisionEventArgs()
|
||||
{
|
||||
Other = other.Target,
|
||||
PenetrationVector = CalculatePenetrationVector(value.Bounds, other.Bounds)
|
||||
};
|
||||
var collisionInfo = new CollisionEventArgs
|
||||
{
|
||||
Other = other.Target,
|
||||
PenetrationVector = CalculatePenetrationVector(value.Bounds, other.Bounds)
|
||||
};
|
||||
|
||||
target.OnCollision(collisionInfo);
|
||||
value.Bounds = value.Target.Bounds;
|
||||
}
|
||||
_collisionTree.Insert(value);
|
||||
}
|
||||
@@ -230,4 +227,4 @@ namespace MonoGame.Extended.Collisions
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,18 +4,32 @@ using System.Collections.Generic;
|
||||
namespace MonoGame.Extended.Collisions
|
||||
{
|
||||
/// <summary>
|
||||
/// Class for doing collision handling with a quad tree.
|
||||
/// Class for doing collision handling with a quad tree.
|
||||
/// </summary>
|
||||
public class Quadtree
|
||||
{
|
||||
/// <summary>
|
||||
/// The default maximum depth.
|
||||
/// </summary>
|
||||
public const int DefaultMaxDepth = 7;
|
||||
|
||||
/// <summary>
|
||||
/// The default maximum objects per node.
|
||||
/// </summary>
|
||||
public const int DefaultMaxObjectsPerNode = 25;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the children of this node.
|
||||
/// </summary>
|
||||
protected List<Quadtree> Children = new List<Quadtree>();
|
||||
|
||||
/// <summary>
|
||||
/// Contains the data for this node in the quadtree.
|
||||
/// </summary>
|
||||
protected HashSet<QuadtreeData> Contents = new HashSet<QuadtreeData>();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a quad tree with the given bounds.
|
||||
/// Creates a quad tree with the given bounds.
|
||||
/// </summary>
|
||||
/// <param name="bounds">The bounds of the new quad tree.</param>
|
||||
public Quadtree(RectangleF bounds)
|
||||
@@ -24,23 +38,31 @@ namespace MonoGame.Extended.Collisions
|
||||
NodeBounds = bounds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current depth for this node in the quadtree.
|
||||
/// </summary>
|
||||
protected int CurrentDepth { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum depth of the quadtree.
|
||||
/// </summary>
|
||||
protected int MaxDepth { get; set; } = DefaultMaxDepth;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum objects per node in this quadtree.
|
||||
/// </summary>
|
||||
protected int MaxObjectsPerNode { get; set; } = DefaultMaxObjectsPerNode;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bounds of the area contained in this quad tree.
|
||||
/// Gets the bounds of the area contained in this quad tree.
|
||||
/// </summary>
|
||||
public RectangleF NodeBounds { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the current node is a leaf node.
|
||||
/// Gets whether the current node is a leaf node.
|
||||
/// </summary>
|
||||
public bool IsLeaf => Children.Count == 0;
|
||||
|
||||
/// <summary>
|
||||
/// Counts the number of unique targets in the current Quadtree.
|
||||
/// Counts the number of unique targets in the current Quadtree.
|
||||
/// </summary>
|
||||
/// <returns>Returns the targets of objects found.</returns>
|
||||
public int NumTargets()
|
||||
@@ -74,21 +96,21 @@ namespace MonoGame.Extended.Collisions
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < dirtyItems.Count; i++)
|
||||
foreach (var quadtreeData in dirtyItems)
|
||||
{
|
||||
dirtyItems[i].MarkClean();
|
||||
quadtreeData.MarkClean();
|
||||
}
|
||||
return objectCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts the data into the tree.
|
||||
/// Inserts the data into the tree.
|
||||
/// </summary>
|
||||
/// <param name="data">Data being inserted.</param>
|
||||
public void Insert(QuadtreeData data)
|
||||
{
|
||||
var actorBounds = data.Target.Bounds;
|
||||
|
||||
var actorBounds = data.Bounds;
|
||||
|
||||
// Object doesn't fit into this node.
|
||||
if (!NodeBounds.Intersects(actorBounds))
|
||||
{
|
||||
@@ -114,7 +136,7 @@ namespace MonoGame.Extended.Collisions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes data from the Quadtree
|
||||
/// Removes data from the Quadtree
|
||||
/// </summary>
|
||||
/// <param name="data">The data to be removed.</param>
|
||||
public void Remove(QuadtreeData data)
|
||||
@@ -126,58 +148,60 @@ namespace MonoGame.Extended.Collisions
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException($"Cannot remove from a non leaf {nameof(Quadtree)}");
|
||||
throw new InvalidOperationException($"Cannot remove from a non leaf {nameof(Quadtree)}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes unneccesary leaf nodes and simplifies the quad tree.
|
||||
/// Removes unnecessary leaf nodes and simplifies the quad tree.
|
||||
/// </summary>
|
||||
public void Shake()
|
||||
{
|
||||
if (!IsLeaf)
|
||||
if (IsLeaf)
|
||||
{
|
||||
List<QuadtreeData> dirtyItems = new List<QuadtreeData>();
|
||||
return;
|
||||
}
|
||||
|
||||
var numObjects = NumTargets();
|
||||
if (numObjects == 0)
|
||||
List<QuadtreeData> dirtyItems = new List<QuadtreeData>();
|
||||
|
||||
var numObjects = NumTargets();
|
||||
if (numObjects == 0)
|
||||
{
|
||||
Children.Clear();
|
||||
}
|
||||
else if (numObjects < MaxObjectsPerNode)
|
||||
{
|
||||
var process = new Queue<Quadtree>();
|
||||
process.Enqueue(this);
|
||||
while (process.Count > 0)
|
||||
{
|
||||
Children.Clear();
|
||||
}
|
||||
else if (numObjects < MaxObjectsPerNode)
|
||||
{
|
||||
var process = new Queue<Quadtree>();
|
||||
process.Enqueue(this);
|
||||
while (process.Count > 0)
|
||||
var processing = process.Dequeue();
|
||||
if (!processing.IsLeaf)
|
||||
{
|
||||
var processing = process.Dequeue();
|
||||
if (!processing.IsLeaf)
|
||||
foreach (var subTree in processing.Children)
|
||||
{
|
||||
foreach (var subTree in processing.Children)
|
||||
{
|
||||
process.Enqueue(subTree);
|
||||
}
|
||||
process.Enqueue(subTree);
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var data in processing.Contents)
|
||||
{
|
||||
foreach (var data in processing.Contents)
|
||||
if (data.Dirty == false)
|
||||
{
|
||||
if (data.Dirty == false)
|
||||
{
|
||||
AddToLeaf(data);
|
||||
data.MarkDirty();
|
||||
dirtyItems.Add(data);
|
||||
}
|
||||
AddToLeaf(data);
|
||||
data.MarkDirty();
|
||||
dirtyItems.Add(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
Children.Clear();
|
||||
}
|
||||
Children.Clear();
|
||||
}
|
||||
|
||||
for (var i = 0; i < dirtyItems.Count; i++)
|
||||
{
|
||||
dirtyItems[i].MarkClean();
|
||||
}
|
||||
foreach (var quadtreeData in dirtyItems)
|
||||
{
|
||||
quadtreeData.MarkClean();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +212,7 @@ namespace MonoGame.Extended.Collisions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits a quadtree into quadrants.
|
||||
/// Splits a quadtree into quadrants.
|
||||
/// </summary>
|
||||
public void Split()
|
||||
{
|
||||
@@ -233,7 +257,7 @@ namespace MonoGame.Extended.Collisions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries the quadtree for targets that intersect with the given area.
|
||||
/// Queries the quadtree for targets that intersect with the given area.
|
||||
/// </summary>
|
||||
/// <param name="area">The area to query for overlapping targets</param>
|
||||
/// <returns>A unique list of targets intersected by area.</returns>
|
||||
@@ -241,16 +265,16 @@ namespace MonoGame.Extended.Collisions
|
||||
{
|
||||
var recursiveResult = new List<QuadtreeData>();
|
||||
QueryWithoutReset(area, recursiveResult);
|
||||
for (var i = 0; i < recursiveResult.Count; i++)
|
||||
foreach (var quadtreeData in recursiveResult)
|
||||
{
|
||||
recursiveResult[i].MarkClean();
|
||||
quadtreeData.MarkClean();
|
||||
}
|
||||
return recursiveResult;
|
||||
}
|
||||
|
||||
private void QueryWithoutReset(IShapeF area, List<QuadtreeData> recursiveResult)
|
||||
{
|
||||
if (!NodeBounds.Intersects(area))
|
||||
if (!NodeBounds.Intersects(area))
|
||||
return;
|
||||
|
||||
if (IsLeaf)
|
||||
@@ -273,4 +297,4 @@ namespace MonoGame.Extended.Collisions
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,65 +1,86 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace MonoGame.Extended.Collisions
|
||||
namespace MonoGame.Extended.Collisions;
|
||||
|
||||
/// <summary>
|
||||
/// Data structure for the quad tree.
|
||||
/// Holds the entity and collision data for it.
|
||||
/// </summary>
|
||||
public class QuadtreeData
|
||||
{
|
||||
private readonly ICollisionActor _target;
|
||||
private readonly HashSet<Quadtree> _parents = new();
|
||||
|
||||
/// <summary>
|
||||
/// Data structure for the quad tree.
|
||||
/// Holds the entity and collision data for it.
|
||||
/// Initialize a new instance of QuadTreeData.
|
||||
/// </summary>
|
||||
public class QuadtreeData
|
||||
/// <param name="target"></param>
|
||||
public QuadtreeData(ICollisionActor target)
|
||||
{
|
||||
public QuadtreeData(ICollisionActor target)
|
||||
{
|
||||
Target = target;
|
||||
Bounds = target.Bounds;
|
||||
}
|
||||
|
||||
public void RemoveParent(Quadtree parent)
|
||||
{
|
||||
Parents.Remove(parent);
|
||||
}
|
||||
|
||||
public void AddParent(Quadtree parent)
|
||||
{
|
||||
Parents.Add(parent);
|
||||
}
|
||||
|
||||
public void RemoveFromAllParents()
|
||||
{
|
||||
foreach (Quadtree parent in Parents.ToList())
|
||||
{
|
||||
parent.Remove(this);
|
||||
}
|
||||
Parents.Clear();
|
||||
}
|
||||
|
||||
public HashSet<Quadtree> Parents = new HashSet<Quadtree>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Target for collision.
|
||||
/// </summary>
|
||||
public ICollisionActor Target { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether Target has had its collision handled this
|
||||
/// iteration.
|
||||
/// </summary>
|
||||
public bool Dirty { get; private set; }
|
||||
|
||||
public void MarkDirty()
|
||||
{
|
||||
Dirty = true;
|
||||
}
|
||||
|
||||
public void MarkClean()
|
||||
{
|
||||
Dirty = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the bounding box for collision detection.
|
||||
/// </summary>
|
||||
public IShapeF Bounds { get; set; }
|
||||
_target = target;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a parent node.
|
||||
/// </summary>
|
||||
/// <param name="parent"></param>
|
||||
public void RemoveParent(Quadtree parent)
|
||||
{
|
||||
_parents.Remove(parent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a parent node.
|
||||
/// </summary>
|
||||
/// <param name="parent"></param>
|
||||
public void AddParent(Quadtree parent)
|
||||
{
|
||||
_parents.Add(parent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove all parent nodes from this node.
|
||||
/// </summary>
|
||||
public void RemoveFromAllParents()
|
||||
{
|
||||
foreach (var parent in _parents.ToList())
|
||||
{
|
||||
parent.Remove(this);
|
||||
}
|
||||
|
||||
_parents.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bounding box for collision detection.
|
||||
/// </summary>
|
||||
public IShapeF Bounds => _target.Bounds;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the collision actor target.
|
||||
/// </summary>
|
||||
public ICollisionActor Target => _target;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether Target has had its collision handled this
|
||||
/// iteration.
|
||||
/// </summary>
|
||||
public bool Dirty { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Mark node as dirty.
|
||||
/// </summary>
|
||||
public void MarkDirty()
|
||||
{
|
||||
Dirty = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mark node as clean, i.e. not dirty.
|
||||
/// </summary>
|
||||
public void MarkClean()
|
||||
{
|
||||
Dirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,16 +13,14 @@ namespace MonoGame.Extended.Collisions.Tests
|
||||
/// </remarks>
|
||||
public class CollisionComponentTests
|
||||
{
|
||||
private CollisionComponent collisionComponent;
|
||||
|
||||
private GameTime _gameTime = new GameTime(TimeSpan.Zero, TimeSpan.FromMilliseconds(16));
|
||||
private readonly CollisionComponent _collisionComponent;
|
||||
private readonly GameTime _gameTime = new GameTime(TimeSpan.Zero, TimeSpan.FromMilliseconds(16));
|
||||
|
||||
public CollisionComponentTests()
|
||||
{
|
||||
collisionComponent = new CollisionComponent(new RectangleF(Point2.Zero, new Point2(10, 10)));
|
||||
_collisionComponent = new CollisionComponent(new RectangleF(Point2.Zero, new Point2(10, 10)));
|
||||
}
|
||||
|
||||
|
||||
#region Circle Circle
|
||||
|
||||
[Fact]
|
||||
@@ -46,9 +44,9 @@ namespace MonoGame.Extended.Collisions.Tests
|
||||
};
|
||||
|
||||
Assert.True(shape1.Intersects(shape2));
|
||||
collisionComponent.Insert(actor1);
|
||||
collisionComponent.Insert(actor2);
|
||||
collisionComponent.Update(_gameTime);
|
||||
_collisionComponent.Insert(actor1);
|
||||
_collisionComponent.Insert(actor2);
|
||||
_collisionComponent.Update(_gameTime);
|
||||
Assert.True(Math.Abs(actor1.Position.Y - -4f) < float.Epsilon);
|
||||
}
|
||||
|
||||
@@ -73,9 +71,9 @@ namespace MonoGame.Extended.Collisions.Tests
|
||||
};
|
||||
|
||||
Assert.True(shape1.Intersects(shape2));
|
||||
collisionComponent.Insert(actor1);
|
||||
collisionComponent.Insert(actor2);
|
||||
collisionComponent.Update(_gameTime);
|
||||
_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
|
||||
@@ -103,9 +101,9 @@ namespace MonoGame.Extended.Collisions.Tests
|
||||
};
|
||||
|
||||
Assert.True(shape1.Intersects(shape2));
|
||||
collisionComponent.Insert(actor1);
|
||||
collisionComponent.Insert(actor2);
|
||||
collisionComponent.Update(_gameTime);
|
||||
_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
|
||||
@@ -134,9 +132,9 @@ namespace MonoGame.Extended.Collisions.Tests
|
||||
};
|
||||
|
||||
Assert.True(shape1.Intersects(shape2));
|
||||
collisionComponent.Insert(actor1);
|
||||
collisionComponent.Insert(actor2);
|
||||
collisionComponent.Update(_gameTime);
|
||||
_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
|
||||
@@ -169,9 +167,9 @@ namespace MonoGame.Extended.Collisions.Tests
|
||||
};
|
||||
|
||||
Assert.True(shape1.Intersects(shape2));
|
||||
collisionComponent.Insert(actor1);
|
||||
collisionComponent.Insert(actor2);
|
||||
collisionComponent.Update(_gameTime);
|
||||
_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);
|
||||
}
|
||||
@@ -198,9 +196,9 @@ namespace MonoGame.Extended.Collisions.Tests
|
||||
};
|
||||
|
||||
Assert.True(shape1.Intersects(shape2));
|
||||
collisionComponent.Insert(actor1);
|
||||
collisionComponent.Insert(actor2);
|
||||
collisionComponent.Update(_gameTime);
|
||||
_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);
|
||||
}
|
||||
@@ -227,9 +225,9 @@ namespace MonoGame.Extended.Collisions.Tests
|
||||
};
|
||||
|
||||
Assert.True(shape1.Intersects(shape2));
|
||||
collisionComponent.Insert(actor1);
|
||||
collisionComponent.Insert(actor2);
|
||||
collisionComponent.Update(_gameTime);
|
||||
_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);
|
||||
}
|
||||
@@ -260,9 +258,9 @@ namespace MonoGame.Extended.Collisions.Tests
|
||||
};
|
||||
|
||||
Assert.True(shape1.Intersects(shape2));
|
||||
collisionComponent.Insert(actor1);
|
||||
collisionComponent.Insert(actor2);
|
||||
collisionComponent.Update(_gameTime);
|
||||
_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);
|
||||
}
|
||||
@@ -289,15 +287,90 @@ namespace MonoGame.Extended.Collisions.Tests
|
||||
};
|
||||
|
||||
Assert.True(shape1.Intersects(shape2));
|
||||
collisionComponent.Insert(actor1);
|
||||
collisionComponent.Insert(actor2);
|
||||
collisionComponent.Update(_gameTime);
|
||||
_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
|
||||
|
||||
public class Behaviours : CollisionComponentTests
|
||||
{
|
||||
[Fact]
|
||||
public void Actors_is_colliding()
|
||||
{
|
||||
var staticBounds = new RectangleF(new Point2(0, 0), new Size2(1, 1));
|
||||
var anotherStaticBounds = new RectangleF(new Point2(0, 0), new Size2(1, 1));
|
||||
var staticActor = new CollisionIndicatingActor(staticBounds);
|
||||
var anotherStaticActor = new CollisionIndicatingActor(anotherStaticBounds);
|
||||
_collisionComponent.Insert(staticActor);
|
||||
_collisionComponent.Insert(anotherStaticActor);
|
||||
|
||||
_collisionComponent.Update(_gameTime);
|
||||
|
||||
Assert.True(staticActor.IsColliding);
|
||||
Assert.True(anotherStaticActor.IsColliding);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Actors_is_not_colliding_when_dynamic_actor_is_moved_out_of_collision_bounds()
|
||||
{
|
||||
var staticBounds = new RectangleF(new Point2(0, 0), new Size2(1, 1));
|
||||
var dynamicBounds = new RectangleF(new Point2(0, 0), new Size2(1, 1));
|
||||
var staticActor = new CollisionIndicatingActor(staticBounds);
|
||||
var dynamicActor = new CollisionIndicatingActor(dynamicBounds);
|
||||
_collisionComponent.Insert(staticActor);
|
||||
_collisionComponent.Insert(dynamicActor);
|
||||
dynamicActor.MoveTo(new Point2(2, 2));
|
||||
|
||||
_collisionComponent.Update(_gameTime);
|
||||
|
||||
Assert.False(staticActor.IsColliding);
|
||||
Assert.False(dynamicActor.IsColliding);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Actors_is_colliding_when_dynamic_actor_is_moved_into_collision_bounds()
|
||||
{
|
||||
var staticBounds = new RectangleF(new Point2(0, 0), new Size2(1, 1));
|
||||
var dynamicBounds = new RectangleF(new Point2(2, 2), new Size2(1, 1));
|
||||
var staticActor = new CollisionIndicatingActor(staticBounds);
|
||||
var dynamicActor = new CollisionIndicatingActor(dynamicBounds);
|
||||
_collisionComponent.Insert(staticActor);
|
||||
_collisionComponent.Insert(dynamicActor);
|
||||
dynamicActor.MoveTo(new Point2(0, 0));
|
||||
|
||||
_collisionComponent.Update(_gameTime);
|
||||
|
||||
Assert.True(staticActor.IsColliding);
|
||||
Assert.True(dynamicActor.IsColliding);
|
||||
}
|
||||
|
||||
private class CollisionIndicatingActor : ICollisionActor
|
||||
{
|
||||
private RectangleF _bounds;
|
||||
|
||||
public CollisionIndicatingActor(RectangleF bounds)
|
||||
{
|
||||
_bounds = bounds;
|
||||
}
|
||||
|
||||
public IShapeF Bounds => _bounds;
|
||||
|
||||
public void OnCollision(CollisionEventArgs collisionInfo)
|
||||
{
|
||||
IsColliding = true;
|
||||
}
|
||||
|
||||
public bool IsColliding { get; private set; }
|
||||
|
||||
public void MoveTo(Point2 position)
|
||||
{
|
||||
_bounds = new RectangleF(position, _bounds.Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user