diff --git a/src/input.rs b/src/input.rs
new file mode 100644
index 0000000..87321c6
--- /dev/null
+++ b/src/input.rs
@@ -0,0 +1,108 @@
+use std::collections::HashSet;
+use bevy::{
+ input::gamepad::{Gamepad, GamepadAxisType, GamepadButtonType, GamepadEvent, GamepadEventType},
+ prelude::*,
+};
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub enum Source {
+ KeyboardRight,
+ KeyboardLeft,
+ Gamepad(Gamepad),
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub enum Key {
+ Up,
+ Down,
+ Left,
+ Right,
+ Jump,
+}
+
+const KEYBOARD_KEYS: &[(KeyCode, Source, Key)] = &[
+ (KeyCode::Up, Source::KeyboardRight, Key::Up),
+ (KeyCode::Down, Source::KeyboardRight, Key::Down),
+ (KeyCode::Left, Source::KeyboardRight, Key::Left),
+ (KeyCode::Right, Source::KeyboardRight, Key::Right),
+ (KeyCode::Return, Source::KeyboardRight, Key::Jump),
+ (KeyCode::W, Source::KeyboardLeft, Key::Up),
+ (KeyCode::S, Source::KeyboardLeft, Key::Down),
+ (KeyCode::A, Source::KeyboardLeft, Key::Left),
+ (KeyCode::D, Source::KeyboardLeft, Key::Right),
+ (KeyCode::Space, Source::KeyboardLeft, Key::Jump),
+];
+
+const GAMEPAD_KEYS: &[(GamepadButtonType, Key)] = &[
+ (GamepadButtonType::DPadUp, Key::Up),
+ (GamepadButtonType::DPadDown, Key::Down),
+ (GamepadButtonType::DPadLeft, Key::Left),
+ (GamepadButtonType::DPadRight, Key::Right),
+ (GamepadButtonType::South, Key::Jump),
+];
+
+#[derive(Default)]
+pub struct InputState(pub HashSet<(Source, Key)>);
+
+pub fn setup(mut commands: Commands) {
+ commands.insert_resource(InputState::default());
+}
+
+pub fn handle(
+ keyboard: Res>,
+ mut gamepad_event: EventReader,
+ mut state: ResMut,
+) {
+ // handle keyboard
+ for (key_code, source, key) in KEYBOARD_KEYS {
+ if keyboard.pressed(*key_code) {
+ state.0.insert((source.clone(), *key));
+ } else {
+ state.0.remove(&(source.clone(), *key));
+ }
+ }
+
+ // handle gamepads
+ for event in gamepad_event.iter() {
+ match event {
+ GamepadEvent(gamepad, GamepadEventType::ButtonChanged(button, value)) => {
+ if let Some((_, key)) = GAMEPAD_KEYS.iter().find(|(button_, _)| {
+ button == button_
+ }) {
+ if *value > 0.01 {
+ state.0.insert((Source::Gamepad(*gamepad), *key));
+ } else {
+ state.0.remove(&(Source::Gamepad(*gamepad), *key));
+ }
+ }
+ }
+ GamepadEvent(gamepad, GamepadEventType::AxisChanged(GamepadAxisType::DPadX, value)) |
+ GamepadEvent(gamepad, GamepadEventType::AxisChanged(GamepadAxisType::LeftStickX, value)) => {
+ if *value < -0.01 {
+ state.0.insert((Source::Gamepad(*gamepad), Key::Left));
+ state.0.remove(&(Source::Gamepad(*gamepad), Key::Right));
+ } else if *value > 0.01 {
+ state.0.insert((Source::Gamepad(*gamepad), Key::Right));
+ state.0.remove(&(Source::Gamepad(*gamepad), Key::Left));
+ } else {
+ state.0.remove(&(Source::Gamepad(*gamepad), Key::Left));
+ state.0.remove(&(Source::Gamepad(*gamepad), Key::Right));
+ }
+ }
+ GamepadEvent(gamepad, GamepadEventType::AxisChanged(GamepadAxisType::DPadY, value)) |
+ GamepadEvent(gamepad, GamepadEventType::AxisChanged(GamepadAxisType::LeftStickY, value)) => {
+ if *value < -0.01 {
+ state.0.insert((Source::Gamepad(*gamepad), Key::Down));
+ state.0.remove(&(Source::Gamepad(*gamepad), Key::Up));
+ } else if *value > 0.01 {
+ state.0.insert((Source::Gamepad(*gamepad), Key::Up));
+ state.0.remove(&(Source::Gamepad(*gamepad), Key::Down));
+ } else {
+ state.0.remove(&(Source::Gamepad(*gamepad), Key::Up));
+ state.0.remove(&(Source::Gamepad(*gamepad), Key::Down));
+ }
+ }
+ _ => {}
+ }
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index f553454..26d35cb 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -5,6 +5,7 @@ use bevy::{
};
use heron::prelude::*;
+mod input;
mod camera;
mod map;
mod player;
@@ -23,13 +24,15 @@ fn main() {
.add_plugin(PhysicsPlugin::default())
.insert_resource(Gravity::from(Vec3::new(0.0, -9.81, 0.0)))
.insert_resource(ClearColor(Color::rgb(0.7, 0.7, 1.0)))
+ .add_startup_system(input::setup)
+ .add_system(input::handle.label("input"))
.add_startup_system(camera::setup)
.add_system(camera::track_players)
.add_startup_system(map::setup)
.add_system(map::build)
.add_system(map::collide)
- .add_startup_system(player::setup)
- .add_system(player::input)
+ .add_system(player::spawn_player)
+ .add_system(player::input.after("input"))
.add_system(exit_on_escape)
// .add_system(log_collisions)
.run();
diff --git a/src/player.rs b/src/player.rs
index 1b6b972..449f40a 100644
--- a/src/player.rs
+++ b/src/player.rs
@@ -1,20 +1,37 @@
use std::f32::consts::PI;
use bevy::prelude::*;
use heron::prelude::*;
+use rand::prelude::*;
use crate::{
+ input::{InputState, Key, Source as InputSource},
map::GroundContact,
Layer,
};
#[derive(Component)]
pub struct Player {
+ input_source: InputSource,
rotation: f32,
}
-pub fn setup(
+pub fn spawn_player(
mut commands: Commands,
+ players: Query<&Player>,
+ input: Res,
asset_server: Res,
) {
+ let input_source = match input.0.iter().find(|(input_source, key)|
+ if *key == Key::Jump {
+ ! players.iter().any(|player| player.input_source == *input_source)
+ } else {
+ false
+ }
+ ) {
+ Some((input_source, _)) => input_source,
+ None => return,
+ };
+ println!("New input_source: {:?}", input_source);
+
let mesh1 = asset_server.load("Mini-Game Variety Pack/Models/Characters/gltf/character_duck.gltf#Mesh0/Primitive0");
let mesh2 = asset_server.load("Mini-Game Variety Pack/Models/Characters/gltf/character_duck.gltf#Mesh0/Primitive1");
let mesh3 = asset_server.load("Mini-Game Variety Pack/Models/Characters/gltf/character_duck.gltf#Mesh0/Primitive2");
@@ -23,7 +40,8 @@ pub fn setup(
let material2 = asset_server.load("Mini-Game Variety Pack/Models/Characters/gltf/character_duck.gltf#Material1");
let material3 = asset_server.load("Mini-Game Variety Pack/Models/Characters/gltf/character_duck.gltf#Material2");
- let transform = Transform::from_xyz(0.0, 12.0, 0.0);
+ let mut rng = rand::thread_rng();
+ let transform = Transform::from_xyz(rng.gen_range(-3.0..3.0), 5.0, rng.gen_range(-3.0..3.0));
commands.spawn()
.insert(RigidBody::Dynamic)
.insert(CollisionLayers::none()
@@ -36,12 +54,13 @@ pub fn setup(
})
.insert(PhysicMaterial {
restitution: 0.0,
- density: 8.0,
+ density: 12.0,
friction: 1.0,
})
.insert(RotationConstraints::lock())
.insert(Velocity::default())
.insert(Player {
+ input_source: input_source.clone(),
rotation: 0.0,
})
.insert(GroundContact::default())
@@ -73,70 +92,75 @@ pub fn setup(
});
}
-pub fn input(time: Res