aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.rs295
1 files changed, 187 insertions, 108 deletions
diff --git a/src/main.rs b/src/main.rs
index 1074319..7131c68 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -8,12 +8,16 @@ use bevy::{prelude::*, render::camera::ScalingMode, window::WindowResized};
use bevy_rapier2d::{pipeline::CollisionEvent::*, prelude::*};
-use bevy_ggrs::{GGRSPlugin, SessionType};
-use ggrs::{Config, PlayerHandle, PlayerType, SessionBuilder, UdpNonBlockingSocket};
+use bevy_ggrs::{GGRSPlugin, Rollback, RollbackIdProvider, SessionType};
+use ggrs::{
+ Config, InputStatus, P2PSession, PlayerHandle, PlayerType, SessionBuilder, SpectatorSession,
+ SyncTestSession, UdpNonBlockingSocket,
+};
use bytemuck::{Pod, Zeroable};
use std::net::SocketAddr;
+use bincode::{deserialize, serialize};
use structopt::StructOpt;
#[derive(Debug)]
@@ -24,39 +28,9 @@ impl Config for GGRSConfig {
type Address = SocketAddr;
}
-#[repr(C)]
-#[derive(Copy, Clone, PartialEq, Pod, Zeroable)]
-pub struct BoxInput {
- pub inp: u8,
-}
-
-const FPS: usize = 60;
+const FPS: usize = 10;
const ROLLBACK_DEFAULT: &str = "rollback_default";
-const INPUT_UP: u8 = 1 << 0;
-const INPUT_DOWN: u8 = 1 << 1;
-const INPUT_LEFT: u8 = 1 << 2;
-const INPUT_RIGHT: u8 = 1 << 3;
-
-pub fn input(_handle: In<PlayerHandle>, keyboard_input: Res<Input<KeyCode>>) -> BoxInput {
- let mut input: u8 = 0;
-
- if keyboard_input.pressed(KeyCode::W) {
- input |= INPUT_UP;
- }
- if keyboard_input.pressed(KeyCode::A) {
- input |= INPUT_LEFT;
- }
- if keyboard_input.pressed(KeyCode::S) {
- input |= INPUT_DOWN;
- }
- if keyboard_input.pressed(KeyCode::D) {
- input |= INPUT_RIGHT;
- }
-
- BoxInput { inp: input }
-}
-
// structopt will read command line parameters for u
#[derive(StructOpt)]
struct Opt {
@@ -105,12 +79,17 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
GGRSPlugin::<GGRSConfig>::new()
.with_update_frequency(FPS)
.with_input_system(input)
- .register_rollback_type::<Transform>()
- .register_rollback_type::<Velocity>()
+ .register_rollback_type::<SerPhysics>()
+ .register_rollback_type::<Player>()
+ .register_rollback_type::<Bullet>()
.with_rollback_schedule(
Schedule::default().with_stage(
ROLLBACK_DEFAULT,
- SystemStage::parallel()
+ SystemStage::single_threaded()
+ .with_system(physics_deser)
+ .with_system(movement)
+ .with_system(shoot)
+ .with_system(hits)
.with_system_set(RapierPhysicsPlugin::<()>::get_systems(
PhysicsStages::SyncBackend,
))
@@ -122,7 +101,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
))
.with_system_set(RapierPhysicsPlugin::<()>::get_systems(
PhysicsStages::DetectDespawn,
- )),
+ ))
+ .with_system(physics_ser),
),
)
.build(&mut app);
@@ -136,24 +116,50 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.insert_resource(sess)
.insert_resource(SessionType::P2PSession)
.add_plugins(DefaultPlugins)
- .add_startup_system(spawn_camera)
+ .add_startup_system(physics_init)
.add_startup_system(setup)
- .add_plugin(LogDiagnosticsPlugin::default())
- .add_plugin(FrameTimeDiagnosticsPlugin::default())
+ .add_startup_system(spawn_camera)
+ //.add_plugin(LogDiagnosticsPlugin::default())
+ //.add_plugin(FrameTimeDiagnosticsPlugin::default())
.add_plugin(
RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(100.0).with_default_system_setup(false),
)
- .add_plugin(RapierDebugRenderPlugin::default())
- .add_system_to_stage(CoreStage::Update, movement)
- .add_system_to_stage(CoreStage::Update, shoot)
+ //.add_plugin(RapierDebugRenderPlugin::default())
.add_system_to_stage(CoreStage::PostUpdate, camera_follow)
- .add_system_to_stage(CoreStage::PostUpdate, hits)
.add_system(window_resized_event)
.run();
Ok(())
}
+#[derive(Default, Reflect, Component)]
+struct SerPhysics {
+ pub ser: Vec<u8>,
+}
+
+fn physics_init(
+ mut commands: Commands,
+ context: Res<RapierContext>,
+ mut rip: ResMut<RollbackIdProvider>,
+) {
+ commands
+ .spawn()
+ .insert(SerPhysics {
+ ser: bincode::serialize(context.into_inner()).unwrap(),
+ })
+ .insert(Rollback::new(rip.next_id()));
+}
+
+fn physics_ser(mut ser_query: Query<&mut SerPhysics>, context: Res<RapierContext>) {
+ ser_query.single_mut().ser = bincode::serialize(context.into_inner()).unwrap();
+}
+
+fn physics_deser(ser_query: Query<&SerPhysics>, mut commands: Commands) {
+ commands.remove_resource::<RapierContext>();
+ commands
+ .insert_resource(bincode::deserialize::<RapierContext>(&ser_query.single().ser).unwrap());
+}
+
fn window_resized_event(
mut events: EventReader<WindowResized>,
mut window: ResMut<WindowDescriptor>,
@@ -167,11 +173,18 @@ fn window_resized_event(
fn camera_follow(
player_query: Query<(&Player, &Transform)>,
mut camera_query: Query<&mut Transform, (Without<Player>, With<Camera>)>,
+ p2p_session: Option<Res<P2PSession<GGRSConfig>>>,
) {
- let (_, transform) = player_query.single();
- let mut camera_transform = camera_query.single_mut();
- camera_transform.translation.x = transform.translation.x;
- camera_transform.translation.y = transform.translation.y;
+ let handles = p2p_session.unwrap().local_player_handles();
+ if handles.len() > 0 {
+ let (_, transform) = player_query
+ .iter()
+ .find(|(p, _)| p.handle == handles[0])
+ .unwrap();
+ let mut camera_transform = camera_query.single_mut();
+ camera_transform.translation.x = transform.translation.x;
+ camera_transform.translation.y = transform.translation.y;
+ }
}
fn spawn_camera(mut commands: Commands) {
@@ -205,30 +218,86 @@ fn hits(
}
}
-#[derive(Component)]
+#[derive(Component, Default, Reflect)]
pub struct Bullet;
-#[derive(Component)]
+#[derive(Component, Default, Reflect)]
pub struct Player {
- speed: f32,
- radius: f32,
+ pub handle: usize,
+ pub speed: f32,
+ pub radius: f32,
+}
+
+#[repr(C)]
+#[derive(Copy, Clone, PartialEq, Pod, Zeroable)]
+pub struct BoxInput {
+ pub inp: u8,
+ pub sx: u8,
+ pub sy: u8,
+}
+
+const INPUT_UP: u8 = 1 << 0;
+const INPUT_DOWN: u8 = 1 << 1;
+const INPUT_LEFT: u8 = 1 << 2;
+const INPUT_RIGHT: u8 = 1 << 3;
+
+pub fn input(_handle: In<PlayerHandle>, keyboard_input: Res<Input<KeyCode>>) -> BoxInput {
+ let mut input: u8 = 0;
+
+ if keyboard_input.pressed(KeyCode::W) {
+ input |= INPUT_UP;
+ }
+ if keyboard_input.pressed(KeyCode::A) {
+ input |= INPUT_LEFT;
+ }
+ if keyboard_input.pressed(KeyCode::S) {
+ input |= INPUT_DOWN;
+ }
+ if keyboard_input.pressed(KeyCode::D) {
+ input |= INPUT_RIGHT;
+ }
+
+ let mut x: u8 = 127;
+ let mut y: u8 = 127;
+ if keyboard_input.pressed(KeyCode::Up) {
+ y = 255;
+ }
+ if keyboard_input.pressed(KeyCode::Down) {
+ y = 0;
+ }
+ if keyboard_input.pressed(KeyCode::Left) {
+ x = 0;
+ }
+ if keyboard_input.pressed(KeyCode::Right) {
+ x = 255;
+ }
+
+ BoxInput {
+ inp: input,
+ sx: x,
+ sy: y,
+ }
}
-fn movement(mut player_query: Query<(&mut Player, &mut Velocity)>, keyboard: Res<Input<KeyCode>>) {
+fn movement(
+ mut player_query: Query<(&mut Player, &mut Velocity)>,
+ inputs: Res<Vec<(BoxInput, InputStatus)>>,
+) {
for (player, mut rb_vels) in player_query.iter_mut() {
+ let input = inputs[player.handle as usize].0.inp;
let mut acc = Vec2::new(0.0, 0.0);
- if keyboard.pressed(KeyCode::W) {
- acc.y += 1.0;
- }
- if keyboard.pressed(KeyCode::S) {
+ if input & INPUT_UP != 0 && input & INPUT_DOWN == 0 {
acc.y -= 1.0;
}
- if keyboard.pressed(KeyCode::A) {
+ if input & INPUT_UP == 0 && input & INPUT_DOWN != 0 {
acc.x -= 1.0;
}
- if keyboard.pressed(KeyCode::D) {
+ if input & INPUT_LEFT != 0 && input & INPUT_RIGHT == 0 {
acc.x += 1.0;
}
+ if input & INPUT_LEFT == 0 && input & INPUT_RIGHT != 0 {
+ acc.x -= 1.0;
+ }
if acc.length_squared() > 0.0 {
acc /= acc.length();
}
@@ -238,23 +307,15 @@ fn movement(mut player_query: Query<(&mut Player, &mut Velocity)>, keyboard: Res
fn shoot(
player_query: Query<(&Player, &Transform, &Velocity)>,
- keyboard: Res<Input<KeyCode>>,
+ inputs: Res<Vec<(BoxInput, InputStatus)>>,
mut commands: Commands,
+ mut rip: ResMut<RollbackIdProvider>,
) {
for (player, player_transform, _rb_vels) in player_query.iter() {
- let mut acc = Vec2::new(0.0, 0.0);
- if keyboard.pressed(KeyCode::Up) {
- acc.y += 1.0;
- }
- if keyboard.pressed(KeyCode::Down) {
- acc.y -= 1.0;
- }
- if keyboard.pressed(KeyCode::Left) {
- acc.x -= 1.0;
- }
- if keyboard.pressed(KeyCode::Right) {
- acc.x += 1.0;
- }
+ let input = inputs[player.handle as usize].0;
+ let sx: f32 = (input.sx as f32) - 127.0 / 256.0;
+ let sy: f32 = (input.sy as f32) - 127.0 / 256.0;
+ let mut acc = Vec2::new(sx, sy);
if acc.length_squared() > 0.0 {
acc /= acc.length();
let head = Vec3::new(acc.x, acc.y, 0.0) * (2.0 + player.radius + 3.0);
@@ -285,7 +346,8 @@ fn shoot(
.insert(Ccd::enabled())
.insert(Velocity::linear(acc * 1000.0))
.insert(CollisionGroups::new(0b010, 0b101))
- .insert(ActiveEvents::COLLISION_EVENTS);
+ .insert(ActiveEvents::COLLISION_EVENTS)
+ .insert(Rollback::new(rip.next_id()));
}
}
}
@@ -368,7 +430,14 @@ fn setup_map(mut commands: Commands) {
}
}
-fn setup(mut commands: Commands, mut rapier_config: ResMut<RapierConfiguration>) {
+fn setup(
+ mut commands: Commands,
+ mut rapier_config: ResMut<RapierConfiguration>,
+ mut rip: ResMut<RollbackIdProvider>,
+ p2p_session: Option<Res<P2PSession<GGRSConfig>>>,
+ synctest_session: Option<Res<SyncTestSession<GGRSConfig>>>,
+ spectator_session: Option<Res<SpectatorSession<GGRSConfig>>>,
+) {
rapier_config.gravity = Vec2::ZERO;
let color = commands
@@ -383,40 +452,50 @@ fn setup(mut commands: Commands, mut rapier_config: ResMut<RapierConfiguration>)
})
.id();
- commands
- .spawn()
- .insert_bundle(SpriteBundle {
- transform: Transform {
- translation: Vec3::new(0.0, 0.0, 0.0),
- scale: Vec3::splat(10.0),
- ..default()
- },
- sprite: Sprite {
- color: Color::WHITE,
+ let num_players = p2p_session
+ .map(|s| s.num_players())
+ .or_else(|| synctest_session.map(|s| s.num_players()))
+ .or_else(|| spectator_session.map(|s| s.num_players()))
+ .expect("No GGRS session found");
+
+ for handle in 0..num_players {
+ commands
+ .spawn()
+ .insert_bundle(SpriteBundle {
+ transform: Transform {
+ translation: Vec3::new(handle as f32, 0.0, 0.0),
+ scale: Vec3::splat(10.0),
+ ..default()
+ },
+ sprite: Sprite {
+ color: Color::WHITE,
+ ..default()
+ },
..default()
- },
- ..default()
- })
- .push_children(&[color])
- .insert(Player {
- speed: 150.0,
- radius: 10.0,
- })
- .insert(RigidBody::Dynamic)
- .insert(Restitution::coefficient(0.0))
- .insert(Collider::ball(1.0))
- .insert(LockedAxes::ROTATION_LOCKED)
- .insert(Damping {
- linear_damping: 30.0,
- angular_damping: 1.0,
- })
- .insert(Friction {
- coefficient: 0.0,
- combine_rule: CoefficientCombineRule::Min,
- })
- .insert(Ccd::enabled())
- .insert(Velocity::zero())
- .insert(CollisionGroups::new(0b001, 0b111));
+ })
+ .push_children(&[color])
+ .insert(Player {
+ handle,
+ speed: 150.0,
+ radius: 10.0,
+ })
+ .insert(RigidBody::Dynamic)
+ .insert(Restitution::coefficient(0.0))
+ .insert(Collider::ball(1.0))
+ .insert(LockedAxes::ROTATION_LOCKED)
+ .insert(Damping {
+ linear_damping: 30.0,
+ angular_damping: 1.0,
+ })
+ .insert(Friction {
+ coefficient: 0.0,
+ combine_rule: CoefficientCombineRule::Min,
+ })
+ .insert(Ccd::enabled())
+ .insert(Velocity::zero())
+ .insert(CollisionGroups::new(0b001, 0b111))
+ .insert(Rollback::new(rip.next_id()));
+ }
setup_map(commands);
}