In the Creating a trigger system recipe, we laid the foundation for a Trigger
system as well as created some basic implementations. A timer can be very useful when creating complex scripts that rely on timing or sequenced events. Not only does it do the obvious (trigger the blast of the door and then the soldiers running through) but it can also work as a relay trigger in case many things should be triggered at the same time. In this recipe, we'll create this Timer
object as well as an actual implementation of it where it triggers an explosion with several components. To save some time, we'll use the TestExplosion
test from jMonkeyEngine to get ParticleEmitters
set up and the timing for free. We'll also create a new ScriptObject
called PlayEffect
, which controls the particle emitters.
To be able to control a ParticleEmitter
object from our script system, we need a new class to handle the ParticleEmitter
object:
PlayEffect
, which implements ScriptObject
.PlayEffect
class needs a Boolean called emitAllParticles
, a ParticleEmitter
field called effect
, and a Boolean to control whether it's enabled or not (default it to true
).trigger
method should call onTrigger
if the object is enabled.onTrigger
method should enable effect
and if emitAllParticles
is true
, it should call emitter.emitAllParticles()
.Apart from the setter methods, this is all that's needed for the PlayEffect
class. Now, we can look at the Timer
class by performing the following steps:
Timer
, which implements ScriptObject
.public interface TimerEvent{ public Object[] call(); }
enabled
and another called running
. It also needs to keep track of time with three floats called time
, lastTime
, and maxTime
.HashMap<Float, TimerEvent>
.addTimerEvent
and add inputs for time
in seconds to execute the event, as well as a TimerEvent
object with the code to execute it. After TimerEvent
is placed in the timerEvents
map, we check whether the supplied time
value is higher than the current maxTime
and set maxTime
to time
if true, as shown in the following code:public void addTimerEvent(float time, TimerEvent callback){ timerEvents.put(time, callback); if(time >maxTime ){ maxTime = time; } }
trigger
method should call onTrigger
, if it is enabled.onTrigger
method should set time to 0
and set running
to true
.update
method should first check whether the Timer
is enabled
and running
.same
statement, we then create an iterator based on keySet
of timerEvents
and parse through it. If the key (a float) is more than lastTime
and less or equal to the current time, we should get the corresponding value from the timerEvents
map and execute it. Otherwise, if the key is less than lastTime
, we should just continue using the following code:Iterator<Float> it = timerEvents.keySet().iterator(); while(it.hasNext()){ float t = it.next(); if(t >lastTime&& t <= time){ TimerEvent event = timerEvents.get(t); if(event != null){ event.call(); } } else if(t <lastTime){ continue; } }
time
is more than maxTime
, in which case, we should set running
to false
.update
method, we set lastTime
to be equal to time
.With the basic logic done, let's take a look at how we can use the timer for something real and use it to trigger an explosion by performing the following steps:
TestExplosion
class from jMonkeyEngine's test package and strip it from everything except the methods that create ParticleEmitters
and the lines in simpleInitApp
, which uses them and sets up the camera.PlayEffect
instance for each of ParticleEmitters
and set the effect accordingly with emitAllParticles
set to true
.Timer
instance called explosionTimer
.TimerEvent
at time 0 where it triggers the flash
, spark
, smoke
, debris
, and shockwave
effects, by calling trigger()
on each of the PlayEffects
, as shown in the following code:explosionTimer.addTimerEvent(0, new Timer.TimerEvent() { public Object[] call() { flashEffect.trigger(); sparkEffect.trigger(); ... return null; } });
TimerEvent
at time 0.05f
, which triggers the flame
and roundSpark
effects.TimerEvent
should happen at time 5f
and should call stop()
on all of the effects.ScriptAppState
instance to which we add explosionTimer
and then add it to stateManager
using the following code:ScriptAppStateappState = new ScriptAppState(); stateManager.attach(appState); appState.addScriptObject(explosionTimer);
explosionTimer
. It should perform the explosion in the same way as TestExplosion
does.Once triggered, Timer
works by checking the time that has passed since it was started (time
). It then checks each of the events in the timerEvents
map to see whether their execution time is anywhere between the current time and the last time (lastTime
). The maxTime
option is used by the Timer
to know when it has executed the last of its events and can switch itself off. If the Timer
was only meant to be used once, the events can simply be removed from the timerEvent
map. This way it can be reused.
The PlayEffect
instance has a fairly simple functionality to turn it on and off. Since ParticleEmitters
can be used in two ways, fire all their particles at once, or emit a continuous stream of particles, it needs to know which way to fire it.
In the example application, we create ScriptAppState
since it's needed to update the Timer
with the passed time. We don't need to add the PlayEffect
instances since they don't use the update
method.
3.142.156.235