entity.h 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. #pragma once
  2. #include <cstddef>
  3. #include <cstdint>
  4. #include <functional>
  5. #include <memory>
  6. #include <type_traits>
  7. #include <typeindex>
  8. #include <vector>
  9. namespace Engine::Core {
  10. using EntityID = std::uint32_t;
  11. constexpr EntityID NULL_ENTITY = 0;
  12. class Component {
  13. public:
  14. virtual ~Component() = default;
  15. };
  16. using ComponentChangeCallback =
  17. std::function<void(EntityID, std::type_index, bool)>;
  18. class Entity {
  19. public:
  20. Entity(EntityID id);
  21. auto get_id() const -> EntityID;
  22. void set_component_change_callback(ComponentChangeCallback callback);
  23. template <typename T, typename... Args>
  24. auto add_component(Args &&...args) -> T * {
  25. static_assert(std::is_base_of_v<Component, T>,
  26. "T must inherit from Component");
  27. auto component = std::make_unique<T>(std::forward<Args>(args)...);
  28. auto ptr = component.get();
  29. std::size_t const slot = component_type_id<T>();
  30. if (m_components_by_type.size() <= slot) {
  31. m_components_by_type.resize(slot + 1);
  32. }
  33. m_components_by_type[slot] = std::move(component);
  34. std::type_index const type_idx = std::type_index(typeid(T));
  35. if (m_component_change_callback) {
  36. m_component_change_callback(m_id, type_idx, true);
  37. }
  38. return ptr;
  39. }
  40. template <typename T> auto get_component() -> T * {
  41. std::size_t const slot = component_type_id<T>();
  42. if (slot < m_components_by_type.size()) {
  43. return static_cast<T *>(m_components_by_type[slot].get());
  44. }
  45. return nullptr;
  46. }
  47. template <typename T> auto get_component() const -> const T * {
  48. std::size_t const slot = component_type_id<T>();
  49. if (slot < m_components_by_type.size()) {
  50. return static_cast<const T *>(m_components_by_type[slot].get());
  51. }
  52. return nullptr;
  53. }
  54. template <typename T> void remove_component() {
  55. std::size_t const slot = component_type_id<T>();
  56. std::type_index const type_idx = std::type_index(typeid(T));
  57. if (slot < m_components_by_type.size() &&
  58. m_components_by_type[slot] != nullptr) {
  59. m_components_by_type[slot].reset();
  60. if (m_component_change_callback) {
  61. m_component_change_callback(m_id, type_idx, false);
  62. }
  63. }
  64. }
  65. template <typename T> auto has_component() const -> bool {
  66. std::size_t const slot = component_type_id<T>();
  67. return slot < m_components_by_type.size() &&
  68. m_components_by_type[slot] != nullptr;
  69. }
  70. private:
  71. static auto resolve_component_type_id(std::type_index type) -> std::size_t;
  72. template <typename T> static auto component_type_id() -> std::size_t {
  73. static const std::size_t id =
  74. resolve_component_type_id(std::type_index(typeid(T)));
  75. return id;
  76. }
  77. EntityID m_id;
  78. std::vector<std::unique_ptr<Component>> m_components_by_type;
  79. ComponentChangeCallback m_component_change_callback;
  80. };
  81. } // namespace Engine::Core