A 2D tile-based sandbox game.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

Collection.h 5.1KB

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