veloren/common/src/comp/controller.rs

202 lines
5.7 KiB
Rust
Raw Normal View History

2019-11-24 20:12:03 +00:00
use crate::sync::Uid;
use specs::{Component, FlaggedStorage};
use specs_idvs::IDVStorage;
2019-11-29 15:20:35 +00:00
use std::time::Duration;
2019-07-29 19:54:58 +00:00
use vek::*;
2019-06-09 14:20:20 +00:00
/// Default duration before an input is considered 'held'.
pub const DEFAULT_HOLD_DURATION: Duration = Duration::from_millis(200);
2019-11-29 15:20:35 +00:00
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum ControlEvent {
Mount(Uid),
Unmount,
InventoryManip(InventoryManip),
//Respawn,
}
2019-11-29 15:20:35 +00:00
/// The various states an input can be in
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum InputState {
Pressed,
Unpressed,
}
/// Whether a key is pressed or unpressed
/// and how long it has been in that state
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Input {
/// Should not be pub because duration should
/// always be reset when state is updated
2019-11-29 15:20:35 +00:00
state: InputState,
/// Should only be updated by npc agents
/// through appropriate fn
2019-11-29 15:20:35 +00:00
duration: Duration,
/// Turned off first tick after switching states
just_changed: bool,
/// Set when `set_state` is called. Needed so
/// tick after change doesn't immediately unset `just_changed`
dirty: bool,
2019-11-29 15:20:35 +00:00
}
impl Input {
fn tick(&mut self, dt: Duration) {
// Increase how long input has been in current state
self.duration = self.duration.checked_add(dt).unwrap_or_default();
if self.dirty {
// Unset dirty first tick after changing into current state
self.dirty = false;
} else {
// Otherwise, just changed is always false
self.just_changed = false;
}
}
2019-11-29 15:20:35 +00:00
/// Whether input is in `InputState::Pressed` state
pub fn is_pressed(&self) -> bool { self.state == InputState::Pressed }
/// Whether it's the first frame this input has been in
/// its current state
2020-02-09 21:15:10 +00:00
pub fn is_just_pressed(&self) -> bool { self.just_changed && self.is_pressed() }
2019-11-29 15:20:35 +00:00
/// Whether input has been in current state longer than
/// `DEFAULT_HOLD_DURATION`
pub fn is_held_down(&self) -> bool {
2020-02-09 21:15:10 +00:00
self.is_pressed() && self.duration >= DEFAULT_HOLD_DURATION
2019-11-29 15:20:35 +00:00
}
2020-01-16 13:28:45 +00:00
/// Whether input has been pressed for longer than `threshold`
2020-01-08 13:17:36 +00:00
pub fn is_long_press(&self, threshold: Duration) -> bool {
2020-03-07 21:03:10 +00:00
self.is_pressed() && self.duration >= threshold
2020-01-08 13:17:36 +00:00
}
/// Handles logic of updating state of Input
2019-11-29 15:20:35 +00:00
pub fn set_state(&mut self, new_state: bool) {
// Only update if state switches
match (self.is_pressed(), new_state) {
(false, true) => {
self.just_changed = true;
self.dirty = true;
2019-11-29 15:20:35 +00:00
self.state = InputState::Pressed;
self.duration = Duration::default();
},
(true, false) => {
self.just_changed = true;
self.dirty = true;
2019-11-29 15:20:35 +00:00
self.state = InputState::Unpressed;
self.duration = Duration::default();
},
(_, _) => {},
2019-11-29 15:20:35 +00:00
};
}
/// Increases `input::duration` by `dur`
2019-11-29 15:20:35 +00:00
pub fn inc_dur(&mut self, dur: Duration) {
self.duration = self.duration.checked_add(dur).unwrap_or_default();
2019-11-29 15:20:35 +00:00
}
/// Returns `input::duration`
pub fn get_dur(&self) -> Duration { self.duration }
2019-11-29 15:20:35 +00:00
}
impl Default for Input {
fn default() -> Self {
Self {
state: InputState::Unpressed,
duration: Duration::default(),
just_changed: false,
dirty: false,
2019-11-29 15:20:35 +00:00
}
}
}
2019-06-09 14:20:20 +00:00
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct ControllerInputs {
2019-11-29 15:20:35 +00:00
pub primary: Input,
pub secondary: Input,
2020-03-24 12:59:53 +00:00
pub ability3: Input,
2019-11-29 15:20:35 +00:00
pub sit: Input,
pub jump: Input,
pub roll: Input,
pub glide: Input,
pub climb: Input,
pub climb_down: Input,
pub wall_leap: Input,
pub respawn: Input,
pub toggle_wield: Input,
2020-03-21 17:26:38 +00:00
pub swap_loadout: Input,
pub charge: Input,
pub move_dir: Vec2<f32>,
pub look_dir: Vec3<f32>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct Controller {
pub inputs: ControllerInputs,
// TODO: consider SmallVec
pub events: Vec<ControlEvent>,
}
2019-11-29 15:20:35 +00:00
impl ControllerInputs {
/// Updates all inputs, accounting for delta time
pub fn tick(&mut self, dt: Duration) {
self.primary.tick(dt);
self.secondary.tick(dt);
2020-03-24 12:59:53 +00:00
self.ability3.tick(dt);
self.sit.tick(dt);
self.jump.tick(dt);
self.roll.tick(dt);
self.glide.tick(dt);
self.climb.tick(dt);
self.climb_down.tick(dt);
self.wall_leap.tick(dt);
self.respawn.tick(dt);
self.toggle_wield.tick(dt);
2020-03-21 17:26:38 +00:00
self.swap_loadout.tick(dt);
self.charge.tick(dt);
}
2020-03-24 12:59:53 +00:00
pub fn holding_ability_key(&self) -> bool {
self.primary.is_pressed() || self.secondary.is_pressed() || self.ability3.is_pressed()
}
2019-11-29 15:20:35 +00:00
}
impl Controller {
2019-11-29 15:20:35 +00:00
/// Sets all inputs to default
pub fn reset(&mut self) { *self = Self::default(); }
pub fn clear_events(&mut self) { self.events.clear(); }
pub fn push_event(&mut self, event: ControlEvent) { self.events.push(event); }
2019-06-09 14:20:20 +00:00
}
impl Component for Controller {
type Storage = FlaggedStorage<Self, IDVStorage<Self>>;
2019-06-09 14:20:20 +00:00
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum MountState {
Unmounted,
MountedBy(Uid),
}
impl Component for MountState {
type Storage = FlaggedStorage<Self, IDVStorage<Self>>;
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Mounting(pub Uid);
impl Component for Mounting {
type Storage = FlaggedStorage<Self, IDVStorage<Self>>;
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum InventoryManip {
Pickup(Uid),
Collect(Vec3<i32>),
Use(usize),
Swap(usize, usize),
Drop(usize),
}