blob: 5e1d28a6a1f09e7ddd4bf9acb1f75f619083e1de (
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq;
using Microsoft.Xna.Framework;
using MonoGame.Extended.Collections;
using MonoGame.Extended.Entities.Systems;
namespace MonoGame.Extended.Entities
{
public class EntityManager : UpdateSystem
{
private const int _defaultBagSize = 128;
public EntityManager(ComponentManager componentManager)
{
_componentManager = componentManager;
_addedEntities = new Bag<int>(_defaultBagSize);
_removedEntities = new Bag<int>(_defaultBagSize);
_changedEntities = new Bag<int>(_defaultBagSize);
_entityToComponentBits = new Bag<BitVector32>(_defaultBagSize);
_componentManager.ComponentsChanged += OnComponentsChanged;
_entityBag = new Bag<Entity>(_defaultBagSize);
_entityPool = new Pool<Entity>(() => new Entity(_nextId++, this, _componentManager), _defaultBagSize);
}
private readonly ComponentManager _componentManager;
private int _nextId;
public int Capacity => _entityBag.Capacity;
public IEnumerable<int> Entities => _entityBag.Where(e => e != null).Select(e => e.Id);
public int ActiveCount { get; private set; }
private readonly Bag<Entity> _entityBag;
private readonly Pool<Entity> _entityPool;
private readonly Bag<int> _addedEntities;
private readonly Bag<int> _removedEntities;
private readonly Bag<int> _changedEntities;
private readonly Bag<BitVector32> _entityToComponentBits;
public event Action<int> EntityAdded;
public event Action<int> EntityRemoved;
public event Action<int> EntityChanged;
public Entity Create()
{
var entity = _entityPool.Obtain();
var id = entity.Id;
Debug.Assert(_entityBag[id] == null);
_entityBag[id] = entity;
_addedEntities.Add(id);
_entityToComponentBits[id] = new BitVector32(0);
return entity;
}
public void Destroy(int entityId)
{
if (!_removedEntities.Contains(entityId))
_removedEntities.Add(entityId);
}
public void Destroy(Entity entity)
{
Destroy(entity.Id);
}
public Entity Get(int entityId)
{
return _entityBag[entityId];
}
public BitVector32 GetComponentBits(int entityId)
{
return _entityToComponentBits[entityId];
}
private void OnComponentsChanged(int entityId)
{
_changedEntities.Add(entityId);
_entityToComponentBits[entityId] = _componentManager.CreateComponentBits(entityId);
EntityChanged?.Invoke(entityId);
}
public override void Update(GameTime gameTime)
{
foreach (var entityId in _addedEntities)
{
_entityToComponentBits[entityId] = _componentManager.CreateComponentBits(entityId);
ActiveCount++;
EntityAdded?.Invoke(entityId);
}
foreach (var entityId in _changedEntities)
{
_entityToComponentBits[entityId] = _componentManager.CreateComponentBits(entityId);
EntityChanged?.Invoke(entityId);
}
foreach (var entityId in _removedEntities)
{
// we must notify subscribers before removing it from the pool
// otherwise an entity system could still be using the entity when the same id is obtained.
EntityRemoved?.Invoke(entityId);
var entity = _entityBag[entityId];
_entityBag[entityId] = null;
_componentManager.Destroy(entityId);
_entityToComponentBits[entityId] = default(BitVector32);
ActiveCount--;
_entityPool.Free(entity);
}
_addedEntities.Clear();
_removedEntities.Clear();
_changedEntities.Clear();
}
}
}
|