use crate::prelude::GameState;
use bevy::{prelude::*, utils::HashSet};
pub use bevy::{
input::{
mouse::{MouseButton, MouseButtonInput, MouseMotion, MouseWheel},
ElementState,
},
window::CursorMoved,
};
pub struct MousePlugin;
impl Plugin for MousePlugin {
fn build(&self, app: &mut bevy::prelude::AppBuilder) {
app.insert_resource(MouseState::default())
.add_system(sync_mouse_state.system().before("game_logic_sync"))
.add_system(sync_mouse_events.system().before("game_logic_sync"));
}
}
#[derive(Clone, Debug, Default)]
pub struct MouseState {
location: Option<Vec2>,
motion: Vec2,
wheel: MouseWheelState,
pressed: HashSet<MouseButton>,
just_pressed: HashSet<MouseButton>,
just_released: HashSet<MouseButton>,
}
#[derive(Clone, Copy, Debug, Default)]
pub struct MouseWheelState {
pub y: f32,
pub x: f32,
}
impl MouseState {
pub fn location(&self) -> Option<Vec2> {
self.location
}
pub fn motion(&self) -> Vec2 {
self.motion
}
pub fn wheel(&self) -> MouseWheelState {
self.wheel
}
pub fn pressed(&self, mouse_button: MouseButton) -> bool {
self.pressed.contains(&mouse_button)
}
pub fn just_pressed(&self, mouse_button: MouseButton) -> bool {
self.just_pressed.contains(&mouse_button)
}
pub fn just_released(&self, mouse_button: MouseButton) -> bool {
self.just_released.contains(&mouse_button)
}
pub fn get_pressed(&self) -> impl ExactSizeIterator<Item = &MouseButton> {
self.pressed.iter()
}
pub fn get_just_pressed(&self) -> impl ExactSizeIterator<Item = &MouseButton> {
self.just_pressed.iter()
}
pub fn get_just_released(&self) -> impl ExactSizeIterator<Item = &MouseButton> {
self.just_released.iter()
}
}
fn sync_mouse_events(
mut game_state: ResMut<GameState>,
mut mouse_button_events: EventReader<MouseButtonInput>,
mut cursor_moved_events: EventReader<CursorMoved>,
mut mouse_motion_events: EventReader<MouseMotion>,
mut mouse_wheel_events: EventReader<MouseWheel>,
) {
game_state.mouse_button_events.clear();
game_state.mouse_location_events.clear();
game_state.mouse_motion_events.clear();
game_state.mouse_wheel_events.clear();
for ev in mouse_button_events.iter() {
game_state.mouse_button_events.push(ev.clone());
}
for ev in cursor_moved_events.iter() {
let mut new_event = ev.clone();
new_event.position -= game_state.screen_dimensions * 0.5;
game_state.mouse_location_events.push(new_event);
}
for ev in mouse_motion_events.iter() {
let mut ev2 = ev.clone();
ev2.delta.y *= -1.0;
game_state.mouse_motion_events.push(ev2.clone());
}
for ev in mouse_wheel_events.iter() {
game_state.mouse_wheel_events.push(ev.clone());
}
}
fn sync_mouse_state(
mouse_button_input: Res<Input<MouseButton>>,
mut mouse_state: ResMut<MouseState>,
mut mouse_motion_events: EventReader<MouseMotion>,
mut cursor_moved_events: EventReader<CursorMoved>,
mut mouse_wheel_events: EventReader<MouseWheel>,
game_state: Res<GameState>,
) {
if let Some(event) = cursor_moved_events.iter().last() {
let location = event.position - game_state.screen_dimensions * 0.5;
mouse_state.location = Some(location);
}
mouse_state.motion = Vec2::ZERO;
for ev in mouse_motion_events.iter() {
let mut ev2 = ev.clone();
ev2.delta.y *= -1.0;
mouse_state.motion += ev2.delta;
}
mouse_state.wheel = MouseWheelState::default();
let mut cumulative_x = 0.0;
let mut cumulative_y = 0.0;
for ev in mouse_wheel_events.iter() {
cumulative_x += ev.x;
cumulative_y += ev.y;
}
mouse_state.wheel.x = match cumulative_x {
x if x > 0.0 => 1.0,
x if x < 0.0 => -1.0,
_ => 0.0,
};
mouse_state.wheel.y = match cumulative_y {
y if y > 0.0 => 1.0,
y if y < 0.0 => -1.0,
_ => 0.0,
};
mouse_state.pressed.clear();
for mouse_button in mouse_button_input.get_pressed() {
mouse_state.pressed.insert(*mouse_button);
}
mouse_state.just_pressed.clear();
for mouse_button in mouse_button_input.get_just_pressed() {
mouse_state.just_pressed.insert(*mouse_button);
}
mouse_state.just_released.clear();
for mouse_button in mouse_button_input.get_just_released() {
mouse_state.just_released.insert(*mouse_button);
}
}