use bevy::{
input::{
gamepad::{GamepadAxisChangedEvent, GamepadButtonChangedEvent},
mouse::{MouseMotion, MouseWheel},
},
prelude::*,
state::state::FreelyMutableState,
};
use std::marker::PhantomData;
use crate::{
accumulative::{
accumulative_control::AccumulativeControl,
accumulative_input::AccumulativeInputs,
accumulative_sensitivity::{GamepadSensitivity, MouseSensitivity},
},
read_input_systems::ReadInputSystems,
};
pub struct AccumulativePlugin<TContext, TAction>(PhantomData<TContext>, PhantomData<TAction>);
impl<TC, TA> Default for AccumulativePlugin<TC, TA> {
fn default() -> Self {
Self(Default::default(), Default::default())
}
}
impl<TContext: FreelyMutableState + FromWorld, TAction: Sync + Send + 'static> Plugin
for AccumulativePlugin<TContext, TAction>
{
fn build(&self, app: &mut App) {
app.init_state::<TContext>()
.init_resource::<MouseSensitivity>()
.init_resource::<GamepadSensitivity>()
.add_systems(Update, Self::check_controls.in_set(ReadInputSystems));
}
}
impl<TContext: States, TAction: Sync + Send + 'static> AccumulativePlugin<TContext, TAction> {
fn check_controls(
mut controls: Query<&mut AccumulativeControl<TContext, TAction>>,
context: Res<State<TContext>>,
mut gamepad_button_input: MessageReader<GamepadButtonChangedEvent>,
mut gamepad_axis_input: MessageReader<GamepadAxisChangedEvent>,
mut mouse_input: MessageReader<MouseMotion>,
mut wheel_events: MessageReader<MouseWheel>,
mouse_sensitivity: Res<MouseSensitivity>,
gamepad_sensitivity: Res<GamepadSensitivity>,
) {
let mut active_controls = controls
.iter_mut()
.filter(|c| c.contexts.contains(&context.get()))
.collect::<Vec<_>>();
let gamepad_inputs = gamepad_button_input.read().collect::<Vec<_>>();
let analog_inputs = gamepad_inputs
.iter()
.map(|g| {
(
AccumulativeInputs::Gamepad(g.button),
g.value * **gamepad_sensitivity,
)
})
.chain(gamepad_axis_input.read().map(|ga| {
(
AccumulativeInputs::GamepadAxis(ga.axis),
ga.value * **gamepad_sensitivity,
)
}))
.chain(wheel_events.read().flat_map(|we| {
[
(AccumulativeInputs::MouseWheelVertical, we.y),
(AccumulativeInputs::MouseWheelHorizontal, we.x),
]
}))
.chain(mouse_input.read().flat_map(|me| {
[
(AccumulativeInputs::MouseX, me.delta.x * **mouse_sensitivity),
(AccumulativeInputs::MouseY, me.delta.y * **mouse_sensitivity),
]
}));
for (inputs, value) in analog_inputs {
let interacted_controls = active_controls
.iter_mut()
.map(|c| (c.mappings.iter().find(|(m, _)| m == &inputs).cloned(), c));
for (mapping, control) in interacted_controls {
let Some((input_type, sensitivity)) = mapping else {
continue;
};
match input_type {
AccumulativeInputs::Gamepad(_) => {
control.set_gamepade_input(value * sensitivity)
}
AccumulativeInputs::GamepadAxis(_) => {
control.set_gamepade_input(value * sensitivity)
}
_ => control.add_input(value * sensitivity),
}
}
}
for control in active_controls.iter_mut() {
control.update_value();
}
}
}