diff options
-rw-r--r-- | examples/breakout/breakout.rs | 146 | ||||
-rw-r--r-- | examples/breakout/client.rs | 16 | ||||
-rw-r--r-- | examples/breakout/server.rs | 2 | ||||
-rw-r--r-- | examples/chat/client.rs | 13 |
4 files changed, 83 insertions, 94 deletions
diff --git a/examples/breakout/breakout.rs b/examples/breakout/breakout.rs index 31fcf01..56f9053 100644 --- a/examples/breakout/breakout.rs +++ b/examples/breakout/breakout.rs @@ -3,7 +3,7 @@ use std::net::{IpAddr, Ipv4Addr}; -use bevy::{ecs::schedule::ShouldRun, prelude::*, time::FixedTimestep}; +use bevy::prelude::*; use bevy_quinnet::{ client::QuinnetClientPlugin, server::{QuinnetServerPlugin, Server}, @@ -47,8 +47,9 @@ const GAP_BETWEEN_BRICKS: f32 = 5.0; // These values are lower bounds, as the number of bricks is computed const GAP_BETWEEN_BRICKS_AND_SIDES: f32 = 20.0; -#[derive(Clone, Eq, PartialEq, Debug, Hash)] +#[derive(Default, Clone, Eq, PartialEq, Debug, Hash, States)] enum GameState { + #[default] MainMenu, HostingLobby, JoiningLobby, @@ -105,90 +106,75 @@ impl WallLocation { } } +fn server_is_listening(server: Res<Server>) -> bool { + server.is_listening() +} + +fn game_is_running(current_state: Res<State<GameState>>) -> bool { + current_state.0 == GameState::Running +} + fn main() { - App::new() - .add_plugins(DefaultPlugins) + let mut app = App::new(); + app.add_plugins(DefaultPlugins) .add_plugin(QuinnetServerPlugin::default()) - .add_plugin(QuinnetClientPlugin::default()) - .add_event::<CollisionEvent>() - .add_state(GameState::MainMenu) - // Resources - .insert_resource(ClearColor(BACKGROUND_COLOR)) + .add_plugin(QuinnetClientPlugin::default()); + app.add_event::<CollisionEvent>(); + app.add_state::<GameState>(); + app.insert_resource(ClearColor(BACKGROUND_COLOR)) .insert_resource(server::Players::default()) .insert_resource(client::Scoreboard { score: 0 }) .insert_resource(client::ClientData::default()) .insert_resource(client::NetworkMapping::default()) - .insert_resource(client::BricksMapping::default()) - // Main menu - .add_system_set( - SystemSet::on_enter(GameState::MainMenu).with_system(client::setup_main_menu), - ) - .add_system_set( - SystemSet::on_update(GameState::MainMenu).with_system(client::handle_menu_buttons), - ) - .add_system_set( - SystemSet::on_exit(GameState::MainMenu).with_system(client::teardown_main_menu), + .insert_resource(client::BricksMapping::default()); + + // Main menu + app.add_system(bevy::window::close_on_esc) + .add_system(client::setup_main_menu.in_schedule(OnEnter(GameState::MainMenu))) + .add_system(client::handle_menu_buttons.in_set(OnUpdate(GameState::MainMenu))) + .add_system(client::teardown_main_menu.in_schedule(OnExit(GameState::MainMenu))); + // Hosting a server on a client + app.add_systems( + (server::start_listening, client::start_connection) + .in_schedule(OnEnter(GameState::HostingLobby)), + ) + .add_systems( + ( + server::handle_client_messages, + server::handle_server_events, + client::handle_server_messages, ) - // Hosting a server on a client - .add_system_set( - SystemSet::on_enter(GameState::HostingLobby) - .with_system(server::start_listening) - .with_system(client::start_connection), + .in_set(OnUpdate(GameState::HostingLobby)), + ); + // or just Joining as a client + app.add_system(client::start_connection.in_schedule(OnEnter(GameState::JoiningLobby))) + .add_system(client::handle_server_messages.in_set(OnUpdate(GameState::JoiningLobby))); + // Running the game. + // Every app is a client + app.add_system(client::setup_breakout.in_schedule(OnEnter(GameState::Running))) + .add_systems( + ( + client::handle_server_messages.before(client::apply_velocity), + client::apply_velocity, + client::move_paddle, + client::update_scoreboard, + client::play_collision_sound, + ) + .distributive_run_if(game_is_running) + .in_schedule(CoreSchedule::FixedUpdate), + ); + // But hosting apps are also a server + app.add_systems( + ( + server::handle_client_messages.before(server::update_paddles), + server::update_paddles.before(server::check_for_collisions), + server::apply_velocity.before(server::check_for_collisions), + server::check_for_collisions, ) - .add_system_set( - SystemSet::on_update(GameState::HostingLobby) - .with_system(server::handle_client_messages) - .with_system(server::handle_server_events) - .with_system(client::handle_server_messages), - ) - // or just Joining as a client - .add_system_set( - SystemSet::on_enter(GameState::JoiningLobby).with_system(client::start_connection), - ) - .add_system_set( - SystemSet::on_update(GameState::JoiningLobby) - .with_system(client::handle_server_messages), - ) - // Running the game. - // Every app is a client - .add_system_set(SystemSet::on_enter(GameState::Running).with_system(client::setup_breakout)) - .add_system_set( - SystemSet::new() - // https://github.com/bevyengine/bevy/issues/1839 - // Run on a fixed Timestep,on all clients, in GameState::Running - .with_run_criteria(FixedTimestep::step(TIME_STEP as f64).pipe( - |In(input): In<ShouldRun>, state: Res<State<GameState>>| match state.current() { - GameState::Running => input, - _ => ShouldRun::No, - }, - )) - .with_system(client::handle_server_messages.before(client::apply_velocity)) - .with_system(client::apply_velocity) - .with_system(client::move_paddle) - .with_system(client::update_scoreboard) - .with_system(client::play_collision_sound.after(client::handle_server_messages)), - ) - // But hosting apps are also a server - .add_system_set( - SystemSet::new() - // https://github.com/bevyengine/bevy/issues/1839 - // Run on a fixed Timestep, only for the hosting client, in GameState::Running - .with_run_criteria(FixedTimestep::step(TIME_STEP as f64).pipe( - |In(input): In<ShouldRun>, - state: Res<State<GameState>>, - server: Res<Server>| match state.current() { - GameState::Running => match server.is_listening() { - true => input, - false => ShouldRun::No, - }, - _ => ShouldRun::No, - }, - )) - .with_system(server::handle_client_messages.before(server::update_paddles)) - .with_system(server::update_paddles.before(server::check_for_collisions)) - .with_system(server::apply_velocity.before(server::check_for_collisions)) - .with_system(server::check_for_collisions), - ) - .add_system(bevy::window::close_on_esc) - .run(); + .distributive_run_if(server_is_listening) + .distributive_run_if(game_is_running) + .in_schedule(CoreSchedule::FixedUpdate), + ); + + app.run(); } diff --git a/examples/breakout/client.rs b/examples/breakout/client.rs index be4435a..e418757 100644 --- a/examples/breakout/client.rs +++ b/examples/breakout/client.rs @@ -4,8 +4,8 @@ use bevy::{ prelude::{ default, AssetServer, Audio, BuildChildren, Bundle, Button, ButtonBundle, Camera2dBundle, Changed, Color, Commands, Component, DespawnRecursiveExt, Entity, EventReader, EventWriter, - Input, KeyCode, Local, PlaybackSettings, Query, Res, ResMut, Resource, State, TextBundle, - Transform, Vec2, Vec3, With, Without, + Input, KeyCode, Local, NextState, PlaybackSettings, Query, Res, ResMut, Resource, + TextBundle, Transform, Vec2, Vec3, With, Without, }, sprite::{Sprite, SpriteBundle}, text::{Text, TextSection, TextStyle}, @@ -194,7 +194,7 @@ pub(crate) fn handle_server_messages( mut client: ResMut<Client>, mut client_data: ResMut<ClientData>, mut entity_mapping: ResMut<NetworkMapping>, - mut game_state: ResMut<State<GameState>>, + mut next_state: ResMut<NextState<GameState>>, mut paddles: Query<&mut Transform, With<Paddle>>, mut balls: Query<(&mut Transform, &mut Velocity, &mut Sprite), (With<Ball>, Without<Paddle>)>, mut bricks: ResMut<BricksMapping>, @@ -240,7 +240,7 @@ pub(crate) fn handle_server_messages( rows, columns, } => spawn_bricks(&mut commands, &mut bricks, offset, rows, columns), - ServerMessage::StartGame {} => game_state.set(GameState::Running).unwrap(), + ServerMessage::StartGame {} => next_state.set(GameState::Running), ServerMessage::BrickDestroyed { by_client_id, brick_id, @@ -324,7 +324,7 @@ pub(crate) fn update_scoreboard( } pub(crate) fn play_collision_sound( - collision_events: EventReader<CollisionEvent>, + mut collision_events: EventReader<CollisionEvent>, audio: Res<Audio>, sound: Res<CollisionSound>, ) { @@ -392,15 +392,15 @@ pub(crate) fn handle_menu_buttons( (&Interaction, &mut BackgroundColor, &MenuItem), (Changed<Interaction>, With<Button>), >, - mut game_state: ResMut<State<GameState>>, + mut next_state: ResMut<NextState<GameState>>, ) { for (interaction, mut color, item) in &mut interaction_query { match *interaction { Interaction::Clicked => { *color = PRESSED_BUTTON_COLOR.into(); match item { - MenuItem::Host => game_state.set(GameState::HostingLobby).unwrap(), - MenuItem::Join => game_state.set(GameState::JoiningLobby).unwrap(), + MenuItem::Host => next_state.set(GameState::HostingLobby), + MenuItem::Join => next_state.set(GameState::JoiningLobby), } } Interaction::Hovered => { diff --git a/examples/breakout/server.rs b/examples/breakout/server.rs index f2389bd..9be514e 100644 --- a/examples/breakout/server.rs +++ b/examples/breakout/server.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap}; +use std::collections::HashMap; use bevy::{ prelude::{ diff --git a/examples/chat/client.rs b/examples/chat/client.rs index fae4976..990efa4 100644 --- a/examples/chat/client.rs +++ b/examples/chat/client.rs @@ -8,8 +8,8 @@ use bevy::{ app::{AppExit, ScheduleRunnerPlugin}, log::LogPlugin, prelude::{ - info, warn, App, Commands, CoreStage, Deref, DerefMut, EventReader, EventWriter, Res, - ResMut, Resource, + info, warn, App, Commands, CoreSet, Deref, DerefMut, EventReader, EventWriter, + IntoSystemConfig, Res, ResMut, Resource, }, }; use bevy_quinnet::{ @@ -128,7 +128,10 @@ fn start_connection(mut client: ResMut<Client>) { // You can already send message(s) even before being connected, they will be buffered. In this example we will wait for a ConnectionEvent. } -fn handle_client_events(connection_events: EventReader<ConnectionEvent>, client: ResMut<Client>) { +fn handle_client_events( + mut connection_events: EventReader<ConnectionEvent>, + client: ResMut<Client>, +) { if !connection_events.is_empty() { // We are connected let username: String = rand::thread_rng() @@ -160,7 +163,7 @@ fn main() { .add_system(handle_terminal_messages) .add_system(handle_server_messages) .add_system(handle_client_events) - // CoreStage::PostUpdate so that AppExit events generated in the previous stage are available - .add_system_to_stage(CoreStage::PostUpdate, on_app_exit) + // CoreSet::PostUpdate so that AppExit events generated in the previous stage are available + .add_system(on_app_exit.in_base_set(CoreSet::PostUpdate)) .run(); } |