C++ property system interface for game editors (reflection system)
- by Cristopher Ismael Sosa Abarca
I have designed an reusable game engine for an project, and their functionality is like this:
Is a completely scripted game engine instead of the usual scripting languages as Lua or Python, this uses Runtime-Compiled C++, and an modified version of Cistron (an component-based programming framework).to be compatible with Runtime-Compiled C++ and so on.
Using the typical GameObject and Component classes of the Component-based design pattern, is serializable via JSON, BSON or Binary useful for selecting which objects will be loaded the next time.
The main problem: We want to use our custom GameObjects and their components properties in our level editor, before used hardcoded functions to access GameObject base class virtual functions from the derived ones, if do you want to modify an property specifically from that class you need inside into the code, this situation happens too with the derived classes of Component class, in little projects there's no problem but for larger projects becomes tedious, lengthy and error-prone.
I've researched a lot to find a solution without luck, i tried with the Ogitor's property system (since our engine is Ogre-based) but we find it inappropiate for the component-based design and it's limited only for the Ogre classes and can lead to performance overhead, and we tried some code we find in the Internet we tested it and worked a little but we considered the macro and lambda abuse too horrible take a look (some code omitted):
IWE_IMPLEMENT_PROP_BEGIN(CBaseEntity)
IWE_PROP_LEVEL_BEGIN("Editor");
IWE_PROP_INT_S("Id", "Internal id", m_nEntID, [](int n) {}, true);
IWE_PROP_LEVEL_END();
IWE_PROP_LEVEL_BEGIN("Entity");
IWE_PROP_STRING_S("Mesh", "Mesh used for this entity",
m_pModelName, [pInst](const std::string& sModelName) {
pInst->m_stackMemUndoType.push(ENT_MEM_MESH); pInst->m_stackMemUndoStr.push(pInst->getModelName());
pInst->setModel(sModelName, false); pInst->saveState();
}, false);
IWE_PROP_VECTOR3_S("Position", m_vecPosition,
[pInst](float fX, float fY, float fZ) {
pInst->m_stackMemUndoType.push(ENT_MEM_POSITION); pInst->m_stackMemUndoVec3.push(pInst->getPosition()); pInst->saveState();
pInst->m_vecPosition.Get()[0] = fX; pInst->m_vecPosition.Get()[1] = fY; pInst->m_vecPosition.Get()[2] = fZ;
pInst->setPosition(pInst->m_vecPosition);
}, false);
IWE_PROP_QUATERNION_S("Orientation (Quat)", m_quatOrientation,
[pInst](float fW, float fX, float fY, float fZ) {
pInst->m_stackMemUndoType.push(ENT_MEM_ROTATE); pInst->m_stackMemUndoQuat.push(pInst->getOrientation()); pInst->saveState();
pInst->m_quatOrientation.Get()[0] = fW; pInst->m_quatOrientation.Get()[1] = fX; pInst->m_quatOrientation.Get()[2] = fY; pInst->m_quatOrientation.Get()[3] = fZ;
pInst->setOrientation(pInst->m_quatOrientation);
}, false);
IWE_PROP_LEVEL_END();
IWE_IMPLEMENT_PROP_END()
We are finding an simplified way to this, without leading confusing the programmers, (will be released to the public) i find ways to achieve this but they are only available for the common scripting as Lua or editors using C#. also too portable, we can write "wrappers" for different GUI toolkits as Qt or GTK, also i'm thinking to using Boost.Wave to get additional macro functionality without creating my own compiler.
The properties designed to use in the editor they are removed in the game since the save file contains their data and loads it using an simple 'load' function to reduce unnecessary code bloat may will be useful if some GameObject property wants to be hidden instead.
In summary, there's a way to implement an reflection(property) system for a level editor based in properties from derived classes?
Also we can use C++11 and Boost (restricted only to Wave and PropertyTree)