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_input_actionmap::InputMap;
@ -68,17 +68,10 @@ pub struct Collision {
pub index: usize,
}
pub const ACTION_FORWARD: &str = "forward";
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(
fn movement_controls<S, A: 'static>(
mut commands: Commands,
input: Res<InputMap<String>>,
config: Res<NavigationConfig<S, A>>,
input: Res<InputMap<A>>,
time: Res<Time>,
mut query: Query<(
Entity,
@ -91,7 +84,10 @@ fn movement_controls(
Option<&Destination>,
)>,
exploration_focused: Query<(Entity, &ExplorationFocused)>,
) {
) where
S: bevy::ecs::component::Component + Clone + Debug + Eq + Hash,
A: Hash + Eq + Clone + Send + Sync,
{
for (
entity,
_,
@ -103,47 +99,72 @@ fn movement_controls(
destination,
) 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 {
commands.entity(entity).insert(Sprinting::default());
} else {
commands.entity(entity).remove::<Sprinting>();
}
let mut direction = Vec3::default();
if input.active(ACTION_FORWARD) {
direction.x += 1.;
if let Some(action) = config.action_forward.clone() {
if input.active(action) {
direction.x += 1.;
}
}
if input.active(ACTION_BACKWARD) {
direction.x -= 1.;
if let Some(action) = config.action_backward.clone() {
if input.active(action) {
direction.x -= 1.;
}
}
if input.active(ACTION_LEFT) {
direction.y += 1.;
if let Some(action) = config.action_left.clone() {
if input.active(action) {
direction.y += 1.;
}
}
if input.active(ACTION_RIGHT) {
direction.y -= 1.;
if let Some(action) = config.action_right.clone() {
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();
if input.active(ACTION_ROTATE_LEFT) {
if input.active(rotate_left) {
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));
}
}
if direction.length_squared() != 0. {
direction = direction.normalize();
let forward_x = input.strength(ACTION_FORWARD).abs();
let backward_x = input.strength(ACTION_BACKWARD).abs();
let x = if forward_x > backward_x {
forward_x
let strength = if let (Some(forward), Some(backward), Some(left), Some(right)) = (
config.action_forward.clone(),
config.action_backward.clone(),
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 {
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 {
**max_speed
} else {
@ -151,7 +172,9 @@ fn movement_controls(
};
speed.0 = s;
direction *= s;
direction *= strength;
if let Some(strength) = strength {
direction *= strength;
}
commands.entity(entity).remove::<Destination>();
commands.entity(entity).remove::<Exploring>();
for (entity, _) in exploration_focused.iter() {
@ -407,40 +430,55 @@ fn speak_direction(
pub const MOVEMENT_LABEL: &str = "MOVEMENT";
#[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_control_states: Vec<S>,
}
impl<S> Default for NavigationConfig<S> {
impl<S, A> Default for NavigationConfig<S, A> {
fn default() -> 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_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 {
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
S: bevy::ecs::component::Component + Clone + Debug + Eq + Hash,
A: Hash + Eq + Clone + Send + Sync,
'a: 'static,
{
fn build(&self, app: &mut AppBuilder) {
if !app.world().contains_resource::<NavigationConfig<S>>() {
app.insert_resource(NavigationConfig::<S>::default());
if !app.world().contains_resource::<NavigationConfig<S, A>>() {
app.insert_resource(NavigationConfig::<S, A>::default());
}
let config = app
.world()
.get_resource::<NavigationConfig<S>>()
.get_resource::<NavigationConfig<S, A>>()
.unwrap()
.clone();
app.register_type::<MaxSpeed>()
@ -508,13 +546,13 @@ where
}
}
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 {
let states = config.movement_control_states;
for state in states {
app.add_system_set(
SystemSet::on_update(state)
.with_system(movement_controls.system().before(MOVEMENT_LABEL)),
.with_system(movement_controls::<S, A>.system().before(MOVEMENT_LABEL)),
);
}
}