Reputation: 93
I am trying to implement a toy ECS for a hobby engine, and am following a small tutorial to kick-start it. An extremely bare-bones implementation using the tutorial is the following
#pragma once
#include <assert.h>
#include <list>
#include <string>
#include <memory>
#include <unordered_map>
#include <entity.hpp>
using ComponentType = std::size_t;
const ComponentType MAX_COMPONENTS = 64000;
class Component
{
public:
Component() = default;
};
class IComponentArray
{
public:
virtual ~IComponentArray() = default;
virtual void EntityDestroyed(Entity entity) = 0;
};
template <typename T>
class ComponentArray : IComponentArray
{
private:
std::size_t size{};
std::list<T> componentList{};
std::unordered_map<Entity, size_t> entityToIndexMap{};
std::unordered_map<size_t, Entity> indexToEntityMap{};
public:
ComponentArray() = default;
void insertData(Entity entity, T component)
{
assert(this->entityToIndexMap.find(entity) == this->entityToIndexMap.end()
&& "Component added to same entity twice!");
size_t newIndex = this->size;
this->entityToIndexMap[entity] = newIndex;
this->indexToEntityMap[newIndex] = entity;
this->componentList[newIndex] = component;
++this->size;
}
void removeData(Entity entity)
{
assert(this->entityToIndexMap.find(entity) != this->entityToIndexMap.end()
&& "Removing non-existant component!");
size_t removedEntityIndex = this->entityToIndexMap[entity];
size_t lastElementIndex = this->size - 1;
Entity lastElementEntity = indexToEntityMap[lastElementIndex];
entityToIndexMap[lastElementEntity] = removedEntityIndex;
indexToEntityMap[removedEntityIndex] = lastElementEntity;
entityToIndexMap.erase(entity);
indexToEntityMap.erase(lastElementIndex);
}
T& getData(Entity entity)
{
assert(this->entityToIndexMap.find(entity) != entityToIndexMap.end()
&& "Retrieved non-existant component!");
return this->componentList[entityToIndexMap[entity]];
}
void destroyEntity(Entity entity)
{
if (entityToIndexMap.find(entity) != entityToIndexMap.end())
this->removeData(entity);
}
};
class ComponentManager
{
private:
std::unordered_map<std::string, ComponentType> componentTypes{};
std::unordered_map<std::string, std::shared_ptr<IComponentArray>> componentArrays{};
ComponentType nextComponentType{};
public:
template <typename T>
void registerComponent()
{
std::string typeName = std::string(typeid(T).name());
assert(this->componentTypes.find(typeName) == this->componentTypes.end()
&& "Registering component type more than once!");
componentTypes.insert({typeName, nextComponentType});
componentArrays.insert({typeName, std::make_shared<ComponentArray<T>>()});
++this->nextComponentType;
}
};
However, when compiling the code, I run into issues with the registerComponent
method in ComponentManager
.
struct Transform3D
{
Vector3 position;
};
int main() {
ComponentManager manager;
manager.registerComponent<Transform3D>();
}
When commenting or removing the registerComponent
line in the second code snippet, the compiler generates no issues, however when uncommenting that line, it spits out a wall of errors, with the top of it saying
no matching function for call to ‘std::unordered_map<std::__cxx11::basic_string<char>, std::shared_ptr<IComponentArray> >::insert(<brace-enclosed initializer list>)’
componentArrays.insert({typeName, std::make_shared<ComponentArray<T>>()});
I have attempted to use something like a pointer to IComponentArray, instead of shared pointers, however, the same error still occurs.
Upvotes: 1
Views: 30
Reputation: 409422
That's because std::make_shared<ComponentArray<T>>()
returns an object of type std::shared_ptr<ComponentArray<T>>
, which doesn't match the data-type of the map.
As a simple solution, define a temporary variable of the right type, initialize it using the make_shared
call, and use that variable when inserting the entry into the map:
std::shared_ptr<IComponentArray> array = std::make_shared<ComponentArray<T>>();
componentArrays.insert({typeName, array});
Upvotes: 1