Make action type configurable.

This commit is contained in:
Nolan Darilek 2021-05-26 16:46:20 -05:00
parent 3084d02f66
commit 6871f4cb96

View File

@ -1,4 +1,4 @@
use std::{collections::HashMap, error::Error, fmt::Debug, hash::Hash}; use std::{collections::HashMap, error::Error, fmt::Debug, hash::Hash, marker::PhantomData};
use bevy::prelude::*; use bevy::prelude::*;
use bevy_input_actionmap::InputMap; use bevy_input_actionmap::InputMap;
@ -68,17 +68,10 @@ pub struct Collision {
pub index: usize, pub index: usize,
} }
pub const ACTION_FORWARD: &str = "forward"; fn movement_controls<S, A: 'static>(
pub const ACTION_BACKWARD: &str = "backward";
pub const ACTION_LEFT: &str = "left";
pub const ACTION_RIGHT: &str = "right";
pub const ACTION_ROTATE_LEFT: &str = "ROTATE_LEFT";
pub const ACTION_ROTATE_RIGHT: &str = "ROTATE_RIGHT";
pub const ACTION_SPRINT: &str = "SPRINT";
fn movement_controls(
mut commands: Commands, mut commands: Commands,
input: Res<InputMap<String>>, config: Res<NavigationConfig<S, A>>,
input: Res<InputMap<A>>,
time: Res<Time>, time: Res<Time>,
mut query: Query<( mut query: Query<(
Entity, Entity,
@ -91,7 +84,10 @@ fn movement_controls(
Option<&Destination>, Option<&Destination>,
)>, )>,
exploration_focused: Query<(Entity, &ExplorationFocused)>, exploration_focused: Query<(Entity, &ExplorationFocused)>,
) { ) where
S: bevy::ecs::component::Component + Clone + Debug + Eq + Hash,
A: Hash + Eq + Clone + Send + Sync,
{
for ( for (
entity, entity,
_, _,
@ -103,47 +99,72 @@ fn movement_controls(
destination, destination,
) in query.iter_mut() ) in query.iter_mut()
{ {
let sprinting = input.active(ACTION_SPRINT); let sprinting = if let Some(action) = config.action_sprint.clone() {
input.active(action)
} else {
false
};
if sprinting { if sprinting {
commands.entity(entity).insert(Sprinting::default()); commands.entity(entity).insert(Sprinting::default());
} else { } else {
commands.entity(entity).remove::<Sprinting>(); commands.entity(entity).remove::<Sprinting>();
} }
let mut direction = Vec3::default(); let mut direction = Vec3::default();
if input.active(ACTION_FORWARD) { if let Some(action) = config.action_forward.clone() {
direction.x += 1.; if input.active(action) {
direction.x += 1.;
}
} }
if input.active(ACTION_BACKWARD) { if let Some(action) = config.action_backward.clone() {
direction.x -= 1.; if input.active(action) {
direction.x -= 1.;
}
} }
if input.active(ACTION_LEFT) { if let Some(action) = config.action_left.clone() {
direction.y += 1.; if input.active(action) {
direction.y += 1.;
}
} }
if input.active(ACTION_RIGHT) { if let Some(action) = config.action_right.clone() {
direction.y -= 1.; if input.active(action) {
direction.y -= 1.;
}
} }
if let Some(rotation_speed) = rotation_speed { if let (Some(rotation_speed), Some(rotate_left), Some(rotate_right)) = (
rotation_speed,
config.action_rotate_left.clone(),
config.action_rotate_right.clone(),
) {
let delta = rotation_speed.radians() * time.delta_seconds(); let delta = rotation_speed.radians() * time.delta_seconds();
if input.active(ACTION_ROTATE_LEFT) { if input.active(rotate_left) {
transform.rotate(Quat::from_rotation_z(delta)); transform.rotate(Quat::from_rotation_z(delta));
} }
if input.active(ACTION_ROTATE_RIGHT) { if input.active(rotate_right) {
transform.rotate(Quat::from_rotation_z(-delta)); transform.rotate(Quat::from_rotation_z(-delta));
} }
} }
if direction.length_squared() != 0. { if direction.length_squared() != 0. {
direction = direction.normalize(); direction = direction.normalize();
let forward_x = input.strength(ACTION_FORWARD).abs(); let strength = if let (Some(forward), Some(backward), Some(left), Some(right)) = (
let backward_x = input.strength(ACTION_BACKWARD).abs(); config.action_forward.clone(),
let x = if forward_x > backward_x { config.action_backward.clone(),
forward_x config.action_left.clone(),
config.action_right.clone(),
) {
let forward_x = input.strength(forward).abs();
let backward_x = input.strength(backward).abs();
let x = if forward_x > backward_x {
forward_x
} else {
backward_x
};
let right_y = input.strength(right).abs();
let left_y = input.strength(left).abs();
let y = if right_y > left_y { right_y } else { left_y };
Some(Vec3::new(x, y, 0.))
} else { } else {
backward_x None
}; };
let right_y = input.strength(ACTION_RIGHT).abs();
let left_y = input.strength(ACTION_LEFT).abs();
let y = if right_y > left_y { right_y } else { left_y };
let strength = Vec3::new(x, y, 0.);
let s = if sprinting { let s = if sprinting {
**max_speed **max_speed
} else { } else {
@ -151,7 +172,9 @@ fn movement_controls(
}; };
speed.0 = s; speed.0 = s;
direction *= s; direction *= s;
direction *= strength; if let Some(strength) = strength {
direction *= strength;
}
commands.entity(entity).remove::<Destination>(); commands.entity(entity).remove::<Destination>();
commands.entity(entity).remove::<Exploring>(); commands.entity(entity).remove::<Exploring>();
for (entity, _) in exploration_focused.iter() { for (entity, _) in exploration_focused.iter() {
@ -407,40 +430,55 @@ fn speak_direction(
pub const MOVEMENT_LABEL: &str = "MOVEMENT"; pub const MOVEMENT_LABEL: &str = "MOVEMENT";
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct NavigationConfig<S> { pub struct NavigationConfig<S, A> {
pub action_backward: Option<A>,
pub action_forward: Option<A>,
pub action_left: Option<A>,
pub action_right: Option<A>,
pub action_rotate_left: Option<A>,
pub action_rotate_right: Option<A>,
pub action_sprint: Option<A>,
pub movement_states: Vec<S>, pub movement_states: Vec<S>,
pub movement_control_states: Vec<S>, pub movement_control_states: Vec<S>,
} }
impl<S> Default for NavigationConfig<S> { impl<S, A> Default for NavigationConfig<S, A> {
fn default() -> Self { fn default() -> Self {
Self { Self {
action_backward: None,
action_forward: None,
action_left: None,
action_right: None,
action_rotate_left: None,
action_rotate_right: None,
action_sprint: None,
movement_states: vec![], movement_states: vec![],
movement_control_states: vec![], movement_control_states: vec![],
} }
} }
} }
pub struct NavigationPlugin<'a, S>(std::marker::PhantomData<&'a S>); pub struct NavigationPlugin<'a, S, A>(PhantomData<&'a S>, std::marker::PhantomData<&'a A>);
impl<'a, S> Default for NavigationPlugin<'a, S> { impl<'a, S, A> Default for NavigationPlugin<'a, S, A> {
fn default() -> Self { fn default() -> Self {
Self(std::marker::PhantomData) Self(PhantomData, PhantomData)
} }
} }
impl<'a, S> Plugin for NavigationPlugin<'a, S> impl<'a, S, A> Plugin for NavigationPlugin<'a, S, A>
where where
S: bevy::ecs::component::Component + Clone + Debug + Eq + Hash, S: bevy::ecs::component::Component + Clone + Debug + Eq + Hash,
A: Hash + Eq + Clone + Send + Sync,
'a: 'static, 'a: 'static,
{ {
fn build(&self, app: &mut AppBuilder) { fn build(&self, app: &mut AppBuilder) {
if !app.world().contains_resource::<NavigationConfig<S>>() { if !app.world().contains_resource::<NavigationConfig<S, A>>() {
app.insert_resource(NavigationConfig::<S>::default()); app.insert_resource(NavigationConfig::<S, A>::default());
} }
let config = app let config = app
.world() .world()
.get_resource::<NavigationConfig<S>>() .get_resource::<NavigationConfig<S, A>>()
.unwrap() .unwrap()
.clone(); .clone();
app.register_type::<MaxSpeed>() app.register_type::<MaxSpeed>()
@ -508,13 +546,13 @@ where
} }
} }
if config.movement_control_states.is_empty() { if config.movement_control_states.is_empty() {
app.add_system(movement_controls.system().before(MOVEMENT_LABEL)); app.add_system(movement_controls::<S, A>.system().before(MOVEMENT_LABEL));
} else { } else {
let states = config.movement_control_states; let states = config.movement_control_states;
for state in states { for state in states {
app.add_system_set( app.add_system_set(
SystemSet::on_update(state) SystemSet::on_update(state)
.with_system(movement_controls.system().before(MOVEMENT_LABEL)), .with_system(movement_controls::<S, A>.system().before(MOVEMENT_LABEL)),
); );
} }
} }