local multiplayer
This commit is contained in:
parent
8f6001d3ec
commit
c565692e63
|
@ -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<Input<KeyCode>>,
|
||||
mut gamepad_event: EventReader<GamepadEvent>,
|
||||
mut state: ResMut<InputState>,
|
||||
) {
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
154
src/player.rs
154
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<InputState>,
|
||||
asset_server: Res<AssetServer>,
|
||||
) {
|
||||
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<Time>, input: Res<Input<KeyCode>>, mut players: Query<(&mut Velocity, &mut Player, &mut Transform, &GroundContact)>) {
|
||||
let x;
|
||||
let z;
|
||||
let target_rotation;
|
||||
match [KeyCode::Right, KeyCode::Left, KeyCode::Up, KeyCode::Down].map(|k| input.pressed(k)) {
|
||||
[false, false, false, true] => {
|
||||
z = 1.0;
|
||||
x = 0.0;
|
||||
target_rotation = Some(0.0);
|
||||
}
|
||||
[false, true, false, true] => {
|
||||
z = 0.7;
|
||||
x = -0.7;
|
||||
target_rotation = Some(1.75 * PI);
|
||||
}
|
||||
[false, true, false, false] => {
|
||||
z = 0.0;
|
||||
x = -1.0;
|
||||
target_rotation = Some(1.5 * PI);
|
||||
}
|
||||
[false, true, true, false] => {
|
||||
z = -0.7;
|
||||
x = -0.7;
|
||||
target_rotation = Some(1.25 * PI);
|
||||
}
|
||||
[false, false, true, false] => {
|
||||
z = -1.0;
|
||||
x = 0.0;
|
||||
target_rotation = Some(1.0 * PI);
|
||||
}
|
||||
[true, false, true, false] => {
|
||||
z = -0.7;
|
||||
x = 0.7;
|
||||
target_rotation = Some(0.75 * PI);
|
||||
}
|
||||
[true, false, false, false] => {
|
||||
z = 0.0;
|
||||
x = 1.0;
|
||||
target_rotation = Some(0.5 * PI);
|
||||
}
|
||||
[true, false, false, true] => {
|
||||
z = 0.7;
|
||||
x = 0.7;
|
||||
target_rotation = Some(0.25 * PI);
|
||||
}
|
||||
_ => {
|
||||
z = 0.0;
|
||||
x = 0.0;
|
||||
target_rotation = None;
|
||||
}
|
||||
}
|
||||
|
||||
let y = if input.pressed(KeyCode::Space) {
|
||||
1.6
|
||||
} else if x != 0.0 || z != 0.0 {
|
||||
// walk bobbing
|
||||
0.3
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
pub fn input(
|
||||
time: Res<Time>,
|
||||
input: Res<InputState>,
|
||||
mut players: Query<(&mut Velocity, &mut Player, &mut Transform, &GroundContact)>
|
||||
) {
|
||||
const SPEED: f32 = 3.0;
|
||||
let target_velocity = SPEED * Vec3::new(x, y, z);
|
||||
for (mut velocity, mut player, mut transform, contact) in players.iter_mut() {
|
||||
let x;
|
||||
let z;
|
||||
let target_rotation;
|
||||
match [Key::Right, Key::Left, Key::Up, Key::Down].map(|key| input.0.contains(&(player.input_source.clone(), key))) {
|
||||
[false, false, false, true] => {
|
||||
z = 1.0;
|
||||
x = 0.0;
|
||||
target_rotation = Some(0.0);
|
||||
}
|
||||
[false, true, false, true] => {
|
||||
z = 0.7;
|
||||
x = -0.7;
|
||||
target_rotation = Some(1.75 * PI);
|
||||
}
|
||||
[false, true, false, false] => {
|
||||
z = 0.0;
|
||||
x = -1.0;
|
||||
target_rotation = Some(1.5 * PI);
|
||||
}
|
||||
[false, true, true, false] => {
|
||||
z = -0.7;
|
||||
x = -0.7;
|
||||
target_rotation = Some(1.25 * PI);
|
||||
}
|
||||
[false, false, true, false] => {
|
||||
z = -1.0;
|
||||
x = 0.0;
|
||||
target_rotation = Some(1.0 * PI);
|
||||
}
|
||||
[true, false, true, false] => {
|
||||
z = -0.7;
|
||||
x = 0.7;
|
||||
target_rotation = Some(0.75 * PI);
|
||||
}
|
||||
[true, false, false, false] => {
|
||||
z = 0.0;
|
||||
x = 1.0;
|
||||
target_rotation = Some(0.5 * PI);
|
||||
}
|
||||
[true, false, false, true] => {
|
||||
z = 0.7;
|
||||
x = 0.7;
|
||||
target_rotation = Some(0.25 * PI);
|
||||
}
|
||||
_ => {
|
||||
z = 0.0;
|
||||
x = 0.0;
|
||||
target_rotation = None;
|
||||
}
|
||||
}
|
||||
|
||||
let y = if input.0.contains(&(player.input_source.clone(), Key::Jump)) {
|
||||
1.4
|
||||
} else if x != 0.0 || z != 0.0 {
|
||||
// walk bobbing
|
||||
0.4
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
let target_velocity = SPEED * Vec3::new(x, y, z);
|
||||
|
||||
if contact.0 > 0 && velocity.linear.y.abs() < 0.2 {
|
||||
velocity.linear = target_velocity;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue