Files
MonoGame.Extended/Source/MonoGame.Extended.Collisions/QuadTree/CollisionComponenet.cs
T
Jon SeamanandDylan Wilson ce9fc2459b QuadTree Collision Library (#504)
* Created unit test project for collisions.

* Started on tests

* Created unit test project for collisions.

* Started on tests

* Update collision test

* CollisionInfo docs

* More docs for CollisionGrid and Cell

* Fix obsolete warning for RectangleF.Intersect

* Summary for CollisionGrid and CollisionGridCell

* QuadTree collision implemented

 - Ported from C++ from Game Physics Cookbook chapter 6, 2D Optimizations

* Small refactor for QuadTree naming

* First tests for QuadTree

* Fix test

* COde Cleanup

* Added DefaultMaxObjectsPerNode

* Add missed Query code

* Insert Tests and bugfix

* Fix bug with QuadTree.Shake

* Fix namespaces

* Query tests and fix

* Additional test for Query

* Initial QuadTreeCollision Component

* Basic collision demo working

* Spikey ball colliding with walls

* Improved the collision demo

* Update QuadTree

* Added comment for CollisionComponent

* Ignore test that needs fixed

* Rename QuadTree to Quadtree

* Fix penetration vector

* Update to 2.0 and xUnit
2018-05-30 20:26:34 +10:00

101 lines
3.4 KiB
C#

using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.Xna.Framework;
namespace MonoGame.Extended.Collisions
{
/// <summary>
/// Handles basic collision between actors.
/// When two actors collide, their OnCollision method is called.
/// </summary>
public class CollisionComponent : SimpleGameComponent
{
private readonly Dictionary<IActorTarget, QuadtreeData> _targetDataDictionary =
new Dictionary<IActorTarget, QuadtreeData>();
private readonly Quadtree _collisionTree;
public CollisionComponent(RectangleF boundary)
{
_collisionTree = new Quadtree(boundary);
}
public override void Update(GameTime gameTime)
{
// Update bounding box locations.
foreach (var value in _targetDataDictionary.Values)
{
_collisionTree.Remove(value);
value.BoundingBox = value.Target.BoundingBox;
_collisionTree.Insert(value);
}
// Detect collisions
foreach (var value in _targetDataDictionary.Values)
{
var target = value.Target;
var collisions =_collisionTree.Query(target.BoundingBox)
.Where(data => data.Target != target);
// Generate list of collision Infos
foreach (var other in collisions)
{
var collisionInfo = new CollisionInfo
{
Other = other.Target,
PenetrationVector = PenetrationVector(value.BoundingBox, other.BoundingBox)
};
target.OnCollision(collisionInfo);
}
}
}
public void Insert(IActorTarget target)
{
if (!_targetDataDictionary.ContainsKey(target))
{
var data = new QuadtreeData(target);
_targetDataDictionary.Add(target, data);
_collisionTree.Insert(data);
}
}
public void Remove(IActorTarget target)
{
if (_targetDataDictionary.ContainsKey(target))
{
var data = _targetDataDictionary[target];
_collisionTree.Remove(data);
_targetDataDictionary.Remove(target);
}
}
private static Vector2 PenetrationVector(RectangleF rect1, RectangleF rect2)
{
var intersectingRectangle = RectangleF.Intersection(rect1, rect2);
Debug.Assert(!intersectingRectangle.IsEmpty,
"Violation of: !intersect.IsEmpty; Rectangles must intersect to calculate a penetration vector.");
Vector2 penetration;
if (intersectingRectangle.Width < intersectingRectangle.Height)
{
var d = rect1.Center.X < rect2.Center.X
? intersectingRectangle.Width
: -intersectingRectangle.Width;
penetration = new Vector2(d, 0);
}
else
{
var d = rect1.Center.Y < rect2.Center.Y
? intersectingRectangle.Height
: -intersectingRectangle.Height;
penetration = new Vector2(0, d);
}
return penetration;
}
}
}