diff --git a/src/Collision/Fixed/SpatialHash2D.cs b/src/Collision/Fixed/SpatialHash2D.cs index 0821799..9d1a87a 100644 --- a/src/Collision/Fixed/SpatialHash2D.cs +++ b/src/Collision/Fixed/SpatialHash2D.cs @@ -7,17 +7,20 @@ namespace MoonWorks.Collision.Fixed /// Used to quickly check if two shapes are potentially overlapping. /// /// The type that will be used to uniquely identify shape-transform pairs. - public class SpatialHash2D where T : struct, System.IEquatable where U : IHasAABB2D + public class SpatialHash2D where T : struct, System.IEquatable { private readonly Fix64 cellSize; private readonly Dictionary> hashDictionary = new Dictionary>(); - private readonly Dictionary IDLookup = new Dictionary(); + private readonly Dictionary IDBoxLookup = new Dictionary(); + private readonly Dictionary IDDataLookup = new Dictionary(); - public int MinX { get; private set; } = 0; - public int MaxX { get; private set; } = 0; - public int MinY { get; private set; } = 0; - public int MaxY { get; private set; } = 0; + private readonly HashSet DynamicIDs = new HashSet(); + + private int MinX; + private int MaxX; + private int MinY; + private int MaxY; private Queue> hashSetPool = new Queue>(); @@ -35,12 +38,11 @@ namespace MoonWorks.Collision.Fixed /// Inserts an element into the SpatialHash. /// /// A unique ID for the shape-transform pair. - /// - /// - /// A bitmask value specifying the groups this object belongs to. - public void Insert(T id, U shape, Transform2D transform2D, uint collisionGroups = uint.MaxValue) + public void Insert(T id, AABB2D aabb, Transform2D transform2D, U data, bool dynamic = true) { - var box = AABB2D.Transformed(shape.AABB, transform2D); + Remove(id); + + var box = AABB2D.Transformed(aabb, transform2D); var minHash = Hash(box.Min); var maxHash = Hash(box.Max); @@ -52,19 +54,26 @@ namespace MoonWorks.Collision.Fixed } hashDictionary[key].Add(id); - IDLookup[id] = (shape, transform2D, collisionGroups); + IDDataLookup[id] = data; } MinX = System.Math.Min(MinX, minHash.Item1); MinY = System.Math.Min(MinY, minHash.Item2); MaxX = System.Math.Max(MaxX, maxHash.Item1); MaxY = System.Math.Max(MaxY, maxHash.Item2); + + if (dynamic) + { + DynamicIDs.Add(id); + } + + IDBoxLookup[id] = box; } /// /// Retrieves all the potential collisions of a shape-transform pair. Excludes any shape-transforms with the given ID. /// - public RetrieveEnumerator Retrieve(T id, V hasAABB, Transform2D transform2D, uint collisionMask = uint.MaxValue) where V : IHasAABB2D + public RetrieveEnumerator Retrieve(T id, V hasAABB, Transform2D transform2D) where V : IHasAABB2D { var box = AABB2D.Transformed(hasAABB.AABB, transform2D); var (minX, minY) = Hash(box.Min); @@ -78,18 +87,17 @@ namespace MoonWorks.Collision.Fixed return new RetrieveEnumerator( this, Keys(minX, minY, maxX, maxY), - id, - collisionMask + id ); } /// /// Retrieves all the potential collisions of a shape-transform pair. /// - public RetrieveEnumerator Retrieve(V hasAABB, Transform2D transform2D, uint collisionMask = uint.MaxValue) where V : IHasAABB2D + public RetrieveEnumerator Retrieve(V hasAABB, Transform2D transform2D) where V : IHasAABB2D { var box = AABB2D.Transformed(hasAABB.AABB, transform2D); - return Retrieve(box, collisionMask); + return Retrieve(box); } /// @@ -97,7 +105,7 @@ namespace MoonWorks.Collision.Fixed /// /// A transformed AABB. /// - public RetrieveEnumerator Retrieve(AABB2D aabb, uint collisionMask = uint.MaxValue) + public RetrieveEnumerator Retrieve(T id, AABB2D aabb) { var (minX, minY) = Hash(aabb.Min); var (maxX, maxY) = Hash(aabb.Max); @@ -110,14 +118,29 @@ namespace MoonWorks.Collision.Fixed return new RetrieveEnumerator( this, Keys(minX, minY, maxX, maxY), - collisionMask + id ); } - public void Update(T id, U shape, Transform2D transform2D, uint collisionGroups = uint.MaxValue) + /// + /// Retrieves objects based on a pre-transformed AABB. + /// + /// A transformed AABB. + /// + public RetrieveEnumerator Retrieve(AABB2D aabb) { - Remove(id); - Insert(id, shape, transform2D, collisionGroups); + var (minX, minY) = Hash(aabb.Min); + var (maxX, maxY) = Hash(aabb.Max); + + if (minX < MinX) { minX = MinX; } + if (maxX > MaxX) { maxX = MaxX; } + if (minY < MinY) { minY = MinY; } + if (maxY > MaxY) { maxY = MaxY; } + + return new RetrieveEnumerator( + this, + Keys(minX, minY, maxX, maxY) + ); } /// @@ -125,24 +148,24 @@ namespace MoonWorks.Collision.Fixed /// public void Remove(T id) { - if (IDLookup.TryGetValue(id, out var data)) + if (IDBoxLookup.TryGetValue(id, out var aabb)) { - var (shape, transform, collisionGroups) = data; - - var box = AABB2D.Transformed(shape.AABB, transform); - var minHash = Hash(box.Min); - var maxHash = Hash(box.Max); + var minHash = Hash(aabb.Min); + var maxHash = Hash(aabb.Max); foreach (var key in Keys(minHash.Item1, minHash.Item2, maxHash.Item1, maxHash.Item2)) { - if (hashDictionary.ContainsKey(key)) + if (hashDictionary.TryGetValue(key, out HashSet value)) { - hashDictionary[key].Remove(id); + value.Remove(id); } } - IDLookup.Remove(id); + IDDataLookup.Remove(id); + IDBoxLookup.Remove(id); } + + DynamicIDs.Remove(id); } /// @@ -155,7 +178,19 @@ namespace MoonWorks.Collision.Fixed hash.Clear(); } - IDLookup.Clear(); + IDDataLookup.Clear(); + IDBoxLookup.Clear(); + } + + /// + /// Removes + /// + public void ClearDynamic() + { + foreach (var id in DynamicIDs) + { + Remove(id); + } } private static long MakeLong(int left, int right) @@ -239,15 +274,13 @@ namespace MoonWorks.Collision.Fixed private bool HashSetEnumeratorActive; private HashSet Duplicates; private T? ID; - private uint CollisionMask; public RetrieveEnumerator GetEnumerator() => this; internal RetrieveEnumerator( SpatialHash2D spatialHash, KeysEnumerator keysEnumerator, - T id, - uint collisionMask + T id ) { SpatialHash = spatialHash; KeysEnumerator = keysEnumerator; @@ -255,13 +288,11 @@ namespace MoonWorks.Collision.Fixed HashSetEnumeratorActive = false; Duplicates = SpatialHash.AcquireHashSet(); ID = id; - CollisionMask = collisionMask; } internal RetrieveEnumerator( SpatialHash2D spatialHash, - KeysEnumerator keysEnumerator, - uint collisionMask + KeysEnumerator keysEnumerator ) { SpatialHash = spatialHash; KeysEnumerator = keysEnumerator; @@ -269,7 +300,6 @@ namespace MoonWorks.Collision.Fixed HashSetEnumeratorActive = false; Duplicates = SpatialHash.AcquireHashSet(); ID = null; - CollisionMask = collisionMask; } public bool MoveNext() @@ -293,7 +323,6 @@ namespace MoonWorks.Collision.Fixed // conditions var t = HashSetEnumerator.Current; - var collisionGroups = SpatialHash.IDLookup[t].Item3; if (Duplicates.Contains(t)) { @@ -302,7 +331,7 @@ namespace MoonWorks.Collision.Fixed if (ID.HasValue) { - if (ID.Value.Equals(t) || (CollisionMask & collisionGroups) == 0) + if (ID.Value.Equals(t)) { return MoveNext(); } @@ -312,13 +341,13 @@ namespace MoonWorks.Collision.Fixed return true; } - public (T, U, Transform2D, uint) Current + public (T, U) Current { get { var t = HashSetEnumerator.Current; - var (u, transform, groups) = SpatialHash.IDLookup[t]; - return (t, u, transform, groups); + var u = SpatialHash.IDDataLookup[t]; + return (t, u); } } }