Hi all!
Sorry if I'm saying something repeated or out of contest, this thread is quite big and I haven't followed it in detail. I'm writting these lines motivated by this twitter stream:
https://twitter.com/davidjrogers/status ... 9357824000 (Almost all is in here, I'm just putting things in order in this post)
Well, let's start. The whole post is about how to identify objects in a smart, clean, easy and consistent way across the whole API.
I would like to suggest the approach I've been using since a while in the Paradise Engine: using a templated base class for identifiable objects, and then inheriting from it for objects which needs to be identify. Let's stop talking and see some code:
Code: Select all
/*
--------------------------------------------------------------------------------
This source file is part of Paradise Utils.
Visit ---
Copyright (C) 2009 Xavier Verguín González <xavierverguin@hotmail.com>
<xavyiy@gmail.com>
--------------------------------------------------------------------------------
*/
#ifndef _PUtils_Identifiable_H_
#define _PUtils_Identifiable_H_
#include "Prerequisites.h"
namespace PUtils {
/** Template base class for identifiable classes
*/
template <class T>
class Identifiable
{
public:
/** Default constructor
*/
inline Identifiable(){}
/** Constructor
@param id Id
*/
inline Identifiable(const T& id)
: mId(id) {}
/** Set id
@param id New id
*/
inline void setId(const T& id)
{
mId = id;
}
/** Get id
@return Id
*/
inline const T& getId() const
{
return mId;
}
protected:
/// Id
T mId;
};
/// Identifiable types
typedef Identifiable<int16> int16Identifiable;
typedef Identifiable<int32> int32Identifiable;
typedef Identifiable<uint16> uint16Identifiable;
typedef Identifiable<uint32> uint32Identifiable;
typedef Identifiable<STDString> strIdentifiable;
}
#endif
One time you've and idea of what the base class looks like, let's continue, then SceneNodes (maybe Nodes) and MovableObjects should inherit from them (and all identifiable objects: materials, gpu programs, etc), something like this:
Code: Select all
namespace PEngine {
/** Node class
*/
class PEngineDllExport Node : public PUtils::Serializable, public PUtils::uint32Identifiable
{
public:
Depending of the nature of the resource, we'll be using uint32Identifiable or strIdentifiable classes (or ever a uint64Identifiable, if we want to warrant MMORPGs compatibility, just kidding, 2^32 is more than enough

). The point is only using strIdentifiable for resources which really needs unique names (since the final goal is improving performance!), maybe physical resources like textures, materials and GPU programs. For nodes and movable objects uint32 ids are perfect.
How to generate/assign the id? easy: in the creator class, SceneManager for nodes and in factories for movable objects. Some important reflexions:
- Ids are generated by an auto-incremental var stored in the creator class: object->setId(mNextId++);
- Use unique ids at movable object level: even if entities and billboard sets (for example) could have the same ids since them are from different factories, it could be quite confusing having movable object ptrs and having duplicated ids for different movable objects. I suggest one unique id at movable object level, maybe stored (the mNextId var) as a static var in the MovableObject class (although I'm not very friend of static vars, hehe)
- Movable objects and nodes would continue having a name variable, but just optional and for lookup operations: if we've two nodes with the same name, we just return the first reference. Internally all is stored in maps (or whatever) based on the unique id.
Some code regarding this last point:
Code: Select all
/** Create node
@param name Node name
@return Node
@remarks For properly remove the created node, use WorldSystem::destroyNode(...).
Use Scene::createNode(...) to create a Node with an unique associated PUtils::uint32Identifiable id.
*/
Node* createNode(const PUtils::STDString& name = "");
/** Get node by name
@param name Node name
@return The node pointer or NULL if the node is not found
@remarks Multiple nodes are allowed to have the same name. The returned node will
be the first result
*/
Node* getNode(const PUtils::STDString& name);
...
/** Create light
@param lt Light type
@param name Light name
@return Light
@remarks For properly remove the created light, use WorldSystem::destroyLight(...).
Use Scene::createLight(...) to create a Light with an unique associated PUtils::uint32Identifiable id.
*/
Light* createLight(const Light::LightType& lt, const PUtils::STDString& name = "");
/** Get light by name
@param name Light name
@return The light pointer or NULL if the light is not found
@remarks Multiple lights are allowed to have the same name. The returned light will
be the first result
*/
Light* getLight(const PUtils::STDString& name);
...etc
What are the advantages of using a base class for identifiable objects?
- Consistent interface across the whole API: smart, clean, easy
- Being able to store ptrs to identifiables, useful in some cases!
- Since the base class is a templated one, we can still to use the same interface even for different type of ids: uint32, String, ... easily.
Hope this helps!
Xavier