-
Notifications
You must be signed in to change notification settings - Fork 7
Event Delays
Please see Event System before using
The EventHandler has been given extended functionality of scheduling events in the future and handling scheduled events. This simplifies code and provides precise timing for features that should not depend on Time System.
Note: Events cannot be saved/loaded. Do not use for functionality that needs to be saved.
The EventHandler
provides the following additional functionality:
-
scheduleEvent
- Similar totrigger
but takes in additional delay arg. Takes in delay (in seconds), event name and up to 3 args. Triggers the event after input seconds. Returns a reference to the event. -
cancelEvent
- Cancels given event. Pass in return value of scheduleEvent. -
cancelAllEvents
- Cancels all events. Use cautiously as it will also cancel scheduled events from other components. -
update
- Checks and executes scheduled events based onServiceLocator.getTimeSource()
, this has been added inentity.update()
. If you an EventHandler elsewhere, this function will have to be added somewhere in the game loop.
The code below outlines how functionality is used for HostileAttackPattern
.
Listener is added to the component in create()
entity.getEvents().addListener("attack", this::attack);
In attack function, it is used to delay shooting projectile and continue attack loop
public void attack() {
...
if (nearestEntity == null) { // No entity detected, clear attack loop
currentAttackEvent = null;
return;
}
...
entity.getEvents().trigger("attackStart") // trigger attack animation
entity.getEvents().scheduleEvent(0.2f, "shoot", position) // shoot projectile after 0.2 sesconds.
// or for dragonfly hostile, shoots 3 projectiles in succession
entity.getEvents().scheduleEvent(0.2f, "shoot", position)
entity.getEvents().scheduleEvent(0.3f, "shoot", position)
entity.getEvents().scheduleEvent(0.4f, "shoot", position)
// Schedule the next attack event
currentAttackEvent = entity.getEvents().scheduleEvent(ATTACK_FREQUENCY, "attack")
}
When an event is scheduled, it is added to the scheduledEvents
list in the EventHandler
. Every time event handler update()
, is called, it will check if each scheduled event can be triggered based on the current game time and the end time of the event. The event is then removed from the list
public void update() {
if (timeSource == null) {
return;
}
List<ScheduledEvent> eventsToTrigger = new ArrayList<>(scheduledEvents);
eventsToTrigger.removeIf(event -> !(timeSource.getTime() >= event.endTime()));
eventsToTrigger.forEach(this::triggerScheduledEvent);
// remove in separate loop to avoid concurrent modification error
scheduledEvents.removeIf(eventsToTrigger::contains);
}
The implementation of the scheduled events was driven by several key factors:
- Independent of time system: e.g. Can set hostile to attack every 1.5s instead of converting to ingame time.
- Improve gameplay features: Introducing delays can add more depth to gameplay, e.g. playing animation to warn player before hostile shoots projectile.
- Simplifies code: Similar functionality can be achieved by listening to time updates from
TimeService
. However this would involve keeping track of and incrementing multiple counters. - Precise Timing: Allows delays to be precisely configured based on input seconds. e.g. shoot projectile 0.2s after attack animation.
- Complies with current code: LibGdx already provides its own TaskScheduler. However the functions will trigger even when the
TimeService
is paused and so cannot be used.