[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Written by Jorrit Tyberghein, jorrit.tyberghein@uz.kuleuven.ac.be. Last updated 16 August 2003.
When you define geometiry in a map file this usually define a static representation of the world. Using the sequence manager it is possible to define specific events that trigger on certain conditions. Using these events (sequences) you can move or animate objects, control lights, fog, ....
The sequence manager is actually divided in two plugins. First there is the basic sequence manager itself. This is nothing more then a schedular that can schedule certain actions that should happen at certain times. Applications can use this sequence manager for their own purposes if they want.
On top of the sequence manager there runs the engine sequence manager. This plugin predefines several operations and triggers which make it a lot easier to do engine related things like moving objects, controlling lights, .... We will discuss mainly the engine sequence manager in this section.
A sequence represents a small script with commands that operate on objects in the world. A trigger represents a series of conditions which will cause the sequence to be executed. The important thing of the sequence manager is that it is very time based. Operations don't all execute at once but at specific times relative to the start of the sequence. Note that all times in the sequence manager are specified in milli-seconds.
The easiest way to explain the engine sequence manager is to look at a simple example as how it can be used from a map file:
<world> ... <sector name="hall"> <light name="roomlight"> <center x="10" y="4" z="10" /> <radius>20</radius> <color red="0" green="0" blue="0" /> <dynamic /> </light> ... </sector> ... <sequences> <sequence name="turn_on_light"> <setlight light="roomlight" red="1" green="1" blue="1" /> <delay time="50" /> <setlight light="roomlight" red="0" green="0" blue="0" /> <delay time="80" /> <setlight light="roomlight" red="1" green="1" blue="1" /> </sequence> </sequences> <triggers> <trigger name="trig_turn_on_light"> <sectorvis sector="hall"> <sphere x="10" y="4" z="10" radius="5" /> </sectorvis> <fire delay="0" sequence="turn_on_light" /> </trigger> </triggers> </world> |
This is a simple example where we turn on a light as soon as we are in a certain radius of the light. Let's explain how it works. First we define a sequence which is called `turn_on_light'. This sequence has three `setlight' operations and two delays. Internally this is compiled to something which looks like this:
time 0ms: setlight 'roomlight',1,1,1 time 50ms: setlight 'roomlight',0,0,0 time 130ms: setlight 'roomlight',1,1,1 |
Basically there are three operations here and the delays are only used to indicate when these operations are executed relative to the start of the entire sequence. So for example, if the sequence is fired at time 10050 then immediatelly at that point the first operation is executed. 50 milliseconds later the second operation is executed and finally, 130 milliseconds later the last operation is exexuted.
There are a few important observations to be made about this. First, as soon as a sequence is executed or fired ALL operations in that sequence will execute at the correct relative time no matter what happens otherwise. This also means that if you fire another sequence then that sequence will also get fired at the same time and depending on the relative timing of the operations some of those operations might happen at the same time.
Also note that there are operations that themselves have a duration. For example, there is a `fadelight' operation which fades a light to some color. It has a `duration' parameter. But this duration does NOT influence the relative timing in the sequence itself. So for example if you have this:
<fadelight light="somelight" red="0" green="0" blue="0" duration="1000" /> <fadelight light="somelight" red="1" green="1" blue="1" duration="1000" /> |
Then this will execute two fade operations on the same light at exactly the same time which is probably not what you want. This example is probably better written as:
<fadelight light="somelight" red="0" green="0" blue="0" duration="1000" /> <delay time="1000" /> <fadelight light="somelight" red="1" green="1" blue="1" duration="1000" /> |
This will place the two operations at a time distance of 1000 milliseconds.
The reason that using `duration' does not automatically advance the internal relative time is that it is sometimes useful to start several fade operations (or other operations that have a duration) at the same time. For example, two fade operations on two different lights.
A sequence as such is not useful. It needs to be fired at some point. You can fire sequences manually from code or you can define a trigger to fire the sequence if a certain condition is true. In this case we have a trigger which is called `trig_turn_on_light'. This trigger will fire if the sector `hall' is visible and the camera is in the sphere defined by the center `10,4,10' and radius `5'. As soon as this condition is valid the `turn_on_light' sequence will be fired immediatelly. Note that this automatically implies that the trigger is disabled. This is to prevent the sequence from being fired several times while the trigger condition remains valid. If you want a trigger that keeps firing you have to re-enable it in the sequence.
<sequences> <sequence name="animlight"> <fadelight light="l1" red="0" green="0" blue="0" duration="1000" /> <delay time="1000" /> <fadelight light="l1" red="1" green="1" blue="1" duration="1000" /> <delay time="1000" /> <fadelight light="l1" red="1" green="0" blue="0" duration="1000" /> <delay time="1000" /> <fadelight light="l1" red="0" green="1" blue="0" duration="1000" /> <delay time="1000" /> <fadelight light="l1" red="0" green="0" blue="1" duration="1000" /> <delay time="1000" /> <enable trigger="animlight" /> </sequence> </sequences> <triggers> <trigger name="animlight"> <sectorvis sector="large" /> <fire sequence="animlight" /> </trigger> </triggers> |
In this example there is a trigger called `animlight' that fires as soon as the sector named `large' is visible. Here is what happens as soon as the condition of the trigger (in this case `sectorvis') is true:
It is important to note that the `duration' parameter that is given in some of the operations does NOT imply that the next operation will execute after that operation has finished. The `duration' parameter has no effect on the internal relative time that is maintained for the sequence operations. To influence that you must use `delay'.
If you want to use the same sequence for different lights you can use parameters like in the following example:
<sequences> <sequence name="animlight"> <args> <arg name="l" /> <arg name="trig" /> </args> <fadelight light_par="l" red="0" green="0" blue="0" duration="1000" /> <delay time="1000" /> <fadelight light_par="l" red="1" green="1" blue="1" duration="1000" /> <delay time="1000" /> <fadelight light_par="l" red="1" green="0" blue="0" duration="1000" /> <delay time="1000" /> <fadelight light_par="l" red="0" green="1" blue="0" duration="1000" /> <delay time="1000" /> <fadelight light_par="l" red="0" green="0" blue="1" duration="1000" /> <delay time="1000" /> <enable trigger_par="trig" /> </sequence> </sequences> <triggers> <trigger name="animlight_l1"> <sectorvis sector="large" /> <fire sequence="animlight"> <light name="l" light="l1" /> <light name="trig" light="animlight_l1" /> </fire> </trigger> <trigger name="animlight_l2"> <sectorvis sector="large" /> <fire sequence="animlight"> <light name="l" light="l2" /> <light name="trig" light="animlight_l2" /> </fire> </trigger> </triggers> |
Here you see how the same sequence (`animlight') is used by two different triggers for two different lights. It is not only the light that has to be given as a parameter but also the trigger that needs to be enabled again. That's why two parameters are used.
A lot more is possible here. I will give a short summary of all commands (that are not operations) that are supported in sequences here:
args
delay
Here is a list of all operations that you can use in a sequence. Note that every operation is tagged with a relative time (relative to the start of the sequence). If you want to use a parameter for an operation that uses an argument to the sequence then you have to add `_par' to the parameter name like this: `light_par'.
run
move
rotate
material
fadecolor
setcolor
fadelight
setlight
fadeambient
setambient
fadefog
setfog
enable
disable
check
test
setvar
Here is a list of all conditions that are supported in a trigger:
onclick
lightvalue
manual
sectorvis
fire
disable
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |