Skip to content

Commit c3baf88

Browse files
committed
Implement entity enumeration
1 parent 2f31b76 commit c3baf88

File tree

3 files changed

+66
-11
lines changed

3 files changed

+66
-11
lines changed

src/EntityRegistry.cs

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
using System;
2+
using System.Collections;
23
using System.Collections.Generic;
34

45
namespace SimpleECS
56
{
6-
class EntityRegistry
7+
class EntityRegistry : IReadOnlyCollection<Entity>
78
{
89
public struct EntityLocation
910
{
@@ -20,19 +21,29 @@ public EntityLocation(ArchetypeContainer archetypeContainer, int index)
2021
private const int InitialCapacity = 512;
2122
EntityLocation[] Locations = new EntityLocation[InitialCapacity];
2223
int[] Versions = new int[InitialCapacity];
23-
Queue<int> freeIDs = new Queue<int>();
24-
int count = 0;
24+
HashSet<int> freeIDs = new HashSet<int>();
25+
int nextId = 0;
26+
27+
public int Count => nextId - freeIDs.Count;
2528

2629
public int GetVersion(int entity) => Versions[entity];
2730

2831
public Entity RegisterEntity(ArchetypeContainer container, int index)
2932
{
30-
if (count == Locations.Length)
33+
if (nextId == Locations.Length)
3134
Array.Resize(ref Locations, Locations.Length * 2);
32-
if (!freeIDs.TryDequeue(out int id))
35+
int id;
36+
if (freeIDs.Count > 0)
3337
{
34-
id = count;
35-
count++;
38+
// faster implementation of First()
39+
foreach (var _id in freeIDs) { id = _id; goto done; }
40+
throw new Exception();
41+
done:;
42+
}
43+
else
44+
{
45+
id = nextId;
46+
nextId++;
3647
}
3748
Locations[id] = new EntityLocation(container, index);
3849
return new Entity(id, Versions[id]);
@@ -44,7 +55,7 @@ public void UnregisterEntity(Entity entity, out EntityLocation lastLocation)
4455
lastLocation = Locations[entity.Id];
4556
Locations[entity.Id] = default;
4657
Versions[entity.Id]++;
47-
freeIDs.Enqueue(entity.Id);
58+
freeIDs.Add(entity.Id);
4859
}
4960
public void MoveEntity(int entity, ArchetypeContainer newContainer, int newIndex)
5061
{
@@ -63,5 +74,38 @@ public bool TryGetLocation(Entity entity, out EntityLocation location)
6374
return true;
6475
}
6576
}
77+
78+
public IEnumerator<Entity> GetEnumerator() => new EntityEnumerator(this);
79+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
80+
struct EntityEnumerator : IEnumerator<Entity>
81+
{
82+
int currentId;
83+
EntityRegistry registry;
84+
public Entity Current => new Entity(currentId, registry.GetVersion(currentId));
85+
86+
object? IEnumerator.Current => this.Current;
87+
88+
public EntityEnumerator(EntityRegistry registry)
89+
{
90+
this.currentId = -1;
91+
this.registry = registry;
92+
}
93+
94+
public void Dispose() { }
95+
96+
public bool MoveNext()
97+
{
98+
do
99+
{
100+
currentId++;
101+
if (registry.nextId == currentId)
102+
return false;
103+
}
104+
while (registry.freeIDs.Contains(currentId));
105+
return true;
106+
}
107+
108+
public void Reset() => currentId = -1;
109+
}
66110
}
67111
}

src/Scene.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
using System.Linq;
22
using System;
33
using System.Collections.Generic;
4+
using System.Collections;
45

56
namespace SimpleECS
67
{
7-
public class Scene
8+
public class Scene : IReadOnlyCollection<Entity>
89
{
910
internal Dictionary<ComponentSet.Readonly, ArchetypeContainer> archetypes = new Dictionary<ComponentSet.Readonly, ArchetypeContainer>();
1011

@@ -14,6 +15,10 @@ public class Scene
1415
public GlobalStorage Globals { get; } = new GlobalStorage();
1516
public CallbackManager Callbacks { get; } = new CallbackManager();
1617

18+
public int Count => EntityRegistry.Count;
19+
public IEnumerator<Entity> GetEnumerator() => EntityRegistry.GetEnumerator();
20+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
21+
1722
public Scene()
1823
{
1924
InitialContainer = new ArchetypeContainer(this);
@@ -41,7 +46,7 @@ public void DeleteEntity(Entity entity)
4146
}
4247
foreach (var (index, type) in location.ArchetypeContainer.additions.Keys)
4348
{
44-
if(index == location.Index)
49+
if (index == location.Index)
4550
{
4651
Callbacks.TryGet(type)?.OnComponentRemoved(this, entity);
4752
}

test/Archetypes.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public void CorrectArchetypesCreated()
4646
Assert.That(scene.archetypes.Count == 1);
4747
scene.InsertNewComponents();
4848
Assert.That(scene.archetypes.Count == 2);
49-
49+
5050
var newEntity = scene.CreateEntity();
5151
scene.InsertNewComponents();
5252
Assert.That(scene.archetypes.Count == 2);
@@ -55,5 +55,11 @@ public void CorrectArchetypesCreated()
5555
newEntity.Add<ExampleComp2>();
5656
Assert.That(scene.archetypes.Count == 2);
5757
}
58+
59+
[Test]
60+
public void EnumerateEntities()
61+
{
62+
Assert.That(scene, Is.EquivalentTo(new[] { entity }));
63+
}
5864
}
5965
}

0 commit comments

Comments
 (0)