shuyi_ui/hurry.rs
1//! [`HurryClock`]: the time of something timed that the player can hurry by
2//! holding a key and finish with a press (ticket 2312): a text box typing
3//! out, a tally counting up, a fight played back.
4
5use crate::input::frame_seconds;
6
7/// How much faster time passes while the key is held, once it has been
8/// held for [`HURRY_DELAY`] (the text box's fast forward).
9pub const HURRY_FACTOR: f32 = 6.0;
10/// Seconds the key must be held before time passes faster, so the tap
11/// that started the step doesn't hurry it.
12pub const HURRY_DELAY: f32 = 0.3;
13
14/// The clock of one timed step: each frame's seconds as they pass, faster
15/// once the player has held the key a moment, and whether a press has
16/// skipped the step.
17///
18/// Its owner calls [`tick`](Self::tick) each frame with whether the key
19/// that hurries is held, and moves its step on by the seconds it returns.
20/// A press calls [`skip`](Self::skip), and the owner, seeing
21/// [`is_skipped`](Self::is_skipped), finishes the step at once. A new step
22/// [`reset`](Self::reset)s the clock.
23///
24/// The hold counts from the first frame the key is held, including that
25/// frame: the part of a frame past [`delay`](Self::delay) goes
26/// [`factor`](Self::factor) times as fast, the part before it as fast as
27/// ever.
28#[derive(Debug, Clone, Copy, PartialEq)]
29pub struct HurryClock {
30 /// Seconds the key must be held before time passes faster.
31 pub delay: f32,
32 /// How much faster time passes after that.
33 pub factor: f32,
34 /// Seconds the key has been held, this frame's included.
35 held_s: f32,
36 /// Whether a press has skipped the step.
37 skipped: bool,
38}
39
40impl Default for HurryClock {
41 /// The text box's: [`HURRY_DELAY`] and [`HURRY_FACTOR`].
42 fn default() -> Self {
43 Self::new(HURRY_DELAY, HURRY_FACTOR)
44 }
45}
46
47impl HurryClock {
48 /// A clock that passes time `factor` times as fast once the key has
49 /// been held `delay` seconds; nothing held, nothing skipped.
50 pub const fn new(delay: f32, factor: f32) -> Self {
51 Self {
52 delay,
53 factor,
54 held_s: 0.0,
55 skipped: false,
56 }
57 }
58
59 /// `dt` seconds on, with the key `held` or not: the seconds that pass
60 /// this frame ([`hold`](Self::hold), then [`passing`](Self::passing)).
61 pub fn tick(&mut self, dt: f32, held: bool) -> f32 {
62 self.hold(held, dt);
63 self.passing(dt)
64 }
65
66 /// Counts `dt` seconds of the key held, or, let go, starts the count
67 /// over. A `dt` that is not finite or is negative counts as 0.
68 pub fn hold(&mut self, held: bool, dt: f32) {
69 if held {
70 self.held_s += frame_seconds(dt);
71 } else {
72 self.held_s = 0.0;
73 }
74 }
75
76 /// The seconds that pass for a frame of `dt` that the key has been held
77 /// through so far: `dt`, with the part of it past the delay
78 /// [`factor`](Self::factor) times as fast. A `dt` that is not finite
79 /// or is negative counts as 0.
80 pub fn passing(&self, dt: f32) -> f32 {
81 let dt = frame_seconds(dt);
82 let fast = (self.held_s - self.delay).clamp(0.0, dt);
83 dt + fast * (self.factor - 1.0)
84 }
85
86 /// The key is no longer counted as held (the step waits on something
87 /// else), as if let go.
88 pub fn release(&mut self) {
89 self.held_s = 0.0;
90 }
91
92 /// A press finishes the step: [`is_skipped`](Self::is_skipped) until
93 /// [`reset`](Self::reset).
94 pub fn skip(&mut self) {
95 self.skipped = true;
96 }
97
98 /// Whether a press has skipped the step.
99 pub fn is_skipped(&self) -> bool {
100 self.skipped
101 }
102
103 /// A new step: nothing held, nothing skipped, the same delay and
104 /// factor.
105 pub fn reset(&mut self) {
106 self.held_s = 0.0;
107 self.skipped = false;
108 }
109}
110
111#[cfg(test)]
112mod tests;