Skip to main content

Time

Struct Time 

Source
pub struct Time { /* private fields */ }
Expand description

Frame timing and a simple named-event scheduler. Available as ctx.time.

// Fire an event called "spawn" every 2.5 seconds of game time.
ctx.time.every("spawn", 2.5);
// ...later, in update():
if ctx.time.fired("spawn") {
    ctx.speech.speak("A new enemy appears");
}

Implementations§

Source§

impl Time

Source

pub fn delta(&self) -> f32

Seconds of game time since the previous frame (affected by Time::set_scale).

Multiply speeds by this to make movement frame rate independent: position.x += speed * ctx.time.delta();

Examples found in repository?
examples/bell_catcher.rs (line 254)
228    fn update(&mut self, ctx: &mut Context) {
229        if self.over {
230            if ctx.ui.closed("over") {
231                ctx.switch_scene(Title);
232            }
233            return;
234        }
235        if ctx.pressed(Key::Escape) {
236            ctx.switch_scene(Title);
237            return;
238        }
239        if ctx.pressed(Key::S) {
240            ctx.speak(format!("{} bells, {} lives", self.score, self.lives));
241        }
242        for (key, step) in [(Key::Left, -1), (Key::Right, 1)] {
243            if ctx.input.repeating(key, 0.3, 0.15) {
244                let lane = (self.lane + step).clamp(-LANES, LANES);
245                if lane == self.lane {
246                    ctx.play("edge");
247                } else {
248                    self.lane = lane;
249                    ctx.audio.sound("step").at(vec3(step as f32 * 0.5, 0.0, 0.0)).random_pitch(0.9, 1.1).play();
250                }
251            }
252        }
253
254        let dt = ctx.time.delta();
255        if self.left < 0.0 {
256            self.left += dt;
257            if self.left >= 0.0 {
258                self.drop_bell();
259            }
260            return;
261        }
262        self.left -= dt;
263        self.next_ring -= dt;
264        if self.left <= 0.0 {
265            self.land(ctx);
266        } else if self.next_ring <= 0.0 {
267            self.ring(ctx);
268        }
269    }
More examples
Hide additional examples
examples/flight.rs (line 89)
75    fn update(&mut self, ctx: &mut Context) {
76        if ctx.pressed(Key::Escape) {
77            ctx.quit();
78        }
79        if ctx.pressed(Key::Left) || ctx.pressed(Key::Right) {
80            let facing = ctx.physics.turn(self.drone, if ctx.pressed(Key::Left) { -30.0 } else { 30.0 });
81            ctx.speak(math::direction_name(facing));
82        }
83        if ctx.pressed(Key::PageUp) || ctx.pressed(Key::PageDown) {
84            let pitch = ctx.physics.tilt(self.drone, if ctx.pressed(Key::PageUp) { 30.0 } else { -30.0 });
85            ctx.speak(describe_pitch(pitch));
86        }
87
88        // Smooth flight: 4 meters per second while a key is held.
89        let speed = 4.0 * ctx.time.delta();
90        let forward = ctx.input.axis(Key::Down, Key::Up);
91        if forward != 0.0 {
92            let result = ctx.physics.move_forward(self.drone, forward * speed);
93            self.fly(ctx, result);
94        }
95        let rise = ctx.input.axis(Key::Q, Key::E);
96        if rise != 0.0 {
97            let result = ctx.physics.move_up(self.drone, rise * speed);
98            self.fly(ctx, result);
99        }
100
101        if ctx.pressed(Key::C) {
102            let position = ctx.physics.position(self.drone);
103            match ctx.physics.nearest_with_tag(position, "bird") {
104                Some(bird) => {
105                    let text = ctx.physics.describe(self.drone, bird); // e.g. "2 o'clock, 9 meters, 6 meters above"
106                    ctx.speak(text);
107                }
108                None => ctx.speak("No birds left"),
109            }
110        }
111        if ctx.pressed(Key::F) {
112            let (facing, pitch) = (ctx.physics.facing(self.drone), ctx.physics.pitch(self.drone));
113            ctx.speak(format!("Facing {}, {}", math::direction_name(facing), describe_pitch(pitch)));
114        }
115        if ctx.pressed(Key::H) {
116            let height = ctx.physics.position(self.drone).z;
117            ctx.speak(format!("{height:.0} meters high"));
118        }
119
120        if let Some(bird) = ctx.physics.entered_tag(self.drone, "bird") {
121            ctx.physics.remove(bird);
122            self.birds -= 1;
123            ctx.play("found");
124            if self.birds == 0 {
125                ctx.ui.message("done", "You found every bird!");
126            } else {
127                ctx.speak(format!("Bird found! {} left.", self.birds));
128            }
129        }
130        if ctx.ui.closed("done") {
131            ctx.quit();
132        }
133    }
Source

pub fn real_delta(&self) -> f32

Like Time::delta but ignores the time scale. Useful for menus while the game is paused.

Source

pub fn elapsed(&self) -> f64

Seconds of game time since the game started.

Examples found in repository?
examples/hello.rs (line 17)
14    fn update(&mut self, ctx: &mut Context) {
15        if ctx.input.pressed(Key::Space) {
16            // A pitch that rises over time, so every beep sounds different.
17            let pitch = 300.0 + (ctx.time.elapsed() as f32 * 50.0) % 900.0;
18            ctx.audio.play_tone(pitch.round(), 0.15);
19        }
20        if ctx.input.pressed(Key::F1) {
21            ctx.speech.repeat_last();
22        }
23        if ctx.input.pressed(Key::Escape) {
24            ctx.quit();
25        }
26    }
More examples
Hide additional examples
examples/platformer.rs (line 64)
58    fn update(&mut self, ctx: &mut Context) {
59        if ctx.pressed(Key::Escape) {
60            ctx.quit();
61        }
62
63        // The lift goes up for 4 seconds and down for 4 seconds.
64        let lift_up = (ctx.time.elapsed() % 8.0) < 4.0;
65        ctx.physics.set_velocity(self.lift, vec3(0.0, 0.0, if lift_up { 2.0 } else { -2.0 }));
66
67        let run = ctx.input.axis(Key::Left, Key::Right);
68        let mut velocity = ctx.physics.velocity(self.player);
69        velocity.x = run * 6.0;
70        ctx.physics.set_velocity(self.player, velocity);
71        if ctx.pressed(Key::Space) && ctx.physics.jump(self.player, 2.5) {
72            ctx.play("jump");
73        }
74        let running = ctx.physics.on_ground(self.player) && run != 0.0;
75        self.run_sound.set_volume(if running { 0.6 } else { 0.0 });
76
77        if let Some(speed) = ctx.physics.landed(self.player) {
78            ctx.audio.sound("land").volume((speed / 12.0).clamp(0.2, 1.0)).play();
79            if speed > 15.0 {
80                ctx.speak("Ouch!");
81            }
82        }
83        if let Some((other, _)) = ctx.physics.collided(self.player)
84            && ctx.physics.tag(other) == "crate"
85        {
86            ctx.play_on(other, "push");
87        }
88        if let Some(coin) = ctx.physics.entered_tag(self.player, "coin") {
89            ctx.physics.remove(coin); // its looping sound stops by itself
90            self.score += 1;
91            ctx.audio.sound("coin").pitch(1.5).play();
92            ctx.speak(format!("{} of {COINS} coins", self.score));
93            if self.score == COINS {
94                ctx.ui.message("won", "You collected every coin! Press enter to quit.");
95            }
96        }
97        if ctx.ui.closed("won") {
98            ctx.quit();
99        }
100
101        if ctx.pressed(Key::S) {
102            let x = ctx.physics.position(self.player).x;
103            ctx.speak(format!("Score {}, position {x:.0}", self.score));
104        }
105    }
Source

pub fn real_elapsed(&self) -> Duration

Wall clock time since the engine started, ignoring the time scale.

Source

pub fn frame(&self) -> u64

Number of frames since the game started.

Source

pub fn fps(&self) -> f32

Current frames per second (smoothed).

Source

pub fn scale(&self) -> f32

Current time scale. 1.0 is normal speed.

Source

pub fn set_scale(&mut self, scale: f32)

Speeds up (> 1.0), slows down (< 1.0) or pauses (0.0) game time. Physics, the scheduler and Time::delta all follow the scale.

Source

pub fn pause(&mut self)

Pauses game time. Same as set_scale(0.0).

Examples found in repository?
examples/beacon.rs (line 138)
137    fn start(&mut self, ctx: &mut Context) {
138        ctx.time.pause();
139        ctx.ui.open(Menu::new("pause", "Paused").button("resume", "Resume").button("quit", "Quit game"));
140    }
Source

pub fn resume(&mut self)

Resumes game time at normal speed.

Examples found in repository?
examples/beacon.rs (line 153)
152    fn end(&mut self, ctx: &mut Context) {
153        ctx.time.resume();
154    }
Source

pub fn is_paused(&self) -> bool

Whether game time is paused.

Source

pub fn after(&mut self, name: impl Into<String>, seconds: f32)

Schedules a one-shot event named name that fires after seconds of game time. Scheduling a name that is already pending replaces it.

Examples found in repository?
examples/clicker.rs (line 15)
8fn main() -> audio_code::Result<()> {
9    let mut score = 0;
10
11    audio_code::run("Clicker", move |ctx| {
12        if ctx.once("intro") {
13            let best: u32 = ctx.storage.get_or("best", 0);
14            ctx.speak(format!("Press space as often as you can in ten seconds. Your best is {best}. Go!"));
15            ctx.time.after("end", 10.0);
16        }
17
18        if ctx.time.is_scheduled("end") && ctx.pressed(Key::Space) {
19            score += 1;
20            ctx.audio.play_tone(300.0 + score as f32 * 15.0, 0.05);
21        }
22
23        if ctx.time.fired("end") {
24            let best: u32 = ctx.storage.get_or("best", 0);
25            if score > best {
26                ctx.storage.set("best", score);
27                ctx.ui.message("result", format!("{score} presses. New record!"));
28            } else {
29                ctx.ui.message("result", format!("{score} presses. Your best is {best}."));
30            }
31        }
32
33        if ctx.ui.closed("result") || ctx.pressed(Key::Escape) {
34            ctx.quit();
35        }
36    })
37}
Source

pub fn every(&mut self, name: impl Into<String>, seconds: f32)

Schedules a repeating event named name that fires every seconds of game time. Scheduling a name that is already pending replaces it.

Source

pub fn cancel(&mut self, name: &str)

Cancels a scheduled event. Does nothing if it does not exist.

Source

pub fn is_scheduled(&self, name: &str) -> bool

Whether an event with this name is waiting to fire.

Examples found in repository?
examples/clicker.rs (line 18)
8fn main() -> audio_code::Result<()> {
9    let mut score = 0;
10
11    audio_code::run("Clicker", move |ctx| {
12        if ctx.once("intro") {
13            let best: u32 = ctx.storage.get_or("best", 0);
14            ctx.speak(format!("Press space as often as you can in ten seconds. Your best is {best}. Go!"));
15            ctx.time.after("end", 10.0);
16        }
17
18        if ctx.time.is_scheduled("end") && ctx.pressed(Key::Space) {
19            score += 1;
20            ctx.audio.play_tone(300.0 + score as f32 * 15.0, 0.05);
21        }
22
23        if ctx.time.fired("end") {
24            let best: u32 = ctx.storage.get_or("best", 0);
25            if score > best {
26                ctx.storage.set("best", score);
27                ctx.ui.message("result", format!("{score} presses. New record!"));
28            } else {
29                ctx.ui.message("result", format!("{score} presses. Your best is {best}."));
30            }
31        }
32
33        if ctx.ui.closed("result") || ctx.pressed(Key::Escape) {
34            ctx.quit();
35        }
36    })
37}
Source

pub fn remaining(&self, name: &str) -> Option<f32>

Seconds until the named event fires, or None if it is not scheduled.

Source

pub fn fired(&self, name: &str) -> bool

Returns true during the frame in which the named event fired.

Examples found in repository?
examples/clicker.rs (line 23)
8fn main() -> audio_code::Result<()> {
9    let mut score = 0;
10
11    audio_code::run("Clicker", move |ctx| {
12        if ctx.once("intro") {
13            let best: u32 = ctx.storage.get_or("best", 0);
14            ctx.speak(format!("Press space as often as you can in ten seconds. Your best is {best}. Go!"));
15            ctx.time.after("end", 10.0);
16        }
17
18        if ctx.time.is_scheduled("end") && ctx.pressed(Key::Space) {
19            score += 1;
20            ctx.audio.play_tone(300.0 + score as f32 * 15.0, 0.05);
21        }
22
23        if ctx.time.fired("end") {
24            let best: u32 = ctx.storage.get_or("best", 0);
25            if score > best {
26                ctx.storage.set("best", score);
27                ctx.ui.message("result", format!("{score} presses. New record!"));
28            } else {
29                ctx.ui.message("result", format!("{score} presses. Your best is {best}."));
30            }
31        }
32
33        if ctx.ui.closed("result") || ctx.pressed(Key::Escape) {
34            ctx.quit();
35        }
36    })
37}
Source

pub fn fired_events(&self) -> impl Iterator<Item = &str>

All events that fired this frame.

Trait Implementations§

Source§

impl Debug for Time

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Time

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl Freeze for Time

§

impl RefUnwindSafe for Time

§

impl Send for Time

§

impl Sync for Time

§

impl Unpin for Time

§

impl UnsafeUnpin for Time

§

impl UnwindSafe for Time

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync> ⓘ

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<S> FromSample<S> for S

Source§

fn from_sample_(s: S) -> S

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<F, T> IntoSample<T> for F
where T: FromSample<F>,

Source§

fn into_sample(self) -> T

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

Source§

fn to_sample_(self) -> U

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more