use bevy::{
input::{
gamepad::{GamepadAxisChangedEvent, GamepadButtonChangedEvent},
mouse::MouseMotion,
},
prelude::*,
state::state::FreelyMutableState,
};
use std::marker::PhantomData;
use crate::accumulative::{
accumulative_control::AccumulativeControl,
accumulative_input::AccumulativeInputs,
accumulative_sensitivity::{GamepadSensitivity, MouseSensitivity},
};
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);
}
}
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>,
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))
.chain(
gamepad_axis_input
.read()
.map(|ga| (AccumulativeInputs::GamepadAxis(ga.axis), ga.value)),
);
for (inputs, value) in analog_inputs {
let interacted_controls = active_controls
.iter_mut()
.filter(|c| c.mappings.contains(&inputs));
for control in interacted_controls {
control.set_gamepade_input(value * **gamepad_sensitivity);
}
}
for motion in mouse_input.read() {
let interacted_x_controls = active_controls
.iter_mut()
.filter(|c| c.mappings.contains(&AccumulativeInputs::MouseX));
for control in interacted_x_controls {
control.add_input(motion.delta.x * **mouse_sensitivity);
}
let interacted_y_controls = active_controls
.iter_mut()
.filter(|c| c.mappings.contains(&AccumulativeInputs::MouseY));
for control in interacted_y_controls {
control.add_input(motion.delta.y * **mouse_sensitivity);
}
}
for control in active_controls.iter_mut() {
control.update_value();
}
}
}