Skip to content
Snippets Groups Projects
double_click.rs 2.28 KiB
Newer Older
use bevy::ecs::system::SystemParam;

use crate::prelude::*;
use std::{fmt::Debug, time::Duration};

pub(crate) fn plugin(app: &mut App) {
    app.init_resource::<ClickStateRes>()
        .register_type::<ClickStateRes>()
        .add_systems(Update, tick);
}

#[derive(SystemParam)]
pub struct ClickState<'w> {
    res: ResMut<'w, ClickStateRes>,
}

/// Actual state struct
#[derive(Resource, Reflect)]
#[reflect(Resource)]
struct ClickStateRes {
    timer_since_last_click: Timer,
    click_state: Option<ClickCount>,
}

impl Default for ClickStateRes {
    fn default() -> Self {
        Self {
            timer_since_last_click: Timer::from_seconds(0.5, TimerMode::Once),
            click_state: None,
        }
    }
}

#[derive(Reflect, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum ClickCount {
    Single,
    Double,
    Triple,
    MoreThanTriple,
}

impl ClickCount {
    fn advance(self) -> Self {
        match self {
            Self::Single => Self::Double,
            Self::Double => Self::Triple,
            Self::Triple => Self::MoreThanTriple,
            Self::MoreThanTriple => Self::MoreThanTriple,
        }
    }
}

impl ClickState<'_> {
    /// Makes [ClickState] aware of a click event.
    pub fn feed_click(&mut self) -> ClickCount {
        self.res.timer_since_last_click.reset();
        match self.res.click_state {
            None => {
                self.res.click_state = Some(ClickCount::Single);
                ClickCount::Single
            }
            Some(click_count) => {
                let new_click_count = click_count.advance();
                self.res.click_state = Some(new_click_count);
                new_click_count
            }
        }
    }

    /// Get the current click state.
    ///
    /// `None` means no clicks have been registered recently
    #[allow(dead_code)]
    pub fn get(&self) -> Option<ClickCount> {
        self.res.click_state
    }

    /// You must call this every frame
    pub(crate) fn tick(&mut self, delta: Duration) {
        self.res.timer_since_last_click.tick(delta);

        if self.res.timer_since_last_click.just_finished() {
            self.res.click_state = None;
            // debug!("Resetting click timer");
        }
    }
}

fn tick(mut state: ClickState, time: Res<Time>) {
    state.tick(time.delta());
}