Entity Component System | Visitor Pattern



  • Hallo,
    hab mich mal an einem einfachen ECS probiert und wollte einfach ein wenig Feedback bevor ich weiter an dem Code arbeite 😃 "ConcreteComponent/ -System/ -Builder sind nur zum Testen dar und haben keinen tieferen Sinn.

    Außerdem frage ich mich, ob es möglich ist aus ConcreteBuilder eine abstrakte Klasse zu machen. Allerdings stoße ich dann auf das Problem, dass die Parameter der Funktion BuildEntity nicht mehr variabel sind, da sie alle die virtuelle Methode BuildEntity überschreiben müssen. Als Lösung für das Problem hab ich was von einem Visitor Pattern gelesen, verstehe das aber nicht ganz 😃 Wäre nett wenn mir das jemand erklären könnte.

    #include <algorithm>
    #include <array>
    #include <bitset>
    #include <chrono>
    #include <iostream>
    #include <memory>
    #include <string>
    #include <vector>
    
    struct AbstractComponent
    {
    	virtual ~AbstractComponent(){};
    };
    
    struct ConcreteComponentOne : public AbstractComponent
    {
    	ConcreteComponentOne(int i = 0, float f = 0.f, bool b = false) : an_integer{ i }, a_floating_point{ f }, a_boolean{ b }{}
    
    	int   an_integer;
    	float a_floating_point;
    	bool  a_boolean;
    };
    
    struct Entity
    {
    	bool alive_ = true;
    
    	array  < AbstractComponent*, 32 >           handles_; 
    	vector < unique_ptr < AbstractComponent > > components_;
    	bitset < 32 >                               signature_;
    };
    
    namespace Internal
    {
    	inline size_t CreateUniqueComponentId()
    	{
    		static size_t kLastComponentId{ 0u };
    		return kLastComponentId++;
    	}
    }
    
    template < typename TComponent >
    inline size_t GetComponentTypeId()
    {
    	static size_t kComponentTypeId{ Internal::CreateUniqueComponentId() };
    	return kComponentTypeId;
    }
    
    class EntityManager
    {
    public:
    	Entity& AddEntity()
    	{
    		entities_.emplace_back(make_unique<Entity>());
    		return *entities_.back();
    	}
    
    	vector < unique_ptr < Entity > >& GetEntities()
    	{
    		return entities_;
    	}
    
    	void Update()
    	{
    		entities_.erase(remove_if(begin(entities_), end(entities_), [](unique_ptr < Entity >& entity){ return !entity->alive_; }), end(entities_));
    	}
    
    private:
    	vector < unique_ptr < Entity > > entities_;
    };
    
    class ConcreteEntityBuilder 
    {
    public:
    	void BuildEntity(EntityManager& manager, int i, float f, bool b ) 
    	{
    		Entity& h_entity{ manager.AddEntity() };
    
    		h_entity.components_.emplace_back(make_unique<ConcreteComponentOne>(i, f, b));
    
    		h_entity.handles_  [GetComponentTypeId<ConcreteComponentOne>()] = h_entity.components_.back().get();
    		h_entity.signature_[GetComponentTypeId<ConcreteComponentOne>()] = true;
    	}
    };
    
    class AbstractSystem
    {
    public:
    	virtual ~AbstractSystem(){}
    
    	virtual void Update(EntityManager& manager, float delta_time) = 0;
    
    	virtual void UpdateFixed(EntityManager& manager) = 0;
    
    protected:
    	bitset < 32 > signature_;
    };
    
    class ConcreteSystem : public AbstractSystem
    {
    public:
    	ConcreteSystem()
    	{
    		signature_[GetComponentTypeId<ConcreteComponentOne>()] = true;
    	}
    
    	void Update(EntityManager& manager, float delta_time) override
    	{
    
    	}
    
    	void UpdateFixed(EntityManager& manager) override
    	{
    		vector<unique_ptr<Entity>>& h_entities{ manager.GetEntities() };
    
    		for (auto& i : h_entities)
    		{
    			if (signature_ == (signature_ & i->signature_))
    			{
    				auto& h_component = *dynamic_cast<ConcreteComponentOne*>(i->handles_[GetComponentTypeId<ConcreteComponentOne>()]);
    
    				cout << h_component.an_integer << " " << h_component.a_floating_point << " " << h_component.a_boolean << endl;
    			}
    		}
    	}
    };
    
    int main()
    {
    	EntityManager manager;
    
    	ConcreteEntityBuilder builder;
    
    	ConcreteSystem system;
    
    	builder.BuildEntity(manager, 100, 10.f, true);
    
    	system.UpdateFixed(manager);
    
    	getchar();
    
    	return EXIT_SUCCESS;
    }
    

Log in to reply