EntityManager.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.Specialized;
  4. using System.Diagnostics;
  5. using System.Linq;
  6. using Microsoft.Xna.Framework;
  7. using MonoGame.Extended.Collections;
  8. using MonoGame.Extended.ECS.Systems;
  9. namespace MonoGame.Extended.ECS
  10. {
  11. public class EntityManager : UpdateSystem
  12. {
  13. private const int _defaultBagSize = 128;
  14. public EntityManager(ComponentManager componentManager)
  15. {
  16. _componentManager = componentManager;
  17. _addedEntities = new Bag<int>(_defaultBagSize);
  18. _removedEntities = new Bag<int>(_defaultBagSize);
  19. _changedEntities = new Bag<int>(_defaultBagSize);
  20. _entityToComponentBits = new Bag<BitVector32>(_defaultBagSize);
  21. _componentManager.ComponentsChanged += OnComponentsChanged;
  22. _entityBag = new Bag<Entity>(_defaultBagSize);
  23. _entityPool = new Pool<Entity>(() => new Entity(_nextId++, this, _componentManager), _defaultBagSize);
  24. }
  25. private readonly ComponentManager _componentManager;
  26. private int _nextId;
  27. public int Capacity => _entityBag.Capacity;
  28. public IEnumerable<int> Entities => _entityBag.Where(e => e != null).Select(e => e.Id);
  29. public int ActiveCount { get; private set; }
  30. private readonly Bag<Entity> _entityBag;
  31. private readonly Pool<Entity> _entityPool;
  32. private readonly Bag<int> _addedEntities;
  33. private readonly Bag<int> _removedEntities;
  34. private readonly Bag<int> _changedEntities;
  35. private readonly Bag<BitVector32> _entityToComponentBits;
  36. public event Action<int> EntityAdded;
  37. public event Action<int> EntityRemoved;
  38. public event Action<int> EntityChanged;
  39. public Entity Create()
  40. {
  41. var entity = _entityPool.Obtain();
  42. var id = entity.Id;
  43. Debug.Assert(_entityBag[id] == null);
  44. _entityBag[id] = entity;
  45. _addedEntities.Add(id);
  46. _entityToComponentBits[id] = new BitVector32(0);
  47. return entity;
  48. }
  49. public void Destroy(int entityId)
  50. {
  51. if (!_removedEntities.Contains(entityId))
  52. _removedEntities.Add(entityId);
  53. }
  54. public void Destroy(Entity entity)
  55. {
  56. Destroy(entity.Id);
  57. }
  58. public Entity Get(int entityId)
  59. {
  60. return _entityBag[entityId];
  61. }
  62. public BitVector32 GetComponentBits(int entityId)
  63. {
  64. return _entityToComponentBits[entityId];
  65. }
  66. private void OnComponentsChanged(int entityId)
  67. {
  68. _changedEntities.Add(entityId);
  69. _entityToComponentBits[entityId] = _componentManager.CreateComponentBits(entityId);
  70. }
  71. public override void Update(GameTime gameTime)
  72. {
  73. foreach (var entityId in _addedEntities)
  74. {
  75. _entityToComponentBits[entityId] = _componentManager.CreateComponentBits(entityId);
  76. ActiveCount++;
  77. EntityAdded?.Invoke(entityId);
  78. }
  79. foreach (var entityId in _changedEntities)
  80. {
  81. EntityChanged?.Invoke(entityId);
  82. }
  83. foreach (var entityId in _removedEntities)
  84. {
  85. // we must notify subscribers before removing it from the pool
  86. // otherwise an entity system could still be using the entity when the same id is obtained.
  87. EntityRemoved?.Invoke(entityId);
  88. var entity = _entityBag[entityId];
  89. _entityBag[entityId] = null;
  90. _componentManager.Destroy(entityId);
  91. _entityToComponentBits[entityId] = default(BitVector32);
  92. ActiveCount--;
  93. _entityPool.Free(entity);
  94. }
  95. _addedEntities.Clear();
  96. _removedEntities.Clear();
  97. _changedEntities.Clear();
  98. }
  99. }
  100. }