SamL
(usa XUbuntu)
Enviado em 10/01/2023 - 12:32h
#ifndef ECS_HPP
#define ECS_HPP
#include <vector>
#include <memory>
#include <unordered_map>
template<class T>
struct Component {
std::shared_ptr<T> component;
};
struct ECS {
private:
//formato <int=entidade, componentesEntidade>
std::unordered_map<int, std::vector<Component>> entities;
public:
template <typename T>
T* get (int id) {
if (id == 0)
return nullptr;
int i = 0;
for (auto it: entities[id]) {
auto ptr = reinterpret_cast<T*>(it.component.get());
if (ptr)
return ptr;
}
return nullptr;
}
bool has (int id) {
return entities.find(id) != entities.end();
}
template<typename T, typename ... Args>
void emplace(int id, Args ... args) {
if (id <= 0)
return;
std::shared_ptr<T> ptr(new T(args...));
entities[id].push_back(std::move(ptr));
}
int create() {
entities[entities.size() + 1];
return entities.size();
}
template <class T>
void some(std::function<bool(T *)> func) {
for (auto it: entities) {
for (auto comp: it.second) {
auto ptr = std::any_cast<T*>(comp.get());
if (ptr && func(ptr))
return;
}
}
}
template <class T>
void each(std::function<void(T *)> func) {
for (auto it: entities) {
for (auto comp: it.second) {
auto ptr = std::any_cast<T*>(comp.get());
if (ptr) {
func(ptr);
}
}
}
}
void destroy(int id) {
if (has(id)) {
entities.erase(id);
}
}
};
#endif
//regsitry:
struct RegistryStruct {
ECS * ecs;
int id = 0;
RegistryStruct() {
ecs = nullptr;
id = 0;
}
RegistryStruct(ECS *_ecs, int _id): ecs(_ecs), id(_id) {
}
void print () {
std::cout<<"RegistryStruct: ecs = "<<ecs<<" id = "<<id<<"\n";
}
};
template<typename T>
bool hasComponent(RegistryStruct ®, bool throwOnError = true) {
return reg.ecs && reg.ecs->has(reg.id) && reg.ecs->template get<T>();
}
template<class T>
T * getComponent(RegistryStruct ®, bool throwOnError = true) {
if (!hasComponent<T>(reg)) {
if (throwOnError)
std::runtime_error(std::string("Não Existe ")+typeid(T).name());
return nullptr;
}
auto it = reg.ecs->template get<T>(reg.id);
return (it);
}
template<typename T>
T * addComponent(RegistryStruct ®) {
if (!reg.ecs->has(reg.id)) {
throw std::runtime_error("Entity é nula!");
}
auto entity = reg.id;
(reg.ecs->template emplace<T>(entity));
return const_cast<T*>(reg.ecs->get<T>(entity));
}
template<typename T, typename ... Args>
T * addComponent(RegistryStruct ®, Args && ... args) {
if (!reg.ecs->has(reg.id)) {
throw std::runtime_error("Entity é nula!");
}
auto entity = reg.id;
reg.ecs->emplace<T, Args...>(entity, args...);
return const_cast<T *>(reg.ecs->template get<T>(reg.id));
}
Fica melhor com um exemplo:
1-ali é minha classe de ECS (quebrada)
2-uso funções templates pra adicionar ou remover compoents.
3-cada component é de um tipo diferente, logo, não é possível ter um map tipo <int,Component<Sprite>> sendo que não existe, ainda, o tipo Sprite.
4-exemplo de uso:
-crio uma classe chamada Sprite
-adiciono um component spirte a um RegistryStruct assim:
auto reg = ecs->create();
//adiciona um componente Sprite ao reg
auto sprite = addComponent<Sprite>(reg, param1, param2, param3);
O meu problema é que não sei usar template com shared_ptr pra ter um ponteiro que varie de acordo com o tipo passado e então guarde ele numa struct Component.
Alguma ideia do que fazer pra ter uma solução mais elegante?