0

Background:

In my game engine I have a generic 'script parser' which is used to create game entities by parsing a script file. So in code you would have something like MyEntity* entity = MyScriptParer::Parse("filename.scr");

Any class which is to be scriptable inherits from a generic base class. Internally in the game engine there are some specific classes that use this - particles, fonts etc and this all works nicely in the parser - see extract below

std::string line;
std::getline(ifs, line);

if (line == "[FONT]") {
    CFont* f = new CFont();
    f->readObject(ifs);
}
else if (line == "[PARTICLE]") {
    CParticle* p = new CParticle();
    p->readObject(ifs);
}
...

My problem comes with how to handle user defined classes i.e classes in the games that use the game engine. The base class has an abstract method readObject so anything which inherits must implement this method.

The issue is how would the parser know about the new class? E.g say I have a CVehicle class the parser would now need to know to recognise "[VEHICLE]" and also be able to create a new CVehicle

Is there any way to store a class type or something in an array/map so maybe I could have a function to register a list of class types with strings to provide a lookup for creating the new instances?

Bit of a long shot and may not be possible so if anyone has other suggestions on how to approach the parsing they will be welcomed

4

2 に答える 2

1

std::type_infoを介してクラス型を配列/マップに格納できます

ただし、C++ で使用できるよりも多くの RTTI が必要になるため、これから型を作成することはできません。(.NET のリフレクションのように)。

ただし、そのようなマップにクラス ファクトリへの関数ポインターを格納することはできます。いえ

typedef CBaseClass* (*pfnCreateClass)();

std::map<std::string, pfnCreateClass> mapCreate;

// Registering
// CMyCustomClass::GetClass() is a static method that creates a CMyCustomClass
mapCreate.insert(std::pair<std::string, pfnCreateClass>("[CUSTOM_CLASS]", CMyCustomClass::GetClass));

// Get class
std::map<std::string, pfnCreateClass>::const_iterator it = mapCreate.find(line);
if(mapCreate.end() != it)
{
    CBaseClass *p = it->second();
    p->readObject(ifs);
}
于 2013-10-06T21:18:18.293 に答える
0

新しい型を登録する関数に型の名前を取り込ませ、型を作成する関数を持たせるだけです。

そのようなもの:

void RegisterType( std::string name, std::function< BaseType() > createFunc );

新しいタイプを登録するときは、次のようにします。

RegisterType( "Vehicle", [](){ return new CVehicle; } );

そうすれば、パーサーはすべての派生型を作成できます。

于 2013-10-06T21:14:25.630 に答える