blob: 2b0920e7de6b043c89ba19637763338f54b3f18d (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace MonoGame.Extended.Collisions;
public class SpatialHash: ISpaceAlgorithm
{
private readonly Dictionary<int, List<ICollisionActor>> _dictionary = new();
private readonly List<ICollisionActor> _actors = new();
private readonly Size2 _size;
public SpatialHash(Size2 size)
{
_size = size;
}
public void Insert(ICollisionActor actor)
{
InsertToHash(actor);
_actors.Add(actor);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void InsertToHash(ICollisionActor actor)
{
var rect = actor.Bounds.BoundingRectangle;
for (var x = rect.Left; x < rect.Right; x+=_size.Width)
for (var y = rect.Top; y < rect.Bottom; y+=_size.Height)
AddToCell(x, y, actor);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void AddToCell(float x, float y, ICollisionActor actor)
{
var index = GetIndex(x, y);
if (_dictionary.TryGetValue(index, out var actors))
actors.Add(actor);
else
_dictionary[index] = new() { actor };
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int GetIndex(float x, float y)
{
return (int)(x / _size.Width) << 16 + (int)(y / _size.Height);
}
public bool Remove(ICollisionActor actor)
{
foreach (var actors in _dictionary.Values)
actors.Remove(actor);
return _actors.Remove(actor);
}
public IEnumerable<ICollisionActor> Query(RectangleF boundsBoundingRectangle)
{
var results = new HashSet<ICollisionActor>();
var bounds = boundsBoundingRectangle.BoundingRectangle;
for (var x = boundsBoundingRectangle.Left; x < boundsBoundingRectangle.Right; x+=_size.Width)
for (var y = boundsBoundingRectangle.Top; y < boundsBoundingRectangle.Bottom; y+=_size.Height)
if (_dictionary.TryGetValue(GetIndex(x, y), out var actors))
foreach (var actor in actors)
if (bounds.Intersects(actor.Bounds))
results.Add(actor);
return results;
}
public List<ICollisionActor>.Enumerator GetEnumerator() => _actors.GetEnumerator();
public void Reset()
{
_dictionary.Clear();
foreach (var actor in _actors)
InsertToHash(actor);
}
}
|