Time component - extensions

Contents:

These feature are available since Castle Game Engine 6.5 and view3dscene 3.19.0.

1. TimeSensor.fractionIncreasing field

As an extension, we add a fractionIncreasing field to the TimeSensor node:

TimeSensor {
  ...
  SFBool     [in,out]      fractionIncreasing  TRUE      
}

When FALSE, the animation runs backwards. It's very simple: after calculating the fraction value, following the X3D specification, we do fraction := 1 - fraction. And then we send fraction through the TimeSensor.fraction_changed event.

If your interpolators react nicely to the TimeSensor.fraction_changed then the animation will run backwards. See a description how TimeSensor and interpolators are typically connected to implement animation.

Note that everything else works as usual, regardless of the fractionIncreasing value. In particular, TimeSensor.elapsedTime and TimeSensor.time output events are always generated with increasing values (trying to force them to go backward would make weird results).

2. TimeSensor.detectAffectedFields field

TimeSensor {
  ...
  SFBool     []            detectAffectedFields  TRUE      
}

In short: This field should remain TRUE (the default value) for time sensor nodes that represent animations that Castle Game Engine can run at any moment (e.g. using TCastleSceneCore.PlayAnimation).

This allows the CGE TCastleSceneCore.ResetAnimationState to work correctly. In turn, this means that TCastleSceneCore.PlayAnimation works always correctly, with and without animation blending (cross-fading).

Details:

When this is TRUE, the engine will detect the fields affected by the animation defined by this TimeSensor node. This "detection" looks what interpolators and triggers are affected by this TimeSensor. To be precise:

  • TimeSensor fraction_changed may be routed to interpolator/sequencer (X3DInterpolatorNode, X3DSequencerNode) input set_fraction. Then the interpolator value_changed must be routed to the field we call "affected".

  • TimeSensor isActive may be routed to trigger ValueTrigger.trigger or IntegerTrigger.set_boolean or TimeTrigger.set_boolean. Then the trigger output (ValueTrigger has many outputs), IntegerTrigger.triggerValue, TimeTrigger.triggerTime must be routed to the field we call "affected".

The values assigned to detected fields will be recorded, for the entire lifetime of this scene.

The detected "affected fields" will be used:

  • The TCastleSceneCore.ResetAnimatedFields sets all the fields affected by any animation to their initial (detected at loading) state.

  • The TCastleSceneCore.PlayAnimation sets all the fields affected by any animation (except the new animation) to their initial (detected at loading) state.

    This is important e.g. if your animation "walk" only moves the model's legs (and doesn't modify model's hands), but some other animation moves hands. Then when doing "walk" we also make sure to put the hands in the original (not animated) position. This is useful, because previous animation could be e.g. "wave_hand" and you don't want the hand to be permanently raised up during "walk" animation cycle.

    Note that if you want to play multiple animations simulteneously, you can use TTimeSensorNode.Start instead of TCastleSceneCore.PlayAnimation. See simultaneous_animations_one_scene example . In this case, the "affected fields" do not matter, starting an animation using TTimeSensorNode.Start doesn't reset any fields.

Set the detectAffectedFields field to FALSE when this detection would be useless and time-consuming. This applies to time sensors which are not supposed to be used with TCastleSceneCore.PlayAnimation. Saving the state of "affected" fields may take time (if they are e.g. MFVec3f fields with lots of data) and may change memory management (if they are e.g. SFNode or MFNode fields).