Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Timers

The goal: run something later, once or repeatedly: a respawn in three seconds, a weapon’s refire, a stamina tick.

#![allow(unused)]
fn main() {
use bindings::engine::KismetSystemLibrary;

#[uclass_impl]
impl Enemy {
    #[ufunction]
    fn remove_from_level(&mut self) {
        if let Ok(me) = self.as_ref().checked() {
            me.k2_destroy_actor();
        }
    }

    #[ufunction(Override)]
    fn receive_end_play(&mut self, _end_play_reason: u8) {
        KismetSystemLibrary::k2_clear_timer(self.as_ref().upcast_to(), "RemoveFromLevel");
    }
}

impl Enemy {
    fn die(&mut self) {
        KismetSystemLibrary::k2_set_timer(
            self.as_ref().upcast_to(),
            "RemoveFromLevel",
            5.0,
            false,
            None,
            None,
            None,
        );
    }
}
}

k2_set_timer is the Blueprint node Set Timer by Function Name: it calls a function of the object, by its Unreal name, after the given seconds. The function is any #[ufunction] of the class: remove_from_level is RemoveFromLevel.

ArgumentWhat it is
objectthe object whose function is called, as UObjectRef<Object> (self.as_ref().upcast_to())
function namethe Unreal name of the function
timeseconds until the call
loopingtrue to call it every time seconds
the restinitial start delay and variance, None for the defaults

k2_clear_timer stops a timer by the same object and name. Clear the timers of an object in its receive_end_play, so none fires on an object being destroyed. Setting a timer that is already running restarts it.

Use case: a looping timer at a fixed rate

The goal: update stamina thirty times a second, whatever the frame rate.

#![allow(unused)]
fn main() {
#[ufunction(Override)]
fn receive_begin_play(&mut self) {
    KismetSystemLibrary::k2_set_timer(
        self.as_ref().upcast_to(),
        "SprintFixedTick",
        1.0 / 30.0,
        true,
        None,
        None,
        None,
    );
}

#[ufunction]
fn sprint_fixed_tick(&mut self) {
}
}

Use case: refire with a cooldown

The goal: an automatic weapon fires every refire_rate seconds while the trigger is held; a semi-automatic one fires once and waits.

#![allow(unused)]
fn main() {
#[ufunction]
fn fire(&mut self) {
    if !self.is_firing() {
        return;
    }

    let next = if self.b_full_auto() { "Fire" } else { "FireCooldownExpired" };

    KismetSystemLibrary::k2_set_timer(
        self.as_ref().upcast_to(),
        next,
        self.refire_rate(),
        false,
        None,
        None,
        None,
    );
}
}

Timers and the game’s time

Timers follow the game: they pause when the game is paused, and slow down with time dilation. To know the current game time:

#![allow(unused)]
fn main() {
let now = GameplayStatics::get_time_seconds(self.as_ref().upcast_to());
}

Comparing it with a stored time is the other way to handle cooldowns, without a timer:

#![allow(unused)]
fn main() {
if now - self.last_attack_time() > f64::from(self.cooldown()) {
    self.set_last_attack_time(now);
}
}

Every frame without an actor

receive_tick runs every frame on an actor. Code that is not an actor, or that must also run in the editor outside Play, can register a frame callback. See Work off the game thread, task::on_tick.