Refactor menu input a bit
This commit is contained in:
+87
-46
@@ -1,65 +1,106 @@
|
||||
use bevy::prelude::*;
|
||||
|
||||
use crate::{game_settings::GameSettings, input::{LocalInputAssignments, LocalInputSource}};
|
||||
use crate::input::{
|
||||
GamepadBinding, LocalInputSource, MenuInputMap, MenuInputMapAction,
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Clone)]
|
||||
pub struct MenuInput {
|
||||
pub movement: Vec2,
|
||||
pub accept: bool
|
||||
pub accept: bool,
|
||||
pub back: bool,
|
||||
pub start: bool,
|
||||
}
|
||||
|
||||
#[derive(Resource, Default)]
|
||||
pub struct MenuInputState {
|
||||
pub inputs: Vec<(LocalInputSource, MenuInput)>,
|
||||
}
|
||||
|
||||
impl MenuInputState {
|
||||
pub fn get(&self, source: &LocalInputSource) -> MenuInput {
|
||||
self.inputs.iter().find(|(candidate, _)| candidate == source).map(|(_, input)| input.clone()).unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn aggregate(&self) -> MenuInput {
|
||||
self.inputs.iter().fold(MenuInput::default(), |mut result, (_, input)| {
|
||||
result.movement += input.movement;
|
||||
result.accept |= input.accept;
|
||||
result.back |= input.back;
|
||||
result.start |= input.start;
|
||||
result
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl MenuInput {
|
||||
|
||||
pub fn accumulate(&mut self, other: &Self) {
|
||||
self.movement += other.movement;
|
||||
self.movement = self.movement.normalize();
|
||||
self.accept = self.accept || other.accept;
|
||||
self.accept |= other.accept;
|
||||
self.back |= other.back;
|
||||
self.start |= other.start;
|
||||
self.movement = self.movement.clamp_length_max(1.0);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_gamepad(gamepad: &Gamepad, game_settings: &GameSettings) -> Self {
|
||||
let mut x = gamepad.left_stick().x;
|
||||
let mut y = gamepad.left_stick().y;
|
||||
|
||||
let deadzone = game_settings.input_common.stick_deadzone.to_num::<f32>();
|
||||
|
||||
if x.abs() < deadzone {
|
||||
x = 0.0;
|
||||
}
|
||||
|
||||
if y.abs() < deadzone {
|
||||
y = 0.0;
|
||||
}
|
||||
|
||||
MenuInput {
|
||||
movement: Vec2::new(x, y),
|
||||
accept: gamepad.pressed(GamepadButton::South)
|
||||
fn keyboard_input(key: &ButtonInput<KeyCode>, map: &MenuInputMap) -> MenuInput {
|
||||
let mut input = MenuInput::default();
|
||||
for binding in &map.keyboard {
|
||||
let pressed = key.pressed(binding.key);
|
||||
match binding.action {
|
||||
MenuInputMapAction::MovementXDir(sign) => {
|
||||
input.movement.x += if pressed { sign as f32 } else { 0.0 };
|
||||
}
|
||||
MenuInputMapAction::MovementYDir(sign) => {
|
||||
input.movement.y += if pressed { sign as f32 } else { 0.0 };
|
||||
}
|
||||
MenuInputMapAction::Accept => input.accept |= pressed,
|
||||
MenuInputMapAction::Back => input.back |= pressed,
|
||||
MenuInputMapAction::Start => input.start |= pressed,
|
||||
}
|
||||
}
|
||||
pub fn from_keyboard(keeb: &ButtonInput<KeyCode>) -> Self {
|
||||
let x = if keeb.pressed(KeyCode::KeyA) { -1.0 } else { 0.0 };
|
||||
let x = x + if keeb.pressed(KeyCode::KeyD) { 1.0 } else { 0.0 };
|
||||
let y = if keeb.pressed(KeyCode::KeyS) { -1.0 } else { 0.0 };
|
||||
let y = y + if keeb.pressed(KeyCode::KeyW) { 1.0 } else { 0.0 };
|
||||
input.accept = map.keyboard.iter().any(|binding| matches!(binding.action, MenuInputMapAction::Accept) && key.pressed(binding.key));
|
||||
input.back = map.keyboard.iter().any(|binding| matches!(binding.action, MenuInputMapAction::Back) && key.pressed(binding.key));
|
||||
input.start = map.keyboard.iter().any(|binding| matches!(binding.action, MenuInputMapAction::Start) && key.pressed(binding.key));
|
||||
input.movement = input.movement.normalize_or_zero();
|
||||
input
|
||||
}
|
||||
|
||||
let movement = Vec2::new(x, y);
|
||||
MenuInput {
|
||||
movement: movement,
|
||||
accept: keeb.pressed(KeyCode::Enter)
|
||||
fn gamepad_input(pad: &Gamepad, map: &MenuInputMap, deadzone: f32) -> MenuInput {
|
||||
let mut input = MenuInput::default();
|
||||
for binding in &map.gamepad {
|
||||
let (value, just_pressed) = match binding.binding {
|
||||
GamepadBinding::Button(button) => (if pad.pressed(button) { 1.0 } else { 0.0 }, pad.just_pressed(button)),
|
||||
GamepadBinding::Axis(axis, sign) => (pad.get(axis).unwrap_or_default() * sign as f32, false),
|
||||
};
|
||||
match binding.action {
|
||||
MenuInputMapAction::MovementXDir(sign) => {
|
||||
input.movement.x += value * sign as f32;
|
||||
}
|
||||
MenuInputMapAction::MovementYDir(sign) => {
|
||||
input.movement.y += value * sign as f32;
|
||||
}
|
||||
MenuInputMapAction::Accept => { input.accept |= value > 0.5; input.accept |= just_pressed; }
|
||||
MenuInputMapAction::Back => { input.back |= value > 0.5; input.back |= just_pressed; }
|
||||
MenuInputMapAction::Start => { input.start |= value > 0.5; input.start |= just_pressed; }
|
||||
}
|
||||
}
|
||||
if input.movement.x.abs() < deadzone { input.movement.x = 0.0; }
|
||||
if input.movement.y.abs() < deadzone { input.movement.y = 0.0; }
|
||||
input.movement = input.movement.clamp_length_max(1.0);
|
||||
input
|
||||
}
|
||||
|
||||
pub fn from_source(source: &LocalInputSource, key: &ButtonInput<KeyCode>, gamepads: &Query<(Entity, &Gamepad)>, assignments: &LocalInputAssignments, game_settings: &GameSettings) -> Self {
|
||||
match source {
|
||||
LocalInputSource::Keyboard => Self::from_keyboard(key),
|
||||
LocalInputSource::Gamepad(entity) => {
|
||||
let gamepad = gamepads.get(*entity);
|
||||
|
||||
if let Ok((_, gamepad)) = gamepad {
|
||||
Self::from_gamepad(gamepad, game_settings)
|
||||
} else {
|
||||
Self::default()
|
||||
}
|
||||
},
|
||||
}
|
||||
pub fn sample_menu_inputs(
|
||||
key: Res<ButtonInput<KeyCode>>,
|
||||
map: Res<MenuInputMap>,
|
||||
pads: Query<(Entity, &Gamepad)>,
|
||||
mut state: ResMut<MenuInputState>,
|
||||
) {
|
||||
state.inputs.clear();
|
||||
let deadzone = 0.275;
|
||||
state.inputs.push((LocalInputSource::Keyboard, keyboard_input(&key, &map)));
|
||||
for (entity, pad) in pads.iter() {
|
||||
state.inputs.push((LocalInputSource::Gamepad(entity), gamepad_input(pad, &map, deadzone)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user