Entity Component System



  • Hallo 🙂
    Hab mich unter Zuhilfenahme von diversen Artikeln und Videos mal an einem sehr einfachen "ECS" versucht. In folgendem seht ihr eine Klasse namens "ComponentManager" ( wenn euch ein besserer Name einfällt, dankeschön 😃 ).
    Dieser wird später einem Entity, das lediglich aus einem unsigned integer besteht ( std::size_t ), in einer Map zugewiesen.

    std::map < EntityId /* using EntityId = std::size_t */, std::unique_ptr< ComponentManager> > entities_;
    

    Wollte einfach einmal eure Meinungen bzw. Verbesserungsvorschläge von euch hören. 🙂

    #ifndef COMPONENT_MANAGER_H
    #define COMPONENT_MANAGER_H
    
    #include <bitset>
    #include <map>
    #include <memory>
    #include <type_traits>
    
    #include "ComponentInterface.h"
    
    #define MAX_COMPONENTS 32
    
    using ComponentId = std::size_t;
    
    class ComponentManager
    {
    public:
    	ComponentManager();
    	~ComponentManager();
    
    	template < typename ComponentType >
    	bool hasComponent() const
    	{
    		return componentBitset_.at(getComponentTypeId<ComponentType>());
    	}
    
    	template < typename ComponentType >
    	ComponentType& addComponent()
    	{
    		if (!hasComponent<ComponentType>())
    		{
    			auto typeId = getComponentTypeId<ComponentType>();
    
    			components_.emplace(typeId, std::make_shared<ComponentType>());
    
    			componentBitset_.at(typeId) = true;
    
    			return *(std::static_pointer_cast<ComponentType>(components_.at(typeId)));
    		}
    			// ERR_INVALID_COMPONENT_TYPE
    	}
    
    	template < typename ComponentType >
    	ComponentType& getComponent()
    	{
    		if (hasComponent<ComponentType>())
    		{
    			return *(std::static_pointer_cast<ComponentType>(components_.at(getComponentTypeId<ComponentType>())));
    		}
    			// ERR_INVALID_COMPONENT_TYPE
    	}
    
    private:
    	inline ComponentId createUniqueComponentId() const
    	{
    		static ComponentId lastId{ 0u };
    		return lastId++;
    	}
    
    	template < typename ComponentType >
    	inline ComponentId getComponentTypeId() const 
    	{
    		if (std::is_base_of<ComponentInterface, ComponentType>::value)
    		{
    			static ComponentId typeId =  createUniqueComponentId();
    			return typeId;
    		}
    			// ERR_INVALID_COMPONENT_TYPE
    	}
    
    	std::bitset<MAX_COMPONENTS> componentBitset_;
    
    	std::map<ComponentId, std::shared_ptr<ComponentInterface>> components_;
    
    }; // class ComponentManager
    
    #endif // COMPONENT_MANAGER_H
    

    Und so kann man das ganze dann benutzen :

    #include <iostream>
    
    #include "ComponentManager.h"
    
    struct ComponentHealth : public ComponentInterface
    {
    	float Health;
    };
    
    struct ComponentPosition : public ComponentInterface
    {
    	float X;
    	float Y;
    };
    
    int main()
    {
    	ComponentManager m;
    	ComponentManager m2;
    
    	auto& handle = m.addComponent<ComponentHealth>();
    
    	handle.Health = 200;
    
    	std::cout << m.getComponent<ComponentHealth>().Health << std::endl;
    
    	auto& handle_2 = m2.addComponent<ComponentPosition>();
    
    	handle_2.X = 400;
    	handle_2.Y = 500;
    
    	std::cout << m2.getComponent<ComponentPosition>().X << std::endl;
    	std::cout << m2.getComponent<ComponentPosition>().Y << std::endl;
    
    	auto& handle_3 = m2.addComponent<ComponentHealth>();
    
    	handle_3.Health = 600;
    
    	std::cout << m2.getComponent<ComponentHealth>().Health << std::endl;
    
    	std::getchar();
    
    	return EXIT_SUCCESS;
    }
    

    Im vornherein schon einmal danke ! 👍


Anmelden zum Antworten