2012-02-27 2 views
4

나는 간단한 메시지 전달 엔티티 시스템을 만들고 있습니다. 나는 런타임에 엔티티 서브 클래스를 만드는 공장에 걸려 엔터티 디스크립터 테이블을 가지고 있고, 그들은 문자열로 생성 할 수 있도록 내가 그것을 가지고 싶습니다런타임시 클래스 정보에 액세스 할 수 있도록 확장 가능한 방법

EntityManager manager; //managers have all of the entity table information (See below) 

//Counter is a sample class that inherits from Entity 
Counter* counter = manager.makeEntity("Counter"); //the string doesn't have to match the class name. 

지금, 나는 간단한 스위치 문을 수있어 ,하지만 시스템을 확장 가능하게하고 싶습니다. 즉, (또는 다른 시스템 사용자가) 새로운 Entity 서브 클래스를 만들고 싶을 때, 스위치 블록으로 가서 추가 할 필요가 없습니다. 현재 매크로를 사용하여 도우미 클래스를 만들고 정적으로 인스턴스화하여 생성자가 엔티티 테이블에 엔트리를 추가합니다. 이 클래스는 또한 엔티티를 초기화하고 생성자에서 많은 상용구를 제거합니다.

//EHandle is a wrapper for Entity*. Currently std::shared_ptr<Entity> 

class GenericDesc 
{ 
public: 
virtual ~GenericDesc() {} 
    virtual EHandle makeEntity() const =0; 
}; 

namespace Descriptor 
{ 
    //Adds a descriptor to an internal map<string, GenericDesc*> 
    void addEntityDescriptor(const std::string& type, GenericDesc& desc); 
    EHandle newEntity(const std::string& type); //Factory method 
} 

//Add this to every entity class definition 
#define DECLARE_ENTITY_CLASS(CLASS_NAME) \ 
    friend class CLASS_NAME##Descriptor; 


//Use these after a class definition to add the entity class to the descriptor table 
#define BEGIN_ENTITY_TYPE(ENTITY_NAME, CLASS_NAME, BASE_NAME) \ 
    BEGIN_ENTITY_TYPE_GUTS(ENTITY_NAME, CLASS_NAME) \ 
     BASE_NAME##Descriptor::prepareEntity(ent); 

#define BEGIN_ENTITY_TYPE_BASELESS(ENTITY_NAME, CLASS_NAME) \ 
    BEGIN_ENTITY_TYPE_GUTS(ENTITY_NAME, CLASS_NAME) \ 
     ent->self = ent; 

#define BEGIN_ENTITY_TYPE_GUTS(ENTITY_NAME, CLASS_NAME) \ 
class CLASS_NAME##Descriptor : public GenericDesc \ 
{ \ 
private: \ 
    typedef CLASS_NAME ClassName; \ 
public: \ 
    CLASS_NAME##Descriptor() \ 
    { \ 
     Descriptor::addEntityDescriptor(ENTITY_NAME, *this); \ 
    } \ 
    virtual ~CLASS_NAME##Descriptor() {} \ 
    virtual EHandle makeEntity() const\ 
    { \ 
     auto ent = std::shared_ptr<CLASS_NAME>(new CLASS_NAME); \ 
     prepareEntity(ent); \ 
     ent->type = ENTITY_NAME; \ 
     return ent; \ 
    } \ 
    static void prepareEntity(std::shared_ptr<ClassName> ent) \ 
    { 

//These functions are caled between BEGIN_ENTITY_TYPE and END_ENTITY_TYPE 
//ADD_ENTITY_INPUT binds a function to a string 
#define ADD_ENTITY_INPUT(INPUT_NAME, INPUT_FUNC) \ 
     ent->addInput(INPUT_NAME, std::bind(&ClassName::INPUT_FUNC, ent, std::placeholders::_1)); 
//ADD_ENTITY_OUTPUT binds an Output object to a string 
#define ADD_ENTITY_OUTPUT(OUTPUT_NAME, OUTPUT_OBJECT) \ 
     ent->addOutput(OUTPUT_NAME, ent->OUTPUT_OBJECT); 

#define END_ENTITY_TYPE(CLASS_NAME) \ 
    } \ 
}; \ 
static CLASS_NAME##Descriptor CLASS_NAME##Desc; //TODO: find a way to fix the multiple-static-allocation issue 

생각

는 중간에 ADD_ENTITY_x 비트와 더불어, BEGIN_ENTITY_TYPE (...) END_ENTITY_TYPE (...) 제를 만들 수 있다는 것입니다. 내 질문은이 작업을 수행하는 덜 매크로 방식이 있는지, 아직 상용구를 최소화하고 Entity 서브 클래스를 정의하는 외부 파일을 수정하지 않아도되는지 여부입니다. 템플릿 클래스가 작동 할 수는 있지만 템플릿 클래스를 사용하여 ADD_ENTITY_INPUT/OUTPUT 작업을 수행하는 방법을 알지 못합니다.

답변

0

이 필요하시면 전체 수 있지만 같은 것을 고려하지 않을 수 있습니다

class Factory 
{ 
public: 
    virtual void InitialiseFactory() = 0; 
    Entity* CreateEntity(string type) 
    { 
     // (obviously, you must handle the string not being found.) 
     return m_MapEntities[ type ]->Clone(); 
    } 
}; 

class MyFactory : public Factory 
{ 
public: 
    void InitialiseFactory() 
    { 
     m_MapEntities["typea"] = new MyEntity(); 
    } 
}; 

여기에서의 아이디어 조회가 변경되지 수있는 기본 클래스에 concretised 것을, 그러나의 특성 엔티티는 파생 클래스의 구현에 제공됩니다.

또 다른 방법은 추가 할 팩토리에 대한 호출을 만드는 각 Entity의 정적 메서드에 대한 것이지만 그 메서드는 여전히 어딘가에서 호출되어야합니다.

+0

그래서 템플릿이 있습니다 : – Lucretiel

+0

그게 질문입니까? :-) –

관련 문제