Seems like my game is pushing hard on Animators and other modifiers of SceneNodes - after going around in design circles and trying different patterns out i think i found a simple way out of the box ...
As I wrote in a different thread, there are three kinds of animators - but i want to update that to be four types:
1. Every frame they want to be called - this is the best for things that change the rendering of an object
2. On a timer - this is best for character animation and other motion based things that dont require every frame updates
3. Called from outside - not timer or frame based - some outside object is determining when to update these
4. Data updating - want to be called whenever something in the scenenode changes (rotation, position, etc.)
If each scenenode could keep a list of each of these it would be AMAZING - and if an animator could be added to multiple lists that would be great too - so for physics i could make an animator that would be added to #3 and #4 lists - the animation framework would have callbacks for each type
and #2 would save the framerate! - the scenenode could organize the list to be in the order of fastest to slowest timer - so one object might want an update every 10 milliseconds while another wants it only once a minute
what do people think? - so the current one stays the same - we just add a timer list, static list and data updating list
with this kind of framework our animators would be incredibly powerful for games!!!
Animator design (a simple proposal)
niko - if you dont want to do the above then there are two additions to the current API that would make it possible for me to build a game object above IRR that does this (currently i cant because scenenodes are a blackbox)
- add a userdata pointer to scenenode
- add a flag that gets set when a node gets modified, and cleared during a render loop (after animators are called of course)
- add a userdata pointer to scenenode
- add a flag that gets set when a node gets modified, and cleared during a render loop (after animators are called of course)
here is the ISceneNode.h file with the proposed additions:
all the lists work on the Animator class, we would just add two calls - UpdateData and TimerAnimate to the class
Animators would work as they always have (per Frame)
DataUpdaters would get called each frame only if the IsChanged bool i true (if data has been modified in this scenenode)
TimerAnimators would be called each frame with an elapsed time variable - the scenenode should keep the list organized from faster to slower updaters so only those that need to get triggered are during a frame gap.
all the lists work on the Animator class, we would just add two calls - UpdateData and TimerAnimate to the class
Animators would work as they always have (per Frame)
DataUpdaters would get called each frame only if the IsChanged bool i true (if data has been modified in this scenenode)
TimerAnimators would be called each frame with an elapsed time variable - the scenenode should keep the list organized from faster to slower updaters so only those that need to get triggered are during a frame gap.
Code: Select all
protected:
//! updates the absolute position based on the relative and the parents position
void updateAbsolutePosition()
{
if (Parent)
AbsoluteTransformation =
Parent->getAbsoluteTransformation() * getRelativeTransformation();
else
AbsoluteTransformation = getRelativeTransformation();
}
//! name of the scene node.
core::stringw Name;
//! absolute transformation of the node.
core::matrix4 AbsoluteTransformation;
//! relative translation of the scene node.
core::vector3df RelativeTranslation;
//! relative rotation of the scene node.
core::vector3df RelativeRotation;
//! relative scale of the scene node.
core::vector3df RelativeScale;
//! Pointer to the parent
ISceneNode* Parent;
//! List of all children of this node
core::list<ISceneNode*> Children;
//! List of all Animators
core::list<ISceneNodeAnimator*> Animators;
//! List of all DataUpdaters
core::list<ISceneNodeAnimator*> DataUpdators;
//! List of all TimeAnimators
core::list<ISceneNodeAnimator*> TimeAnimators;
//! User data pointer
u32 *UserData;
//! id of the node.
s32 ID;
//! pointer to the scene manager
ISceneManager* SceneManager;
//! pointer to the triangleselector
ITriangleSelector* TriangleSelector;
//! automatic culling
bool AutomaticCullingEnabled;
//! flag if debug data should be drawed, like Bounding Boxes.
bool DebugDataVisible;
//! is the node visible?
bool IsVisible;
//! did data get modified in between frames?
bool IsChanged;
};
} // end namespace scene
} // end namespace irr
#endif
and here is the OnPostRender
i havent figured out how to do the timerAnimators since the elapsed time is not sent into OnPostRender - seems like each scenenode would have to hold into the aggregate time elapsed until it made it through its list of timers - for instance there might be three .10, .30 and .40 - if each elapsed time is coming in around 3 milliseconds it will take a while until the .40 one is triggered
hmmm, this is a tough one - its nice to have animators inside scenenodes but having high gap timers (.40 for instance) means that a ton of performance gets killed if the animators gets called every frame - right now in my game i keep these kinds of animators completely separate from the scenenode they effect
i havent figured out how to do the timerAnimators since the elapsed time is not sent into OnPostRender - seems like each scenenode would have to hold into the aggregate time elapsed until it made it through its list of timers - for instance there might be three .10, .30 and .40 - if each elapsed time is coming in around 3 milliseconds it will take a while until the .40 one is triggered
hmmm, this is a tough one - its nice to have animators inside scenenodes but having high gap timers (.40 for instance) means that a ton of performance gets killed if the animators gets called every frame - right now in my game i keep these kinds of animators completely separate from the scenenode they effect
Code: Select all
virtual void OnPostRender(u32 timeMs)
{
if (IsVisible)
{
// animate this node with all dataupdators if changed
if (IsChanged)
{
core::list<ISceneNodeAnimator*>::Iterator ait = DataUpdaters.begin();
for (; ait != DataUpdaters.end(); ++ait)
(*ait)->dataUpdateNode(this, timeMs);
}
IsChanged = false;
// animate this node with all animators
core::list<ISceneNodeAnimator*>::Iterator ait = Animators.begin();
for (; ait != Animators.end(); ++ait)
(*ait)->animateNode(this, timeMs);
// update absolute position
updateAbsolutePosition();
// perform the post render process on all children
core::list<ISceneNode*>::Iterator it = Children.begin();
for (; it != Children.end(); ++it)
(*it)->OnPostRender(timeMs);
}
}