use bevy::{ecs::entity_disabling::Disabled, prelude::*, state::state::FreelyMutableState};
use std::marker::PhantomData;
use crate::{
analog::{analog_control::AnalogControl, analog_plugin::AnalogPlugin},
button::{button_control::ButtonControl, button_plugin::ButtonPlugin},
};
pub struct ControlsPlugin<TContext, TAction>(PhantomData<TContext>, PhantomData<TAction>);
impl<TC, TA> Default for ControlsPlugin<TC, TA> {
fn default() -> Self {
Self(Default::default(), Default::default())
}
}
impl<TContext: FreelyMutableState + FromWorld, TAction: Sync + Send + 'static> Plugin
for ControlsPlugin<TContext, TAction>
{
fn build(&self, app: &mut App) {
app.init_state::<TContext>()
.add_plugins(ButtonPlugin::<TContext, TAction>::default())
.add_plugins(AnalogPlugin::<TContext, TAction>::default())
.add_systems(Update, Self::context_change);
}
}
impl<TContext: States, TAction: Sync + Send + 'static> ControlsPlugin<TContext, TAction> {
fn context_change(
mut messages: MessageReader<StateTransitionEvent<TContext>>,
mut commands: Commands,
button_controls: Query<(Entity, &ButtonControl<TContext, TAction>, Has<Disabled>)>,
analog_controls: Query<(Entity, &AnalogControl<TContext, TAction>, Has<Disabled>)>,
) {
for message in messages.read() {
if message.entered == message.exited {
continue;
}
let controls = button_controls
.iter()
.map(|(e, b, d)| (e, &b.contexts, d))
.chain(analog_controls.iter().map(|(e, a, d)| (e, &a.contexts, d)))
.map(|(e, c, d)| (e, c.iter().map(|c| Some(c.clone())).collect::<Vec<_>>(), d));
for (entity, contexts, has_disabled) in controls {
if has_disabled && contexts.contains(&message.entered) {
commands.entity(entity).remove::<Disabled>();
}
if !has_disabled && !contexts.contains(&message.entered) {
commands.entity(entity).insert(Disabled);
}
}
info!(
"Switched control contex from {:?} to {:?}",
message.exited, message.entered
);
}
}
}