A 2D tile-based sandbox game.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Collection.h 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. #pragma once
  2. #include <vector>
  3. #include <string>
  4. #include <typeindex>
  5. #include "common.h"
  6. #include "Entity.h"
  7. #include "SlotVector.h"
  8. #include "SmallOptional.h"
  9. namespace Swan {
  10. class EntityCollection;
  11. class EntityRef {
  12. public:
  13. EntityRef() = default;
  14. EntityRef(EntityCollection *coll, size_t index, size_t generation):
  15. coll_(coll), index_(index), generation_(generation) {}
  16. template<typename Func>
  17. EntityRef &then(Func func);
  18. bool hasValue();
  19. Entity *get();
  20. private:
  21. EntityCollection *coll_;
  22. size_t index_;
  23. size_t generation_;
  24. };
  25. class EntityCollection {
  26. public:
  27. struct Factory {
  28. const std::string name;
  29. std::unique_ptr<EntityCollection> (*const create)(std::string name);
  30. };
  31. template<typename Ent>
  32. struct EntWrapper {
  33. size_t generation;
  34. Ent ent;
  35. bool operator==(const EntWrapper &other) const {
  36. return generation == other.generation;
  37. }
  38. };
  39. template<typename Ent>
  40. struct OptionalPolicy {
  41. static void setEmpty(unsigned char *ptr) {
  42. ((EntWrapper<Ent> *)ptr)->generation = ~0ull;
  43. }
  44. static bool isEmpty(const unsigned char *ptr) {
  45. return ((EntWrapper<Ent> *)ptr)->generation == ~0ull;
  46. }
  47. };
  48. template<typename Ent>
  49. using OptEnt = SmallOptional<EntWrapper<Ent>, OptionalPolicy<Ent>>;
  50. virtual ~EntityCollection() = default;
  51. template<typename Ent, typename... Args>
  52. EntityRef spawn(Args&&... args);
  53. virtual const std::string &name() = 0;
  54. virtual std::type_index type() = 0;
  55. virtual size_t size() = 0;
  56. virtual Entity *get(size_t idx) = 0;
  57. virtual Entity *get(size_t idx, size_t version) = 0;
  58. virtual EntityRef spawn(const Context &ctx, const Entity::PackObject &obj) = 0;
  59. virtual void update(const Context &ctx, float dt) = 0;
  60. virtual void tick(const Context &ctx, float dt) = 0;
  61. virtual void draw(const Context &ctx, Win &win) = 0;
  62. private:
  63. virtual void *getEntityVector() = 0;
  64. virtual size_t nextGeneration() = 0;
  65. };
  66. template<typename Ent>
  67. class EntityCollectionImpl: public EntityCollection {
  68. public:
  69. EntityCollectionImpl(std::string name): name_(std::move(name)) {}
  70. size_t size() override { return entities_.size(); }
  71. Entity *get(size_t idx) override { return &entities_[idx]->ent; }
  72. Entity *get(size_t idx, size_t generation) override;
  73. const std::string &name() override { return name_; }
  74. std::type_index type() override { return typeid(Ent); }
  75. EntityRef spawn(const Context &ctx, const Entity::PackObject &obj) override;
  76. void update(const Context &ctx, float dt) override;
  77. void tick(const Context &ctx, float dt) override;
  78. void draw(const Context &ctx, Win &win) override;
  79. private:
  80. void *getEntityVector() override { return (void *)&entities_; }
  81. size_t nextGeneration() override { return generation_++; }
  82. const std::string name_;
  83. SlotVector<EntityCollection::OptEnt<Ent>> entities_;
  84. size_t generation_ = 0;
  85. };
  86. /*
  87. * EntityRef
  88. */
  89. template<typename Func>
  90. inline EntityRef &EntityRef::then(Func func) {
  91. Entity *ent = coll_->get(index_, generation_);
  92. if (ent != nullptr)
  93. func(ent);
  94. return *this;
  95. }
  96. inline Entity *EntityRef::get() {
  97. return coll_->get(index_, generation_);
  98. }
  99. inline bool EntityRef::hasValue() {
  100. return coll_->get(index_, generation_) != nullptr;
  101. }
  102. /*
  103. * EntityCollection
  104. */
  105. template<typename Ent, typename... Args>
  106. inline EntityRef EntityCollection::spawn(Args&&... args) {
  107. auto entities = (SlotVector<OptEnt<Ent>> *)getEntityVector();
  108. size_t generation = nextGeneration();
  109. size_t idx = entities->emplace(EntWrapper<Ent>{
  110. generation, std::move(Ent(std::forward<Args>(args)...)) });
  111. return { this, idx, generation };
  112. }
  113. /*
  114. * EntityCollectionImpl
  115. */
  116. template<typename Ent>
  117. inline Entity *EntityCollectionImpl<Ent>::get(size_t idx, size_t generation) {
  118. if (idx >=entities_.size())
  119. return nullptr;
  120. auto &e = entities_[idx];
  121. // We don't even need to check if e.hasValue(), because if it doesn't,
  122. // its generation will be 0xffff... and the check will fail
  123. if (e->generation != generation)
  124. return nullptr;
  125. return &e->ent;
  126. }
  127. template<typename Ent>
  128. inline EntityRef EntityCollectionImpl<Ent>::spawn(const Context &ctx, const Entity::PackObject &obj) {
  129. size_t generation = nextGeneration();
  130. size_t idx = entities_.emplace(EntWrapper<Ent>{
  131. generation, std::move(Ent(ctx, obj)) });
  132. return { this, idx, generation };
  133. }
  134. template<typename Ent>
  135. inline void EntityCollectionImpl<Ent>::update(const Context &ctx, float dt) {
  136. for (auto &ent: entities_)
  137. ent->ent.update(ctx, dt);
  138. }
  139. template<typename Ent>
  140. inline void EntityCollectionImpl<Ent>::tick(const Context &ctx, float dt) {
  141. for (auto &ent: entities_)
  142. ent->ent.tick(ctx, dt);
  143. }
  144. template<typename Ent>
  145. inline void EntityCollectionImpl<Ent>::draw(const Context &ctx, Win &win) {
  146. for (auto &ent: entities_)
  147. ent->ent.draw(ctx, win);
  148. }
  149. }