Let's have a look at the declaration (typically stored in a .h file): To keep it simple we define just three properties for the Light entity: “enabled”, “diffuse colour”, and “position”. Furthermore we override two event callbacks (onInitialise() and onTick()). In the class implementation we go into further detail of the underlying implementations.
class Light : public Entity { YAKE_DECLARE_ENTITY(Light) public: OBJECT_PROPS_BEGIN(Light) OBJECT_PROP("diffuseColour", Color, Color(1,1,1,1)) OBJECT_PROP("position", Vector3, Vector3(0,0,0)) OBJECT_PROP("enabled", bool, true) OBJECT_PROPS_END() protected: Light(); virtual void onInitialise(object_creation_context& creationCtx); virtual void onTick(); };
For this example it would be enough to use the define and implement the constructor. We override the onTick() and onInitialise() methods just to show how it's done.
YAKE_DEFINE_ENTITY_1( Light, Entity ) Light::Light() { } void Light::onTick() { Entity::onTick(); // <- Don't forget to inherit base entity class' functionality! // Custom code here... } void Light::onInitialise(object_creation_context& creationCtx) { Entity::onInitialise(creationCtx); // <- Again! // Custom code here... }
The concepts are quite similar to defining an entity itself.
class LightVisual : public EntityComponent { YAKE_DECLARE_ENTITY_COMPONENT( LightVisual, "light.visual" ); protected: virtual void onInitialise(object_creation_context& creationCtx); virtual void onTick(); private: SharedPtr<graphics::ISceneNode> mpSN; graphics::ILight* mpLight; bool mLightEnabled; };
Register component:
YAKE_REGISTER_ENTITY_COMPONENT( LightVisual );
Constructor:
LightVisual::LightVisual( Entity& owner ) : EntityComponent( owner ), mpLight(0), mLightEnabled(false) {}
The initialisation code (including basic error handling):
void LightVisual::onInitialise(object_creation_context& creationCtx) { EntityComponent::onInitialise(creationCtx); //if (!isServer()) { YAKE_ASSERT( creationCtx.mpGWorld ); // Create a graphics::ILight object. mpLight = creationCtx.mpGWorld->createLight(); YAKE_ASSERT( mpLight ); // Create a graphics::ISceneNode object for moving our light around. mpSN.reset( creationCtx.mpGWorld->createSceneNode() ); YAKE_ASSERT( mpSN.get() ); mpSN->attachLight( mpLight ); // Attach the light to the scene node. // Configure the light (type, colour ...) mpLight->setType( graphics::ILight::LT_POINT ); mpLight->setDiffuseColour( Color(1,0,0) ); mpLight->setEnabled( true ); getOwner().getProperty("enabled")->setValue(true); mpSN->setPosition( Vector3(0,20,0) ); } }
Each tick we update the Light entity's properties to the graphics light object. This is just one possible implemenation. Another approach would be to do this every frame (onFrame()) or via an event or callback/signals based system. Everything's possible.
For each property we check whether the values has actually changed. If it has, we update the visual component's graphics objects accordingly and reset the properties' “dirty” flags.
void LightVisual::onTick() { // position Property* pProp = getOwner().getProperty("position"); YAKE_ASSERT( pProp ); if (pProp->hasChanged()) { YAKE_ASSERT( mpSN ); if (pProp && mpSN) mpSN->setPosition( pProp->getValueAs<Vector3>() ); pProp->setHasChanged( false ); } // enabled pProp = getOwner().getProperty("enabled"); YAKE_ASSERT( pProp ); if (pProp->hasChanged()) { YAKE_ASSERT( mpLight ); if (pProp && mpLight) mpLight->setEnabled( pProp->getValueAs<bool>() ); pProp->setHasChanged( false ); } // colour pProp = getOwner().getProperty("diffuseColour"); YAKE_ASSERT( pProp ); if (pProp->hasChanged()) { YAKE_ASSERT( mpLight ); if (pProp && mpLight) mpLight->setDiffuseColour( pProp->getValueAs<Color>() ); pProp->setHasChanged( false ); } }