Question

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

Was it helpful?

Solution

You can store a class type in an array/map via std::type_info

However, you cannot create a type from this, as it would require more RTTI than is available in C++. (like reflection in .NET).

However, you could store a function pointer to a class factory in such a map. I.e.

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);
}

OTHER TIPS

Just have the function to register a new type take in the name of the type and a function for creating the type.

Something like so:

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

When registering a new type you do it like so:

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

That way the parser can create all the derived types.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top