This tutorial page assumes a good understanding of vrmlscript in particular directOutput and array access methods.
Translation event and animation contol
This example uses a Script node to control the animation of a black ball across a surface. The source which produces the translation values (in this case a TouchSensor's hitPoint_changed event) produces occasional values and not a continious stream which is usual for animations.
In addition the Script stores in incoming values and moves smoothly from one point to the next at a constant movement rate of 10 meter per second. When the previous animation finishes it retrieves the next stored value and then beings a new animation after disgarding the last value.
DEF MainTranform Transform {
children [
DEF Offset Transform {
translation 0 0.5 0
children [
Shape{
appearance Appearance {
material Material {
diffuseColor 0 0 0
specularColor .5 .5 .5
ambientIntensity 0
emissiveColor .15 .15 .15
}
}
geometry
Sphere {
radius 0.5
}
}
]
}
DEF Timer TimeSensor {
cycleInterval 1
startTime -1
}
DEF Move PositionInterpolator {
key [ 0, 1 ]
keyValue [ 0 0 0, 0 0 0 ]
}
DEF OffsetScript Script {
eventIn SFVec3f set_translation
eventIn SFBool timerIsActive
eventOut SFTime startTime
field SFNode Timer USE Timer
field SFNode Move USE Move
field MFVec3f storedValues []
field SFBool timerActive FALSE
field SFVec3f currentLocation 0 0 0
field SFVec3f l_ 0 0 0
field SFFloat distance 0
url "javascript:
function set_translation (val,ts) {
if (timerActive) {
// if timer is running add new value to the end of the stack
storedValues[(storedValues.length)+1]=val;
}
else {
// else calculate the distance between the current
// location and the next next stored on then begin the animation
l_[0]=currentLocation[0]-(val[0]);
l_[1]=currentLocation[1]-(val[1]);
l_[2]=currentLocation[2]-(val[2]);
// the length of this vector is the distance between
// the two points
distance = l_.length();
// animation interval = distance/10 meters per second movement rate
Timer.cycleInterval=distance/10;
// set animation keyValues
Move.keyValue[0]=currentLocation;
Move.keyValue[1]=new SFVec3f((val.x),(val.y),(val.z));
//start Timer
startTime=ts;
currentLocation=val;
}
}
function timerIsActive (val,ts) {
timerActive=val;
if ((!timerActive)&&((storedValues.length)>0)) {
// if the timer is inactive and there are stored values
// retrive the stored value and call the above function
set_translation(storedValues[storedValues.length-1],ts);
// decrease the number of stored values by one removing the
// above used value
storedValues.length=storedValues.length-1;
}
}
"
}
]
}
# route status of pointer and timer to Script
ROUTE Sensor.hitPoint_changed TO OffsetScript.set_translation
ROUTE Timer.isActive TO OffsetScript.timerIsActive
# animation routes
ROUTE OffsetScript.startTime TO Timer.startTime
ROUTE Timer.fraction_changed TO Move.set_fraction
ROUTE Move.value_changed TO MainTranform.translation
Modified version of example with extra code explained in notes below added. Touchsensor fix
Notes
One know problem with the above example is the pointer is not over the Ground geometry the hitPoint_changed event reverts back to 0 0 0. This only effects the above example and I have chosen not to add the aditional code as it would complicate the example code.
A simple solution would be to use the isOver event produced by the TouchSensor the check if the 0 0 0 value is due to the pointer no longer being over the Ground geometry and ROUTEing this to a new function in the Script node which then keeps track.
If the source of the translations values is another source (for example a ProximitySensor or another Scipt) this additonal code would be unneeded.
The Graphics and 3D content of this site are the works of the author unless noted otherwise.
The Unauthorized use of any of this site's content for commercial or other uses is strictly forebidden.