NasNas
An intuitive and beginner friendly 2D game framework for C++
View.hpp
1 // Created by Modar Nasser on 17/08/2021.
2 
3 #pragma once
4 
5 #include <algorithm>
6 #include <array>
7 #include <functional>
8 #include <tuple>
9 
10 #include <NasNas/ecs/Storage.hpp>
11 
12 namespace ns::ecs::detail {
13 
14  template<typename TEntity, typename... TComps>
15  struct components_view {
16  using components_pool_super = typename components_pool<TEntity>::super;
17  const components_pool_super* ref_set;
18  const std::tuple<components_pool<TEntity, TComps>*...> pools;
19 
20  components_view(components_pool<TEntity, TComps>&... components) : pools(&components...) {
21  std::array<components_pool_super*, sizeof...(TComps)> pools_vec = {
22  static_cast<components_pool_super*>(std::get<components_pool<TEntity, TComps>*>(pools))...
23  };
24  std::sort(pools_vec.begin(), pools_vec.end(), [] (auto* lhs, auto* rhs) {return lhs->size() < rhs->size();});
25  ref_set = pools_vec[0];
26  }
27 
28  template<typename... Comps>
29  auto get(const TEntity ent) const -> decltype(auto) {
30  if constexpr(sizeof...(Comps) == 0) {
31  return std::tuple_cat(std::forward_as_tuple(std::get<components_pool<TEntity, TComps>*>(pools)->get(ent))...);
32  } else if constexpr(sizeof...(Comps) == 1) {
33  return (std::get<components_pool<TEntity, Comps> *>(pools)->get(ent), ...);
34  } else {
35  return std::tuple_cat(std::forward_as_tuple(std::get<components_pool<TEntity, Comps>*>(pools)->get(ent))...);
36  }
37  }
38 
39  auto for_each(std::function<void(Entity, TComps&...)> fn) {
40  for (auto& ent : ref_set->data()) {
41  if ((std::get<components_pool<TEntity, TComps>*>(pools)->contains(ent) && ...)) {
42  auto&& comps_tuple = std::forward_as_tuple((std::get<components_pool<TEntity, TComps>*>(pools)->get(ent))...);
43  std::apply(fn, std::tuple_cat(std::make_tuple(ent), comps_tuple));
44  }
45  }
46  }
47 
48  auto for_each(std::function<void(Entity)> fn) {
49  for (auto& ent : ref_set->data()) {
50  if ((std::get<components_pool<TEntity, TComps>*>(pools)->contains(ent) && ...)) {
51  std::apply(fn, std::make_tuple(ent));
52  }
53  }
54  }
55 
56  auto for_each(std::function<void(TComps&...)> fn) {
57  for (auto& ent : ref_set->data()) {
58  if ((std::get<components_pool<TEntity, TComps>*>(pools)->contains(ent) && ...)) {
59  auto&& comps_tuple = std::forward_as_tuple((std::get<components_pool<TEntity, TComps>*>(pools)->get(ent))...);
60  std::apply(fn, comps_tuple);
61  }
62  }
63  }
64 
65  auto for_each_pair(std::function<void(Entity, Entity)> fn) {
66  for (auto it1 = ref_set->data().begin(); it1 != ref_set->data().end(); ++it1) {
67  if ((std::get<components_pool<TEntity, TComps>*>(pools)->contains(*it1) && ...)) {
68  for (auto it2 = it1+1; it2 != ref_set->data().end(); ++it2) {
69  if ((std::get<components_pool<TEntity, TComps>*>(pools)->contains(*it2) && ...))
70  std::apply(fn, std::make_tuple(*it1, *it2));
71  }
72  }
73  }
74  }
75  };
76 
77 }