local multiplayer

This commit is contained in:
Astro 2022-01-15 02:09:12 +01:00
parent 8f6001d3ec
commit c565692e63
3 changed files with 202 additions and 67 deletions

108
src/input.rs Normal file
View File

@ -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));
}
}
_ => {}
}
}
}

View File

@ -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();

View File

@ -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;
}