1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
//! Module for the Blink component and BlinkSystem.

use amethyst_core::{
    ecs::{Component, DenseVecStorage, Entities, Join, Read, System, WriteStorage},
    Hidden, Time,
};

#[cfg(feature = "profiler")]
use thread_profiler::profile_scope;

/// # Blink Component
/// Periodically adds and removes a `Hidden` Component on the entity this is attached to.
///
/// ## Visibility Period
/// During the first half period, the entity is visible.
/// [0, delay/2[
///
/// During the second half period, the entity is invisible.
/// [delay/2, delay]
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Blink {
    /// Period of a full blink cycle.
    pub delay: f32,
    /// Timer value keeping track of the time during the blink cycle.
    pub timer: f32,
    /// Whether to use the scaled or unscaled time.
    pub absolute_time: bool,
}

impl Component for Blink {
    type Storage = DenseVecStorage<Self>;
}

/// System updating the `Blink` component.
#[derive(Debug)]
pub struct BlinkSystem;

impl<'a> System<'a> for BlinkSystem {
    type SystemData = (
        Entities<'a>,
        WriteStorage<'a, Hidden>,
        WriteStorage<'a, Blink>,
        Read<'a, Time>,
    );

    fn run(&mut self, (entities, mut hiddens, mut blinks, time): Self::SystemData) {
        #[cfg(feature = "profiler")]
        profile_scope!("blink_system");

        let abs_sec = time.delta_seconds();
        let abs_unscaled_sec = time.delta_real_seconds();

        for (entity, blink) in (&*entities, &mut blinks).join() {
            if blink.absolute_time {
                blink.timer += abs_unscaled_sec;
            } else {
                blink.timer += abs_sec;
            }

            // Reset timer because we ended the last cycle.
            // Keeps the overflow time.
            if blink.timer > blink.delay {
                blink.timer -= blink.delay;
            }

            // We could cache the division, but that would require a stricter api on Blink.
            let on = blink.timer < blink.delay / 2.0;

            match (on, hiddens.contains(entity)) {
                (true, false) => hiddens.insert(entity, Hidden).unwrap_or_else(|_| {
                    panic!("Failed to insert Hidden component for {:?}", entity)
                }),
                (false, true) => hiddens.remove(entity),
                _ => None,
            };
        }
    }
}