vecs
Fast, flexible ecs in C++ with ergonomic API
Loading...
Searching...
No Matches
vecs.h
Go to the documentation of this file.
1
5#ifndef __VECS_H__
6#define __VECS_H__
7
8#include <cassert>
9#include <chrono>
10#include <cstdio>
11#include <functional>
12#include <memory>
13#include <typeindex>
14#include <unordered_map>
15#include <variant>
16
17#include "bundle.h"
18#include "dense_map.h"
19#include "type_id.h"
20
21namespace vecs {
22
23template<typename T>
24class Optional;
25
26template<typename T>
27struct With {};
28
29template<typename T>
30struct Without {};
31
32template<typename... Filters>
33class Filter {};
34
35namespace _traits {
36
37 template<typename T>
38 struct function_traits;
39
40 // Specialization for function types
41 template<typename R, typename... Args>
42 struct function_traits<R(Args...)> {
43 using result_type = R;
44 using args_tuple = std::tuple<Args...>;
45 };
46
47 // Specialization for function pointers
48 template<typename R, typename... Args>
49 struct function_traits<R (*)(Args...)>: function_traits<R(Args...)> {};
50
51 // Specialization for function references
52 template<typename R, typename... Args>
53 struct function_traits<R (&)(Args...)>: function_traits<R(Args...)> {};
54
55 // Specialization for member function pointers
56 template<typename C, typename R, typename... Args>
57 struct function_traits<R (C::*)(Args...)>: function_traits<R(Args...)> {};
58
59 // Specialization for const member function pointers
60 template<typename C, typename R, typename... Args>
61 struct function_traits<R (C::*)(Args...) const>:
62 function_traits<R(Args...)> {};
63
64 // Specialization for functors and lambdas
65 template<typename T>
66 struct function_traits: function_traits<decltype(&T::operator())> {};
67
68 template<typename T, typename... Ts>
69 struct contains;
70
71 template<typename T>
72 struct contains<T>: std::false_type {};
73
74 template<typename T, typename U, typename... Ts>
75 struct contains<T, U, Ts...>: contains<T, Ts...> {};
76
77 template<typename T, typename... Ts>
78 struct contains<T, T, Ts...>: std::true_type {};
79
80 template<typename T>
81 struct is_optional: std::false_type {};
82
83 template<typename T>
84 struct is_optional<Optional<T>>: std::true_type {};
85
86} // namespace _traits
87
88namespace _traits::query {
89
90 template<typename T>
92 using StorageType = T*;
93 using IterationType = T&;
94 using IterationPointerType = T*;
95
96 static IterationType dereference(StorageType arg) {
97 return *arg;
98 }
99 };
100
101 template<>
102 struct QueryTypeTraits<Entity> {
103 using StorageType = Entity;
104 using IterationType = Entity;
105 using IterationPointerType = Entity*;
106
107 static IterationType dereference(StorageType arg) {
108 return arg;
109 }
110 };
111
112 template<typename T>
114 using StorageType = Optional<T>;
117
118 static IterationType dereference(StorageType arg) {
119 return arg;
120 }
121 };
122
123 template<typename T>
125 static constexpr bool is_with = false;
126 static constexpr bool is_without = false;
127 using component_type = void;
128 };
129
130 template<typename T>
131 struct filter_traits<With<T>> {
132 static constexpr bool is_with = true;
133 static constexpr bool is_without = false;
134 using component_type = T;
135 };
136
137 template<typename T>
139 static constexpr bool is_with = false;
140 static constexpr bool is_without = true;
141 using component_type = T;
142 };
143
144} // namespace _traits::query
145
146struct Parent {
147 Entity entity;
148
149 operator Entity() {
150 return entity;
151 }
152};
153
158enum class ScheduleLabel {
159 Startup,
160 PreUpdate,
161 Update,
162 Validate,
163 PostUpdate,
164 PreStore,
165 Store
166};
167
168// Forward declare
169class World;
170template<typename... Components>
171struct Bundle;
172template<typename... Components>
173class Observer;
174class Commands;
175
176template<typename Tuple>
177auto get_system_params(World& world);
178
180 virtual ~TypeErasedResource() = default;
181};
182
192template<typename T>
198 explicit Resource(T* ptr) : m_ptr(ptr) {}
199
200 T& operator*() const {
201 return *m_ptr;
202 }
203
204 T* operator->() const {
205 return m_ptr;
206 }
207
208 T* get() const {
209 return m_ptr;
210 }
211
212 T* get_mut() {
213 return m_ptr;
214 }
215
216 private:
217 T* m_ptr {nullptr};
218};
219
221 public:
222 virtual ~TypeErasedObserver() = default;
223 virtual const std::vector<Entity>& added() const = 0;
224 virtual const std::vector<Entity>& inserted() const = 0;
225 virtual const std::vector<Entity>& removed() const = 0;
226
227 private:
228 friend class World;
229 virtual const ComponentMask& mask() const = 0;
230 virtual void insert(Entity entity) = 0;
231 virtual void remove(Entity entity) = 0;
232 virtual void add(Entity entity) = 0;
233 virtual void clear() = 0;
234};
235
260template<typename... Components>
262 public:
268 Observer() : m_mask(compute_mask<Components...>()) {}
269
270 Observer(const Observer&) = delete;
271 Observer& operator=(const Observer&) = delete;
272 Observer(Observer&&) = delete;
273 Observer& operator=(Observer&&) = delete;
274
283 const std::vector<Entity>& added() const override {
284 return get_entities(Added);
285 }
286
295 const std::vector<Entity>& inserted() const override {
296 return get_entities(Inserted);
297 }
298
307 const std::vector<Entity>& removed() const override {
308 return get_entities(Removed);
309 }
310
311 private:
312 ComponentMask m_mask;
313
314 using kind = unsigned int;
315
316 constexpr static kind Added = 0;
317 constexpr static kind Inserted = 1;
318 constexpr static kind Removed = 2;
319
320 inline const std::vector<Entity>& get_entities(kind kind) const {
321 static const std::vector<Entity> empty;
322 auto it = m_entities.find(kind);
323 return (it != m_entities.end()) ? it->second : empty;
324 }
325
326 const ComponentMask& mask() const override {
327 return m_mask;
328 }
329
330 void add(Entity entity) override {
331 m_entities[Added].push_back(entity);
332 }
333
334 void insert(Entity entity) override {
335 m_entities[Inserted].push_back(entity);
336 }
337
338 void remove(Entity entity) override {
339 m_entities[Removed].push_back(entity);
340 }
341
342 void clear() override {
343 m_entities.clear();
344 }
345
346 storage::dense_map<kind, std::vector<Entity>> m_entities;
347};
348
349class EntityBuilder;
350template<typename... Components>
351class Query;
352
353struct Time {
354 float delta {0.f};
355};
356
361class World {
362 public:
363 World() :
364 m_last_time(std::chrono::high_resolution_clock::now()),
365 m_commands(std::make_unique<Commands>(*this)) {
366 add_resource(&m_time);
367 }
368
378 template<typename T>
379 World& add_resource(T* resource) {
380 m_resources[typeid(T)] = std::make_unique<Resource<T>>(resource);
381 return *this;
382 }
383
393 template<typename T>
395 auto it = m_resources.find(typeid(T));
396
397 assert(it != m_resources.end() && "Requested resource not found");
398
399 return *static_cast<Resource<T>*>(it->second.get());
400 }
401
417 template<typename Func>
418 void add_system(ScheduleLabel label, Func&& func) {
419 get_systems(label).emplace_back(
420 std::make_unique<System<std::decay_t<Func>>>(
421 std::forward<Func>(func),
422 *this
423 )
424 );
425 }
426
442 template<typename Func>
443 void add_system(Func&& func) {
444 add_system(ScheduleLabel::Update, std::forward<Func>(func));
445 }
446
450 inline void progress() {
451 auto current_time = std::chrono::high_resolution_clock::now();
452 std::chrono::duration<float> delta = current_time - m_last_time;
453 m_time.delta = delta.count();
454 m_last_time = current_time;
455 execute_progress();
456 }
457
463 inline void progress(float delta_time) {
464 m_time.delta = delta_time;
465 execute_progress();
466 }
467
468 EntityBuilder spawn();
469
470 template<typename... Components>
471 inline Query<Components...> query() {
472 return Query<Components...>(this);
473 }
474
475 template<typename... Components>
476 Observer<Components...>& observe() {
477 auto observer = std::make_unique<Observer<Components...>>();
478 auto new_observer = observer.get();
479 m_observers.push_back(std::move(observer));
480 return *new_observer;
481 }
482
483 inline Commands& commands();
484
485 void despawn(Entity entity) {
486 auto entity_it = m_entity_archetype_map.find(entity);
487 if (entity_it == m_entity_archetype_map.end()) {
488 // can't despawn non-existant entity
489 return;
490 }
491
492 Archetype* archetype = entity_it->second;
493 archetype->remove_entity(entity);
494 m_entity_archetype_map.erase(entity_it);
495 notify_remove(archetype->m_mask, entity);
496 m_free_list.push_back(entity);
497 ++m_query_version;
498 }
499
500 void log_archetypes() {
501 printf("--- Logging Archetypes ---\n");
502 for (const auto& archetype : m_archetypes) {
503 printf(
504 "Archetype with mask: %s\n",
505 archetype->m_mask.to_string().c_str()
506 );
507
508 if (archetype->m_entity_to_index.empty()) {
509 printf("No entities in this archetype (empty)\n");
510 } else {
511 printf("Entities in this archetype: ");
512 for (const auto& entity : archetype->m_entity_to_index) {
513 printf("Entity(%zu) ", entity.first);
514 }
515 printf("(total = %zu)\n", archetype->m_entity_to_index.size());
516 }
517 }
518 printf("--- End of Archetypes Log ---\n");
519 }
520
521 private:
522 template<typename... Components>
523 friend class Query;
524 friend class EntityBuilder;
525 friend class EntityCommands;
526
527 // System implementation details
528 struct TypeErasedSystem {
529 virtual ~TypeErasedSystem() = default;
530 virtual void execute(World& world) = 0;
531 };
532
533 template<typename Func>
534 struct System: TypeErasedSystem {
535 Func func;
536
537 System(Func&& f, World& world) :
538 params(get_system_params<
539 typename _traits::function_traits<Func>::args_tuple>(world)),
540 func(std::forward<Func>(f)) {}
541
542 void execute(World& world) override {
543 std::apply(func, params);
544 }
545
546 private:
547 using Params =
548 decltype(get_system_params<
549 typename _traits::function_traits<Func>::args_tuple>(
550 std::declval<World&>()
551 ));
552 Params params;
553 };
554
555 // Archetype storage implementation details
556 class Archetype {
557 private:
558 template<typename... Components>
559 friend class Query;
560 friend class World;
561 friend class EntityBuilder;
562
563 template<typename T>
564 T* get_component(Entity entity) {
565 auto it = m_entity_to_index.find(entity);
566 if (it == m_entity_to_index.end()) {
567 return nullptr;
568 }
569 return get_row<T>(it->second);
570 }
571
572 template<typename T>
573 T* get_row(size_t row) {
574 static const ComponentId id = TypeIDGenerator::get_type_id<T>();
575 auto it = m_type_to_column.find(id);
576 if (it == m_type_to_column.end()) {
577 // Component type does not exist in the archetype
578 return nullptr;
579 }
580
581 auto* column =
582 static_cast<ComponentColumn<T>*>(m_columns[it->second].get());
583 if (row >= column->data.size()) {
584 // Row index is out of range
585 return nullptr;
586 }
587
588 return &column->data[row];
589 }
590
591 template<typename Component>
592 static auto
593 get_component_or_entity(Archetype* archetype, const Entity& entity) {
594 if constexpr (std::is_same_v<Component, Entity>) {
595 return entity;
596 } else if constexpr (_traits::is_optional<Component>()) {
597 using UnderlyingType = typename Component::value_type;
598 return Optional<UnderlyingType>(
599 archetype->template get_component<UnderlyingType>(entity)
600 );
601 } else {
602 return archetype->template get_component<Component>(entity);
603 }
604 }
605
606 template<typename... Components>
607 static auto
608 make_component_tuple(Archetype* archetype, const Entity& entity) {
609 return std::make_tuple(
610 get_component_or_entity<Components>(archetype, entity)...
611 );
612 }
613
614 Archetype(const ComponentMask& mask) : m_mask(mask) {}
615
616 template<typename... Components>
617 static std::unique_ptr<Archetype> from_columns() {
618 ComponentMask mask = compute_mask<Components...>();
619 auto archetype = std::make_unique<Archetype>(Archetype(mask));
620 (archetype->add_column<Components>(), ...);
621 return std::move(archetype);
622 }
623
624 template<typename... NewComponents>
625 static std::unique_ptr<Archetype>
626 from_archetype(const Archetype& old_archetype) {
627 ComponentMask new_components_mask =
628 compute_mask<NewComponents...>();
629 ComponentMask combined_mask =
630 old_archetype.m_mask | new_components_mask;
631
632 auto new_archetype =
633 std::make_unique<Archetype>(Archetype(combined_mask));
634
635 for (const auto& [component_id, column_index] :
636 old_archetype.m_type_to_column) {
637 auto& component = old_archetype.m_columns[column_index];
638 new_archetype->m_columns.emplace_back(component->clone_empty());
639 new_archetype->m_type_to_column[component_id] =
640 new_archetype->m_columns.size() - 1;
641 }
642
643 (new_archetype->add_column<NewComponents>(), ...);
644
645 return new_archetype;
646 }
647
648 template<typename T>
649 void add_column() {
650 ComponentId id = TypeIDGenerator::get_type_id<T>();
651 m_columns.push_back(std::make_unique<ComponentColumn<T>>());
652 m_type_to_column[id] = m_columns.size() - 1;
653 }
654
655 template<typename T>
656 void add_row(size_t row, T&& component) {
657 static const ComponentId id = TypeIDGenerator::get_type_id<T>();
658
659 auto it = m_type_to_column.find(id);
660 if (it == m_type_to_column.end()) {
661 printf("Error: column does not exist in archetype\n");
662 std::abort();
663 }
664
665 auto* column = static_cast<ComponentColumn<T>*>(
666 m_columns[m_type_to_column[id]].get()
667 );
668
669 if (column->data.size() <= row) {
670 column->data.resize(row + 1);
671 }
672
673 column->data[row] = std::forward<T>(component);
674 }
675
676 template<typename... Components>
677 void update_components(Entity entity, Components&&... components) {
678 (update_row<Components>(entity, components), ...);
679 }
680
681 template<typename T>
682 void update_row(Entity entity, T&& component) {
683 static const ComponentId id = TypeIDGenerator::get_type_id<T>();
684
685 auto it = m_type_to_column.find(id);
686 if (it == m_type_to_column.end()) {
687 printf("error: coulmn does not exist in archetype\n");
688 std::abort();
689 }
690
691 auto* column = static_cast<ComponentColumn<T>*>(
692 m_columns[m_type_to_column[id]].get()
693 );
694
695 auto row_it = m_entity_to_index.find(entity);
696
697 if (row_it == m_entity_to_index.end()) {
698 printf("error: row does not exist in archetype\n");
699 std::abort();
700 }
701
702 column->data[row_it->second] = std::forward<T>(component);
703 }
704
705 template<typename... Components>
706 bool has_components() const {
707 auto mask = compute_mask<Components...>();
708 return has_components(mask);
709 }
710
711 bool has_components(ComponentMask mask) const {
712 // return (m_mask & mask) == mask;
713 return m_mask.contains(mask);
714 }
715
716 template<typename... Components>
717 void add_entity(Entity entity, Components&&... components) {
718 size_t row = m_next_available_row;
719 m_entity_to_index[entity] = row;
720 (add_row<Components>(row, std::forward<Components>(components)),
721 ...);
722 ++m_next_available_row;
723 }
724
725 void remove_entity(Entity entity) {
726 auto it = m_entity_to_index.find(entity);
727 if (it == m_entity_to_index.end()) {
728 return;
729 }
730 size_t row = it->second;
731 size_t last_row = m_next_available_row - 1;
732 if (row != last_row) {
733 for (auto& column : m_columns) {
734 column->swap(row, last_row);
735 }
736 for (auto& pair : m_entity_to_index) {
737 if (pair.second == last_row) {
738 pair.second = row;
739 break;
740 }
741 }
742 }
743
744 --m_next_available_row;
745
746 for (auto& column : m_columns) {
747 column->pop_back();
748 }
749
750 m_entity_to_index.erase(it);
751 }
752
753 struct TypeErasedComponentColumn {
754 virtual ~TypeErasedComponentColumn() = default;
755 virtual std::unique_ptr<TypeErasedComponentColumn>
756 clone_empty() const = 0;
757 virtual void copy_component_to(
758 TypeErasedComponentColumn* target_column,
759 size_t from_index,
760 size_t to_index
761 ) = 0;
762 virtual void swap(size_t index1, size_t index2) = 0;
763 virtual void pop_back() = 0;
764 };
765
766 template<typename T>
767 struct ComponentColumn: TypeErasedComponentColumn {
768 using StorageType = typename std::decay<T>::type;
769
770 std::vector<StorageType> data;
771
772 std::unique_ptr<TypeErasedComponentColumn>
773 clone_empty() const override {
774 return std::make_unique<ComponentColumn<T>>();
775 }
776
777 void copy_component_to(
778 TypeErasedComponentColumn* target_column,
779 size_t from_index,
780 size_t to_index
781 ) override {
782 auto* target = static_cast<ComponentColumn<T>*>(target_column);
783 if (target->data.size() <= to_index) {
784 target->data.resize(to_index + 1);
785 }
786 target->data[to_index] = this->data[from_index];
787 }
788
789 void swap(size_t index1, size_t index2) override {
790 std::swap(data[index1], data[index2]);
791 }
792
793 void pop_back() override {
794 data.pop_back();
795 }
796 };
797
798 template<typename... NewComponents>
799 void move_entity(
800 Archetype* target_archetype,
801 Entity entity,
802 NewComponents&&... new_components
803 ) {
804 auto it = m_entity_to_index.find(entity);
805 if (it == m_entity_to_index.end()) {
806 printf("Error: Entity not found in archetype during move.\n");
807 std::abort();
808 }
809 size_t source_row = it->second;
810 size_t target_row = target_archetype->m_next_available_row;
811 target_archetype->m_entity_to_index[entity] = target_row;
812
813 for (const auto& [component_id, column_index] : m_type_to_column) {
814 auto& src_column = m_columns[column_index];
815 auto target_it =
816 target_archetype->m_type_to_column.find(component_id);
817 if (target_it != target_archetype->m_type_to_column.end()) {
818 size_t target_column_index = target_it->second;
819 auto& target_column =
820 target_archetype->m_columns[target_column_index];
821
822 // Move the component data
823 src_column->copy_component_to(
824 target_column.get(),
825 source_row,
826 target_row
827 );
828 }
829 }
830
831 // Add new components
832 (target_archetype->add_row<NewComponents>(
833 target_row,
834 std::forward<NewComponents>(new_components)
835 ),
836 ...);
837
838 // Increment the target archetype's row count
839 ++target_archetype->m_next_available_row;
840 }
841
842 ComponentMask m_mask;
843
844 size_t m_next_available_row {0};
845 storage::dense_map<ComponentId, size_t> m_type_to_column;
846 storage::dense_map<Entity, size_t> m_entity_to_index;
847 std::vector<std::unique_ptr<TypeErasedComponentColumn>> m_columns;
848 };
849
850 void notify_add(const ComponentMask& mask, Entity entity) {
851 for (const auto& observer : m_observers) {
852 if (mask.contains(observer->mask())) {
853 observer->add(entity);
854 }
855 }
856 }
857
858 void notify_insert(const ComponentMask& mask, Entity entity) {
859 for (const auto& observer : m_observers) {
860 if (mask.contains(observer->mask())) {
861 observer->insert(entity);
862 }
863 }
864 }
865
866 void notify_remove(const ComponentMask& mask, Entity entity) {
867 for (const auto& observer : m_observers) {
868 if (mask.contains(observer->mask())) {
869 observer->remove(entity);
870 }
871 }
872 }
873
874 template<typename... Components>
875 void add_components(Entity entity, Components&&... components) {
876 auto new_components_mask = compute_mask<Components...>();
877 ComponentMask combined_mask = new_components_mask;
878
879 Archetype* current_archetype = nullptr;
880 auto entity_it = m_entity_archetype_map.find(entity);
881 if (entity_it != m_entity_archetype_map.end()) {
882 current_archetype = entity_it->second;
883 combined_mask = current_archetype->m_mask | new_components_mask;
884
885 // Check if the current archetype can accommodate the new components
886 if (current_archetype->m_mask.contains(new_components_mask)) {
887 current_archetype->update_components(entity, components...);
888 notify_insert(combined_mask, entity);
889 return;
890 }
891 }
892
893 // Find or create an archetype with the combined mask
894 Archetype* target_archetype = nullptr;
895 auto archetype_it = m_archetype_map.find(combined_mask);
896 if (archetype_it != m_archetype_map.end()) {
897 // Use existing archetype
898 target_archetype = archetype_it->second;
899 } else {
900 // Create a new archetype with combined components
901 if (current_archetype == nullptr) {
902 auto new_archetype = Archetype::from_columns<Components...>();
903 target_archetype = new_archetype.get();
904 m_archetypes.push_back(std::move(new_archetype));
905 m_archetype_map[combined_mask] = target_archetype;
906 } else {
907 auto new_archetype =
908 Archetype::from_archetype<Components...>(*current_archetype
909 );
910 target_archetype = new_archetype.get();
911 m_archetypes.push_back(std::move(new_archetype));
912 m_archetype_map[combined_mask] = target_archetype;
913 }
914 }
915
916 if (current_archetype != nullptr) {
917 current_archetype->move_entity(
918 target_archetype,
919 entity,
920 std::forward<Components>(components)...
921 );
922 notify_add(combined_mask, entity);
923 notify_insert(combined_mask, entity);
924 // Remove the entity from the current archetype
925 current_archetype->remove_entity(entity);
926 } else {
927 target_archetype->add_entity(
928 entity,
929 std::forward<Components>(components)...
930 );
931 notify_add(combined_mask, entity);
932 notify_insert(combined_mask, entity);
933 }
934 m_entity_archetype_map[entity] = target_archetype;
935 ++m_query_version;
936 }
937
938 template<typename Component>
939 void remove_component(Entity entity) {
940 auto entity_it = m_entity_archetype_map.find(entity);
941 if (entity_it == m_entity_archetype_map.end()) {
942 return;
943 }
944
945 Archetype* current_archetype = entity_it->second;
946
947 ComponentMask new_mask = current_archetype->m_mask;
948 ComponentId component_id = TypeIDGenerator::get_type_id<Component>();
949 new_mask.reset(component_id);
950
951 // Check if an archetype with this mask already exists
952 Archetype* target_archetype = nullptr;
953 auto archetype_it = m_archetype_map.find(new_mask);
954 if (archetype_it != m_archetype_map.end()) {
955 target_archetype = archetype_it->second;
956 } else {
957 // Create a new archetype based on the current one minus the target component
958 target_archetype =
959 Archetype::from_archetype<>(*current_archetype).release();
960 target_archetype->m_mask = new_mask;
961
962 m_archetypes.push_back(std::unique_ptr<Archetype>(target_archetype)
963 );
964 m_archetype_map[new_mask] = target_archetype;
965 }
966
967 current_archetype->move_entity(target_archetype, entity);
968 current_archetype->remove_entity(entity);
969
970 m_entity_archetype_map[entity] = target_archetype;
971 notify_remove(current_archetype->m_mask, entity);
972
973 ++m_query_version;
974 }
975
976 inline void execute_schedule(ScheduleLabel label) {
977 for (const auto& system : get_systems(label)) {
978 system->execute(*this);
979 }
980 // auto it = m_systems.find(label);
981 // if (it != m_systems.end()) {
982 // for (auto& system_ptr : it->second) {
983 // system_ptr->execute(*this);
984 // }
985 // }
986 }
987
988 inline void execute_commands();
989
990 inline void execute_progress() {
991 execute_schedule(ScheduleLabel::Startup);
992 execute_schedule(ScheduleLabel::PreUpdate);
993 execute_schedule(ScheduleLabel::Update);
994 execute_schedule(ScheduleLabel::Validate);
995 execute_schedule(ScheduleLabel::PostUpdate);
996 execute_schedule(ScheduleLabel::PreStore);
997 execute_schedule(ScheduleLabel::Store);
998
999 for (const auto& observer : m_observers) {
1000 observer->clear();
1001 }
1002
1003 execute_commands();
1004
1005 get_systems(ScheduleLabel::Startup).clear();
1006
1007 // auto startup_it = m_systems.find(ScheduleLabel::Startup);
1008 // if (startup_it != m_systems.end()) {
1009 // startup_it->second.clear();
1010 // }
1011 }
1012
1013 Time m_time;
1014 std::chrono::high_resolution_clock::time_point m_last_time;
1015
1016 inline std::vector<std::unique_ptr<TypeErasedSystem>>&
1017 get_systems(ScheduleLabel label) {
1018 return m_systems[static_cast<std::underlying_type_t<ScheduleLabel>>(
1019 label
1020 )];
1021 }
1022
1023 storage::dense_map<
1024 std::underlying_type_t<ScheduleLabel>,
1025 std::vector<std::unique_ptr<TypeErasedSystem>>>
1026 m_systems;
1027
1028 // std::unordered_map<
1029 // ScheduleLabel,
1030 // std::vector<std::unique_ptr<TypeErasedSystem>>>
1031 // m_systems;
1032
1033 std::unordered_map<std::type_index, std::unique_ptr<TypeErasedResource>>
1034 m_resources;
1035
1036 Entity m_current_entity_id {0};
1037 unsigned int m_query_version {0};
1038 std::vector<std::unique_ptr<Archetype>> m_archetypes;
1039 std::unordered_map<ComponentMask, Archetype*> m_archetype_map;
1040 storage::dense_map<Entity, Archetype*> m_entity_archetype_map;
1041 std::vector<std::unique_ptr<TypeErasedObserver>> m_observers;
1042 std::unique_ptr<Commands> m_commands;
1043 std::vector<Entity> m_free_list;
1044};
1045
1046template<typename... Filters>
1048 static ComponentMask evaluate(ComponentMask mask) {
1049 QueryFilter<Filters...> filter;
1050 (Filters::evaluate(mask), ...);
1051 return mask;
1052 }
1053};
1054
1055// template<typename... Components>
1056// struct With {
1057// static void evaluate(ComponentMask& mask) {
1058// mask |= compute_mask<Components...>();
1059// }
1060// };
1061
1062// template<typename... Components>
1063// struct Without {
1064// static void evaluate(ComponentMask& mask) {
1065// mask &= ~compute_mask<Components...>();
1066// }
1067// };
1068
1087template<typename T>
1089 public:
1090 using value_type = T;
1091
1095 Optional() : m_ptr(nullptr) {}
1096
1102 explicit Optional(T* ptr) : m_ptr(ptr) {}
1103
1109 operator bool() const {
1110 return has_value();
1111 }
1112
1118 T& operator*() const {
1119 return get();
1120 }
1121
1127 T& get() const {
1128 assert(has_value() && "Optional is none");
1129 return *m_ptr;
1130 }
1131
1132 T* operator->() {
1133 return m_ptr;
1134 }
1135
1136 T* operator->() const {
1137 return m_ptr;
1138 }
1139
1145 bool has_value() const {
1146 return m_ptr != nullptr;
1147 }
1148
1149 private:
1150 T* m_ptr;
1151};
1152
1153// Forward declaration of primary template
1154template<typename... Args>
1155class Test;
1156
1157// Specialization for Filter version
1158template<typename... Filters, typename... Components>
1159class Test<Filter<Filters...>, Components...> {
1160 private:
1161 template<typename T>
1163
1164 static ComponentMask compute_mask() {
1165 ComponentMask mask;
1166 (add_component_to_mask<Components>(mask), ...);
1167 (apply_filter<Filters>(mask), ...);
1168 return mask;
1169 }
1170
1171 template<typename Component>
1172 static void add_component_to_mask(ComponentMask& mask) {
1174 && !std::is_same_v<Component, Entity>) {
1175 ComponentId id = TypeIDGenerator::get_type_id<Component>();
1176 if (id >= mask.size()) {
1177 mask.resize(id + 1);
1178 }
1179 mask.set(id);
1180 }
1181 }
1182
1183 template<typename Filter>
1184 static void apply_filter(ComponentMask& mask) {
1185 using Traits = filter_traits<Filter>;
1186 if constexpr (Traits::is_with) {
1187 add_component_to_mask<typename Traits::component_type>(mask);
1188 } else if constexpr (Traits::is_without) {
1189 ComponentId id =
1190 TypeIDGenerator::get_type_id<typename Traits::component_type>();
1191 if (id >= mask.size()) {
1192 mask.resize(id + 1);
1193 }
1194 mask.reset(id);
1195 }
1196 }
1197
1198 public:
1199 void describe() {
1200 printf("Components: ");
1201 ((printf("%s ", typeid(Components).name())), ...);
1202 printf("\n");
1203 printf("Filters: ");
1204 ((printf("%s ", typeid(Filters).name())), ...);
1205 printf("\n");
1206
1207 auto mask = compute_mask();
1208 printf("Mask: ");
1209 for (size_t i = 0; i < mask.size(); ++i) {
1210 printf("%d", mask.test(i) ? 1 : 0);
1211 }
1212 printf("\n");
1213 }
1214};
1215
1216// New specialization for components-only version
1217template<typename... Components>
1218class Test {
1219 private:
1220 static ComponentMask compute_mask() {
1221 ComponentMask mask;
1222 (add_component_to_mask<Components>(mask), ...);
1223 return mask;
1224 }
1225
1226 template<typename Component>
1227 static void add_component_to_mask(ComponentMask& mask) {
1229 && !std::is_same_v<Component, Entity>) {
1230 ComponentId id = TypeIDGenerator::get_type_id<Component>();
1231 if (id >= mask.size()) {
1232 mask.resize(id + 1);
1233 }
1234 mask.set(id);
1235 }
1236 }
1237
1238 public:
1239 void describe() {
1240 printf("Components: ");
1241 ((printf("%s ", typeid(Components).name())), ...);
1242 printf("\n");
1243
1244 auto mask = compute_mask();
1245 printf("Mask: ");
1246 for (size_t i = 0; i < mask.size(); ++i) {
1247 printf("%d", mask.test(i) ? 1 : 0);
1248 }
1249 printf("\n");
1250 }
1251};
1252
1253// Deduction guides
1254template<typename... Filters, typename... Components>
1255Test(Filter<Filters...>, Components...)
1256 -> Test<Filter<Filters...>, Components...>;
1257
1258template<typename... Components>
1259Test(Components...) -> Test<Components...>;
1260
1269template<typename... Components>
1270class Query {
1271 public:
1272 template<typename T>
1274
1275 template<typename T>
1276 using ComponentStorageType = typename QueryTypeTraits<T>::StorageType;
1277
1278 using QueryComponents =
1279 std::vector<std::tuple<ComponentStorageType<Components>...>>;
1280
1286 Query(World* world) : m_world(world) {
1287 prepare_query();
1288 }
1289
1290 static ComponentMask compute_mask() {
1291 ComponentMask mask;
1292 (add_component_to_mask<Components>(mask), ...);
1293 return mask;
1294 }
1295
1301 class Iterator {
1302 public:
1303 using iterator_category = std::forward_iterator_tag;
1304 using value_type =
1305 std::tuple<typename QueryTypeTraits<Components>::IterationType...>;
1306 using difference_type = std::ptrdiff_t;
1307 using pointer = std::tuple<
1308 typename QueryTypeTraits<Components>::IterationPointerType...>;
1309 using reference = value_type;
1310
1318 typename QueryComponents::iterator current,
1319 typename QueryComponents::iterator end
1320 ) :
1321 m_current(current),
1322 m_end(end) {}
1323
1330 ++m_current;
1331 return *this;
1332 }
1333
1339 reference operator*() const {
1340 return dereference_tuple(std::index_sequence_for<Components...> {});
1341 }
1342
1349 bool operator!=(const Iterator& other) const {
1350 return m_current != other.m_current;
1351 }
1352
1353 private:
1354 typename QueryComponents::iterator m_current;
1355 typename QueryComponents::iterator m_end;
1356
1357 template<size_t... Is>
1358 reference dereference_tuple(std::index_sequence<Is...>) const {
1359 return std::tuple<
1360 typename QueryTypeTraits<Components>::IterationType...>(
1361 dereference_element<Components>(std::get<Is>(*m_current))...
1362 );
1363 }
1364
1365 template<typename T>
1366 typename QueryTypeTraits<T>::IterationType
1367 dereference_element(typename QueryTypeTraits<T>::StorageType elem
1368 ) const {
1369 return QueryTypeTraits<T>::dereference(elem);
1370 }
1371 };
1372
1379 ensure_up_to_date();
1380 return Iterator(m_components.begin(), m_components.end());
1381 }
1382
1389 return Iterator(m_components.end(), m_components.end());
1390 }
1391
1398 struct Single {
1402 Single() = default;
1403
1409 Single(const std::tuple<Components*...>& components) :
1410 m_state(dereference_tuple(components)) {}
1411
1418 inline std::tuple<Components&...> operator*() {
1419 assert(is_valid() && "Attempted to dereference an invalid Single.");
1420 return std::get<std::tuple<Components&...>>(m_state);
1421 }
1422
1428 inline operator bool() const {
1429 return is_valid();
1430 }
1431
1432 private:
1433 friend class Query;
1434 std::variant<std::monostate, std::tuple<Components&...>> m_state;
1435
1436 template<typename... Ts>
1437 static inline std::tuple<Ts&...>
1438 dereference_tuple(const std::tuple<Ts*...>& pointers) {
1439 return std::apply(
1440 [](auto*... ptrs) { return std::tie(*ptrs...); },
1441 pointers
1442 );
1443 }
1444
1445 inline bool is_valid() const {
1446 return std::holds_alternative<std::tuple<Components&...>>(m_state);
1447 }
1448 };
1449
1455 struct Record {
1456 using RecordComponents =
1457 std::tuple<ComponentStorageType<Components>...>;
1458
1459 Record() = default;
1460
1466 operator bool() const {
1467 return is_valid();
1468 }
1469
1475 inline bool is_valid() const {
1476 return std::holds_alternative<RecordComponents>(m_state);
1477 }
1478
1485 inline auto operator*() const {
1486 assert(is_valid() && "Attempted to dereference an invalid Record.");
1487 return dereference_tuple(std::index_sequence_for<Components...> {});
1488 }
1489
1490 inline auto operator*() {
1491 assert(is_valid() && "Attempted to dereference an invalid Record.");
1492 return dereference_tuple(std::index_sequence_for<Components...> {});
1493 }
1494
1495 private:
1496 friend struct Query;
1497 std::variant<std::monostate, RecordComponents> m_state;
1498
1499 explicit Record(const RecordComponents& components) :
1500 m_state(components) {}
1501
1502 template<size_t... Is>
1503 auto dereference_tuple(std::index_sequence<Is...>) {
1504 auto& components = std::get<RecordComponents>(m_state);
1505 return std::tuple<decltype(QueryTypeTraits<Components>::dereference(
1506 std::get<Is>(components)
1507 ))...>(
1508 QueryTypeTraits<Components>::dereference(std::get<Is>(components
1509 ))...
1510 );
1511 }
1512
1513 template<size_t... Is>
1514 auto dereference_tuple(std::index_sequence<Is...>) const {
1515 const auto& components = std::get<RecordComponents>(m_state);
1516 return std::tuple<
1517 const decltype(QueryTypeTraits<Components>::dereference(
1518 std::get<Is>(components)
1519 ))...>(
1520 QueryTypeTraits<Components>::dereference(std::get<Is>(components
1521 ))...
1522 );
1523 }
1524
1525 template<typename T>
1526 static auto
1527 dereference_element(typename QueryTypeTraits<T>::StorageType elem) {
1528 return QueryTypeTraits<T>::dereference(elem);
1529 }
1530 };
1531
1556 inline Record get(Entity entity) {
1557 auto archetype_it = m_world->m_entity_archetype_map.find(entity);
1558 if (archetype_it == m_world->m_entity_archetype_map.end()) {
1559 return {};
1560 }
1561
1562 World::Archetype* archetype = archetype_it->second;
1563
1565 if (!archetype->has_components(record_mask)) {
1566 return {};
1567 }
1568
1569 return Record(World::Archetype::make_component_tuple<Components...>(
1570 archetype,
1571 entity
1572 ));
1573 }
1574
1597 ensure_up_to_date();
1598
1599 if (m_components.size() != 1) {
1600 return {};
1601 }
1602
1603 return Record(m_components.at(0));
1604 }
1605
1606 private:
1607 World* m_world {nullptr};
1608 QueryComponents m_components;
1609 unsigned int m_query_version {0};
1610
1611 void ensure_up_to_date();
1612
1613 void prepare_query();
1614
1615 template<typename Component>
1616 static void add_component_to_mask(ComponentMask& mask) {
1617 if constexpr (!_traits::is_optional<Component>::value
1618 && !std::is_same_v<Component, Entity>) {
1619 ComponentId id = TypeIDGenerator::get_type_id<Component>();
1620 if (id >= mask.size()) {
1621 mask.resize(id + 1);
1622 }
1623 mask.set(id);
1624 }
1625 }
1626
1627 template<typename T>
1628 static decltype(auto) dereference_if_needed(T&& arg) {
1629 return QueryTypeTraits<std::remove_reference_t<T>>::dereference(
1630 std::forward<T>(arg)
1631 );
1632 }
1633};
1634
1640 public:
1644 EntityBuilder() = delete;
1645
1651 template<typename... Components>
1652 bool has() const {
1653 auto it = m_world->m_entity_archetype_map.find(m_id);
1654 if (it == m_world->m_entity_archetype_map.end()) {
1655 return false;
1656 }
1657 auto archetype = it->second;
1658 return archetype->has_components<Components...>();
1659 }
1660
1665 operator Entity() {
1666 return m_id;
1667 }
1668
1669 void despawn() {
1670 m_world->despawn(m_id);
1671 }
1672
1679 template<typename... Components>
1680 EntityBuilder& insert(Components&&... components) {
1681 auto components_tuple =
1682 std::make_tuple(std::forward<Components>(components)...);
1683 auto flat_tuple = flatten_tuple(std::move(components_tuple));
1684
1685 // m_world->add_components(m_id, std::forward<Components>(components)...);
1686 std::apply(
1687 [this](auto&&... flat_comps) {
1688 m_world->add_components(
1689 m_id,
1690 std::forward<decltype(flat_comps)>(flat_comps)...
1691 );
1692 },
1693 flat_tuple
1694 );
1695 return *this;
1696 }
1697
1698 template<typename Component>
1699 EntityBuilder& remove() {
1700 m_world->remove_component<Component>(m_id);
1701 return *this;
1702 }
1703
1710 template<typename Func>
1712 EntityBuilder new_builder = m_world->spawn();
1713 EntityBuilder ret_builder = func(new_builder);
1714 ret_builder.insert(Parent {m_id});
1715
1716 return *this;
1717 }
1718
1724 EntityBuilder& add_child(Entity entity) {
1725 EntityBuilder(m_world, entity).insert(Parent {m_id});
1726 return *this;
1727 }
1728
1735 template<typename... Components>
1736 EntityBuilder& insert_child(Components&&... components) {
1737 auto child =
1738 m_world->spawn().insert(std::forward<Components>(components)...);
1739 add_child(child);
1740 return *this;
1741 }
1742
1743 private:
1744 friend class World;
1745 friend class EntityCommands;
1746
1747 EntityBuilder(World* world, Entity entity) : m_id(entity), m_world(world) {}
1748
1749 // Used for flattening bundle component
1750 template<typename Tuple>
1751 static auto flatten_tuple(Tuple&& t) {
1752 return flatten_tuple_impl(
1753 std::forward<Tuple>(t),
1754 std::make_index_sequence<
1755 std::tuple_size<std::decay_t<Tuple>>::value> {}
1756 );
1757 }
1758
1759 template<typename Tuple, std::size_t... Is>
1760 static auto flatten_tuple_impl(Tuple&& t, std::index_sequence<Is...>) {
1761 return std::tuple_cat(
1762 flatten_element(std::get<Is>(std::forward<Tuple>(t)))...
1763 );
1764 }
1765
1766 template<typename T>
1767 static auto flatten_element(T&& t) {
1768 if constexpr (_traits::is_bundle_v<T>) {
1769 return flatten_tuple(std::forward<T>(t).components);
1770 } else {
1771 return std::make_tuple(std::forward<T>(t));
1772 }
1773 }
1774
1775 World* m_world {nullptr};
1776 Entity m_id;
1777};
1778
1786 public:
1796 template<typename... Components>
1797 EntityCommands& insert(Components&&... components);
1798
1799 template<typename Component>
1800 EntityCommands& remove() {
1801 Entity entity = m_entity;
1802 // util::commands_add(m_commands, [entity](World& world) {
1803 // EntityBuilder(&world, entity).remove<Component>();
1804 // });
1805 return *this;
1806 }
1807
1808 operator Entity() {
1809 return m_entity;
1810 }
1811
1812 EntityCommands& add_child(Entity entity);
1813
1814 template<typename... Components>
1815 EntityCommands& insert_child(Components&&... components);
1816
1817 template<typename Func>
1818 EntityCommands& with_children(Func&& func);
1819
1825 void despawn();
1826
1827 private:
1828 friend class Commands;
1829
1830 EntityCommands(Commands& commands, Entity entity) :
1831 m_commands(commands),
1832 m_entity(entity) {}
1833
1834 Commands& m_commands;
1835 Entity m_entity;
1836};
1837
1838class Command {
1839 public:
1840 template<typename F>
1841 explicit Command(F&& f) :
1842 m_cmd(std::make_unique<Model<std::decay_t<F>>>(std::forward<F>(f))) {}
1843
1844 Command(const Command&) = delete;
1845 Command& operator=(const Command&) = delete;
1846 Command(Command&&) noexcept = default;
1847 Command& operator=(Command&&) noexcept = default;
1848
1849 void execute(World& world) {
1850 m_cmd->execute(world);
1851 }
1852
1853 private:
1854 struct Concept {
1855 virtual ~Concept() = default;
1856 virtual void execute(World& world) = 0;
1857 };
1858
1859 template<typename F>
1860 struct Model: Concept {
1861 F f;
1862
1863 explicit Model(F&& f_) : f(std::move(f_)) {}
1864
1865 void execute(World& world) override {
1866 f(world);
1867 }
1868 };
1869
1870 std::unique_ptr<Concept> m_cmd;
1871};
1872
1881 public:
1882 Commands(World& world) : m_world(world) {}
1883
1884 Commands(const Commands&) = delete;
1885 Commands& operator=(const Commands&) = delete;
1886 Commands(Commands&&) noexcept = default;
1887 Commands& operator=(Commands&&) noexcept = delete;
1888
1894 template<typename Func>
1895 void add(Func&& func) {
1896 m_commands.emplace_back(std::forward<Func>(func));
1897 }
1898
1908 Entity entity = m_world.spawn();
1909 return EntityCommands(*this, entity);
1910 }
1911
1922 return EntityCommands(*this, entity);
1923 }
1924
1925 private:
1926 friend class World;
1927
1928 void apply() {
1929 std::vector<Command> commands_to_execute;
1930 std::swap(commands_to_execute, m_commands);
1931
1932 for (auto& command : commands_to_execute) {
1933 command.execute(m_world);
1934 }
1935 }
1936
1937 private:
1938 World& m_world;
1939 std::vector<Command> m_commands;
1940};
1941
1942template<typename... Components>
1943EntityCommands& EntityCommands::insert(Components&&... components) {
1944 m_commands.add([entity = m_entity,
1945 tuple_components =
1946 std::make_tuple(std::forward<Components>(components)...
1947 )](World& world) mutable {
1948 std::apply(
1949 [&world, entity](auto&&... comps) {
1950 EntityBuilder(&world, entity).insert(std::move(comps)...);
1951 },
1952 tuple_components
1953 );
1954 });
1955 return *this;
1956}
1957
1958// template<typename... Components>
1959// EntityCommands& EntityCommands::insert(Components&&... components) {
1960// Entity entity = m_entity;
1961
1962// std::tuple<std::decay_t<Components>...> components_copy(
1963// std::forward<Components>(components)...
1964// );
1965
1966// m_commands.add([entity = m_entity,
1967// components_copy =
1968// std::move(components_copy)](World& world) mutable {
1969// std::apply(
1970// [&world, entity](auto&&... comps) {
1971// EntityBuilder(&world, entity).insert(std::move(comps)...);
1972// },
1973// components_copy
1974// );
1975// });
1976
1977// return *this;
1978// }
1979
1980template<typename Func>
1981EntityCommands& EntityCommands::with_children(Func&& func) {
1982 m_commands.add([entity = m_entity,
1983 func = std::forward<Func>(func)](World& world) mutable {
1984 EntityBuilder(&world, entity).with_children(std::forward<Func>(func));
1985 });
1986
1987 return *this;
1988}
1989
1990template<typename... Components>
1991EntityCommands& EntityCommands::insert_child(Components&&... components) {
1992 std::tuple<std::decay_t<Components>...> components_copy(
1993 std::forward<Components>(components)...
1994 );
1995
1996 m_commands.add([entity = m_entity,
1997 components_copy =
1998 std::move(components_copy)](World& world) {
1999 std::apply(
2000 [&world, entity](auto&&... comps) {
2001 EntityBuilder(&world, entity).insert_child(std::move(comps)...);
2002 },
2003 components_copy
2004 );
2005 });
2006 return *this;
2007}
2008
2009inline Commands& World::commands() {
2010 return *m_commands.get();
2011}
2012
2013inline void World::execute_commands() {
2014 m_commands->apply();
2015}
2016
2017template<typename... Components>
2018void Query<Components...>::prepare_query() {
2019 ComponentMask query_mask = Query<Components...>::compute_mask();
2020
2021 m_components.clear();
2022 for (const auto& archetype : m_world->m_archetypes) {
2023 if (archetype->m_mask.contains(query_mask)) {
2024 for (const auto& [entity, index] : archetype->m_entity_to_index) {
2025 m_components.emplace_back(
2026 World::Archetype::make_component_tuple<Components...>(
2027 archetype.get(),
2028 entity
2029 )
2030 );
2031 }
2032 }
2033 }
2034 m_query_version = m_world->m_query_version;
2035}
2036
2037template<typename... Components>
2038void Query<Components...>::ensure_up_to_date() {
2039 if (m_query_version != m_world->m_query_version) {
2040 prepare_query();
2041 }
2042}
2043
2056template<typename T>
2058 static_assert(
2059 sizeof(T) == -1,
2060 "into_system_param not specialized for this type"
2061 );
2062};
2063
2072template<typename T>
2074
2083template<typename T>
2085
2086// Built-in system parameters
2087
2099template<typename T>
2100struct Local {
2107 return m_data;
2108 }
2109
2110 private:
2111 T m_data;
2112};
2113
2123template<typename T>
2136 static Local<T> get(World&) {
2137 return Local<T> {};
2138 }
2139};
2140
2141template<>
2142struct into_system_param<const Time&> {
2143 static const Time& get(World& world) {
2144 auto time = world.get_resource<Time>();
2145 return *time;
2146 }
2147};
2148
2157template<typename T>
2164 static Resource<T> get(World& world) {
2165 return world.get_resource<T>();
2166 }
2167};
2168
2178template<typename... Components>
2179struct into_system_param<Query<Components...>> {
2189 static Query<Components...> get(World& world) {
2190 return Query<Components...>(&world);
2191 }
2192};
2193
2203template<typename... Components>
2204struct into_system_param<const Observer<Components...>&> {
2205 static const Observer<Components...>& get(World& world) {
2216 return world.observe<Components...>();
2217 }
2218};
2219
2220template<>
2222 static Commands& get(World& world) {
2223 return world.commands();
2224 }
2225};
2226
2227template<typename Tuple>
2229
2230template<typename... Args>
2231struct get_system_params_helper<std::tuple<Args...>> {
2232 static auto get(World& world) {
2233 return std::make_tuple(
2234 wrap_param<Args>(into_system_param<Args>::get(world))...
2235 );
2236 }
2237
2238 private:
2239 template<typename T, typename ParamT>
2240 static auto wrap_param(ParamT&& param) {
2241 if constexpr (std::is_reference_v<ParamT>) {
2242 return std::ref(param);
2243 } else {
2244 return std::forward<ParamT>(param);
2245 }
2246 }
2247};
2248
2249template<typename Tuple>
2250auto get_system_params(World& world) {
2252}
2253
2254} // namespace vecs
2255
2256#endif
Definition vecs.h:1838
Provides a deferred command interface to manage entity operations within the ECS world.
Definition vecs.h:1880
EntityCommands entity(Entity entity)
Provides an EntityCommands interface to manage commands for an existing entity.
Definition vecs.h:1921
void add(Func &&func)
Adds a deferred command to be executed on the world.
Definition vecs.h:1895
EntityCommands spawn()
Spawns a new entity and provides a deferred interface to add components to it.
Definition vecs.h:1907
Provides methods to construct and modify entities within the ECS world.
Definition vecs.h:1639
bool has() const
Checks if the entity has all specified components.
Definition vecs.h:1652
EntityBuilder & with_children(Func &&func)
Spawns a new entity, allows modifications via a function, and assigns it as a child of the current en...
Definition vecs.h:1711
EntityBuilder & add_child(Entity entity)
Adds an existing entity as a child of the current entity.
Definition vecs.h:1724
EntityBuilder & insert_child(Components &&... components)
Spawns a new entity, inserts components, and assigns it as a child of the current entity.
Definition vecs.h:1736
EntityBuilder()=delete
Deleted default constructor to prevent creating an EntityBuilder without parameters.
EntityBuilder & insert(Components &&... components)
Inserts components into the entity.
Definition vecs.h:1680
Provides a deferred command interface for managing a specific entity's state within the ECS world.
Definition vecs.h:1785
EntityCommands & insert(Components &&... components)
Adds a deferred command to insert components into the entity.
Definition vecs.h:1943
void despawn()
Adds a deferred command to despawn the entity.
Definition vecs.h:33
Observer class for tracking component changes within a system.
Definition vecs.h:261
const std::vector< Entity > & removed() const override
Retrieves the entities that have been had the observed components removed.
Definition vecs.h:307
Observer()
Constructs an Observer for the specified components.
Definition vecs.h:268
const std::vector< Entity > & inserted() const override
Retrieves the entities that have been inserted with the observed components.
Definition vecs.h:295
const std::vector< Entity > & added() const override
Retrieves the entities that have been added for the first time with the observed components.
Definition vecs.h:283
Provides an interface for interacting with optional components.
Definition vecs.h:1088
Optional()
Constructs an empty Optional with no value.
Definition vecs.h:1095
bool has_value() const
Checks if a value is present.
Definition vecs.h:1145
T & get() const
Returns a reference to the contained value.
Definition vecs.h:1127
Optional(T *ptr)
Constructs an Optional that holds a pointer to a value.
Definition vecs.h:1102
T & operator*() const
Dereferences the contained value.
Definition vecs.h:1118
Iterator for iterating over entities matching the query.
Definition vecs.h:1301
Iterator(typename QueryComponents::iterator current, typename QueryComponents::iterator end)
Constructs an iterator for the query.
Definition vecs.h:1317
Iterator & operator++()
Advances the iterator to the next entity.
Definition vecs.h:1329
reference operator*() const
Dereferences the iterator to access the current entity's components.
Definition vecs.h:1339
bool operator!=(const Iterator &other) const
Compares two iterators for inequality.
Definition vecs.h:1349
Represents a query for components within the ECS world.
Definition vecs.h:1270
Record get_single()
Retrieves the components of a single entity matching the query.
Definition vecs.h:1596
Record get(Entity entity)
Retrieves the components of an entity matching the query.
Definition vecs.h:1556
Iterator begin()
Returns an iterator to the beginning of the query results.
Definition vecs.h:1378
Iterator end()
Returns an iterator to the end of the query results.
Definition vecs.h:1388
Query(World *world)
Constructs a Query to search for entities with specified components.
Definition vecs.h:1286
Definition vecs.h:1218
Definition vecs.h:220
The ECS world.
Definition vecs.h:361
void progress(float delta_time)
Progresses the ECS world by one tick, with a supplied delta time.
Definition vecs.h:463
Resource< T > & get_resource() const
Retrieves a non-owned resource of type T.
Definition vecs.h:394
World & add_resource(T *resource)
Adds a non-owned resource to the world.
Definition vecs.h:379
void add_system(Func &&func)
Adds a system to the Update schedule.
Definition vecs.h:443
void add_system(ScheduleLabel label, Func &&func)
Adds a system to the specified schedule.
Definition vecs.h:418
void progress()
Progresses the ECS world by one tick, with automatically calculated delta time.
Definition vecs.h:450
A dynamic bitset that automatically grows to support an arbitrary number of bits.
Definition dynamic_bitset.h:19
Definition vecs.h:69
Definition vecs.h:66
Definition vecs.h:81
A collection of components grouped together as a single bundle.
Definition vecs.h:171
A container for local data specific to a system.
Definition vecs.h:2100
T & operator*()
Dereferences the local data, providing access to the stored value.
Definition vecs.h:2106
Definition vecs.h:146
A container for a single record and its components, as a result of a query.
Definition vecs.h:1455
auto operator*() const
Dereferences the record.
Definition vecs.h:1485
bool is_valid() const
Checks if the Record is valid.
Definition vecs.h:1475
A container for a single entity and its components, as a result of a query.
Definition vecs.h:1398
Single(const std::tuple< Components *... > &components)
Constructs a valid Single result from a tuple of component pointers.
Definition vecs.h:1409
std::tuple< Components &... > operator*()
Dereferences the components.
Definition vecs.h:1418
Single()=default
Default constructor for an invalid state.
Definition vecs.h:1047
A non-owning wrapper around a resource of type T.
Definition vecs.h:193
Resource(T *ptr)
Constructs a non-owning Resource wrapper for a given pointer.
Definition vecs.h:198
Definition vecs.h:353
Definition vecs.h:179
Definition vecs.h:27
Definition vecs.h:30
Definition vecs.h:2228
static Local< T > get(World &)
Retrieves a persistent instance of Local<T> for system use.
Definition vecs.h:2136
static Query< Components... > get(World &world)
Retrieves a Query<Components...> from the world.
Definition vecs.h:2189
static Resource< T > get(World &world)
Fetches Resource<T> from the world.
Definition vecs.h:2164
static const Observer< Components... > & get(World &world)
Definition vecs.h:2205
A template for converting types into system parameters.
Definition vecs.h:2057
ScheduleLabel
Labels for predefined execution phases of systems within the ECS World
Definition vecs.h:158