From 6b5c9ca2a7d0b6047720cb4325c588f5dc56b4c9 Mon Sep 17 00:00:00 2001 From: Thom Bruce Date: Mon, 30 Oct 2023 17:34:03 +0000 Subject: [PATCH 01/13] add basic bevy_common_assets configuration and demo working setup --- CHANGELOG.md | 4 +++ Cargo.lock | 22 ++++++++++++--- Cargo.toml | 2 ++ assets/verse.config.ron | 10 +++++++ src/common_assets_demo.rs | 57 +++++++++++++++++++++++++++++++++++++++ src/main.rs | 10 ++++++- 6 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 assets/verse.config.ron create mode 100644 src/common_assets_demo.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index e077e53..bb17208 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- bevy_common_assets allowing certain data to be loaded from asset files + ### Changed - Gravitable component added allowing dynamic_orbit system to be applied to any entity diff --git a/Cargo.lock b/Cargo.lock index 82a1eff..5cab07f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -469,6 +469,18 @@ dependencies = [ "rodio", ] +[[package]] +name = "bevy_common_assets" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0e5659f20aeaa1703e76d87c62d66f92aaa56e431fbed71bb38345b576aa6f0" +dependencies = [ + "anyhow", + "bevy", + "ron", + "serde", +] + [[package]] name = "bevy_core" version = "0.11.3" @@ -3497,18 +3509,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.189" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" +checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.189" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" +checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" dependencies = [ "proc-macro2", "quote", @@ -4012,11 +4024,13 @@ dependencies = [ "bevy", "bevy-inspector-egui", "bevy_asset_loader", + "bevy_common_assets", "bevy_rapier2d", "bevy_spatial", "bevy_tiling_background", "image", "leafwing-input-manager", + "serde", "winit", ] diff --git a/Cargo.toml b/Cargo.toml index d9bc2a0..1685c44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,11 +9,13 @@ edition = "2021" bevy = "0.11.3" bevy-inspector-egui = "0.20.0" bevy_asset_loader = { version = "0.17.0", features = ["2d"] } +bevy_common_assets = { version = "0.7.0", features = ["ron"] } bevy_rapier2d = "0.22.0" bevy_spatial = "0.6.0" bevy_tiling_background = { git = "https://github.com/rparrett/bevy_tiling_background.git", branch = "tex-typo" } image = "0.24.7" leafwing-input-manager = "0.10.0" +serde = "1.0.190" winit = "0.28.7" # Enable a small amount of optimization in debug mode diff --git a/assets/verse.config.ron b/assets/verse.config.ron new file mode 100644 index 0000000..f5a8a0e --- /dev/null +++ b/assets/verse.config.ron @@ -0,0 +1,10 @@ +( + positions: [ + (142., 56., 0.), + (25., 132., 0.), + (123., 7., 0.), + (-61., 149., 0.), + (-96., -52., 0.), + (69., -189., 0.), + ] +) diff --git a/src/common_assets_demo.rs b/src/common_assets_demo.rs new file mode 100644 index 0000000..dc71b03 --- /dev/null +++ b/src/common_assets_demo.rs @@ -0,0 +1,57 @@ +use bevy::prelude::*; +use bevy::reflect::{TypePath, TypeUuid}; +use bevy_common_assets::ron::RonAssetPlugin; + +use crate::core::resources::state::GameState; + +pub struct CommonAssetsDemoPlugin; +impl Plugin for CommonAssetsDemoPlugin { + fn build(&self, app: &mut App) { + app.add_plugins(RonAssetPlugin::::new(&["config.ron"])) + .add_systems(Startup, setup) + .add_systems( + Update, + (spawn_level, spawn_level_again).run_if(in_state(GameState::StartMenu)), + ); + } +} + +fn setup(mut commands: Commands, asset_server: Res) { + let level = LevelHandle(asset_server.load("verse.config.ron")); + commands.insert_resource(level); +} + +fn spawn_level( + // mut commands: Commands, + level: Res, + mut levels: ResMut>, +) { + if let Some(level) = levels.remove(level.0.id()) { + for position in level.positions { + println!("{}", position[0]); + } + } +} + +// It only works the FIRST time. I think because .remove() removes +// the data, it cannot be found again by a later system. +fn spawn_level_again( + // mut commands: Commands, + level: Res, + mut levels: ResMut>, +) { + if let Some(level) = levels.remove(level.0.id()) { + for position in level.positions { + println!("{}", position[0]); + } + } +} + +#[derive(serde::Deserialize, TypeUuid, TypePath)] +#[uuid = "bdb624ed-62bc-447f-9f89-f361ed58748c"] +struct Level { + positions: Vec<[f32; 3]>, +} + +#[derive(Resource)] +struct LevelHandle(Handle); diff --git a/src/main.rs b/src/main.rs index 9cd72be..d092661 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,7 @@ use winit::window::Icon; #[cfg(debug_assertions)] use {bevy_inspector_egui::quick::WorldInspectorPlugin, bevy_rapier2d::prelude::*}; +mod common_assets_demo; mod core; mod inputs; mod shaders; @@ -18,6 +19,7 @@ mod ui; mod world; use crate::{ + common_assets_demo::CommonAssetsDemoPlugin, core::resources::{ assets::{AudioAssets, SpriteAssets, UiAssets}, state::GameState, @@ -53,7 +55,13 @@ fn main() { .set(ImagePlugin::default_nearest()), ); - app.add_plugins((CorePlugin, ShipsPlugin, WorldPlugin, UiPlugin)); + app.add_plugins(( + CommonAssetsDemoPlugin, + CorePlugin, + ShipsPlugin, + WorldPlugin, + UiPlugin, + )); #[cfg(debug_assertions)] app.add_plugins(( From a06e288e1f00cedf4d351bb2f66dfaf83ebdc255 Mon Sep 17 00:00:00 2001 From: Thom Bruce Date: Mon, 30 Oct 2023 18:25:03 +0000 Subject: [PATCH 02/13] move config handle into assets resource --- src/common_assets_demo.rs | 37 ++++++++++-------------------------- src/core/resources/assets.rs | 8 ++++++++ src/main.rs | 5 +++-- 3 files changed, 21 insertions(+), 29 deletions(-) diff --git a/src/common_assets_demo.rs b/src/common_assets_demo.rs index dc71b03..427c485 100644 --- a/src/common_assets_demo.rs +++ b/src/common_assets_demo.rs @@ -2,32 +2,22 @@ use bevy::prelude::*; use bevy::reflect::{TypePath, TypeUuid}; use bevy_common_assets::ron::RonAssetPlugin; -use crate::core::resources::state::GameState; +use crate::core::resources::{assets::DataAssets, state::GameState}; pub struct CommonAssetsDemoPlugin; impl Plugin for CommonAssetsDemoPlugin { fn build(&self, app: &mut App) { - app.add_plugins(RonAssetPlugin::::new(&["config.ron"])) - .add_systems(Startup, setup) + app.add_plugins(RonAssetPlugin::::new(&["config.ron"])) .add_systems( Update, - (spawn_level, spawn_level_again).run_if(in_state(GameState::StartMenu)), + (spawn_config, spawn_config_again).run_if(in_state(GameState::StartMenu)), ); } } -fn setup(mut commands: Commands, asset_server: Res) { - let level = LevelHandle(asset_server.load("verse.config.ron")); - commands.insert_resource(level); -} - -fn spawn_level( - // mut commands: Commands, - level: Res, - mut levels: ResMut>, -) { - if let Some(level) = levels.remove(level.0.id()) { - for position in level.positions { +fn spawn_config(data: Res, mut configs: ResMut>) { + if let Some(config) = configs.remove(data.config.clone()) { + for position in config.positions { println!("{}", position[0]); } } @@ -35,13 +25,9 @@ fn spawn_level( // It only works the FIRST time. I think because .remove() removes // the data, it cannot be found again by a later system. -fn spawn_level_again( - // mut commands: Commands, - level: Res, - mut levels: ResMut>, -) { - if let Some(level) = levels.remove(level.0.id()) { - for position in level.positions { +fn spawn_config_again(data: Res, mut configs: ResMut>) { + if let Some(config) = configs.remove(data.config.clone()) { + for position in config.positions { println!("{}", position[0]); } } @@ -49,9 +35,6 @@ fn spawn_level_again( #[derive(serde::Deserialize, TypeUuid, TypePath)] #[uuid = "bdb624ed-62bc-447f-9f89-f361ed58748c"] -struct Level { +pub struct Config { positions: Vec<[f32; 3]>, } - -#[derive(Resource)] -struct LevelHandle(Handle); diff --git a/src/core/resources/assets.rs b/src/core/resources/assets.rs index 2162f1b..376d308 100644 --- a/src/core/resources/assets.rs +++ b/src/core/resources/assets.rs @@ -1,6 +1,14 @@ use bevy::prelude::*; use bevy_asset_loader::prelude::*; +use crate::common_assets_demo::Config; + +#[derive(AssetCollection, Resource)] +pub struct DataAssets { + #[asset(path = "verse.config.ron")] + pub config: Handle, +} + #[derive(AssetCollection, Resource)] pub struct SpriteAssets { #[asset(path = "space/ships/player.png")] diff --git a/src/main.rs b/src/main.rs index d092661..4bed410 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,7 +21,7 @@ mod world; use crate::{ common_assets_demo::CommonAssetsDemoPlugin, core::resources::{ - assets::{AudioAssets, SpriteAssets, UiAssets}, + assets::{AudioAssets, DataAssets, SpriteAssets, UiAssets}, state::GameState, }, core::CorePlugin, @@ -74,7 +74,8 @@ fn main() { ) .add_collection_to_loading_state::<_, SpriteAssets>(GameState::Loading) .add_collection_to_loading_state::<_, AudioAssets>(GameState::Loading) - .add_collection_to_loading_state::<_, UiAssets>(GameState::Loading); + .add_collection_to_loading_state::<_, UiAssets>(GameState::Loading) + .add_collection_to_loading_state::<_, DataAssets>(GameState::Loading); app.insert_resource(ClearColor(Color::rgb(0., 0., 0.))); From a0738316d0f55df9f9cdf90e6c023f7a861b870e Mon Sep 17 00:00:00 2001 From: Thom Bruce Date: Mon, 30 Oct 2023 18:33:11 +0000 Subject: [PATCH 03/13] get reference rather than destructively mutating config --- src/common_assets_demo.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/common_assets_demo.rs b/src/common_assets_demo.rs index 427c485..24ae06d 100644 --- a/src/common_assets_demo.rs +++ b/src/common_assets_demo.rs @@ -9,15 +9,15 @@ impl Plugin for CommonAssetsDemoPlugin { fn build(&self, app: &mut App) { app.add_plugins(RonAssetPlugin::::new(&["config.ron"])) .add_systems( - Update, + OnEnter(GameState::StartMenu), (spawn_config, spawn_config_again).run_if(in_state(GameState::StartMenu)), ); } } -fn spawn_config(data: Res, mut configs: ResMut>) { - if let Some(config) = configs.remove(data.config.clone()) { - for position in config.positions { +fn spawn_config(data: Res, configs: ResMut>) { + if let Some(config) = configs.get(&data.config.clone()) { + for position in &config.positions { println!("{}", position[0]); } } @@ -25,9 +25,9 @@ fn spawn_config(data: Res, mut configs: ResMut>) { // It only works the FIRST time. I think because .remove() removes // the data, it cannot be found again by a later system. -fn spawn_config_again(data: Res, mut configs: ResMut>) { - if let Some(config) = configs.remove(data.config.clone()) { - for position in config.positions { +fn spawn_config_again(data: Res, configs: ResMut>) { + if let Some(config) = configs.get(&data.config.clone()) { + for position in &config.positions { println!("{}", position[0]); } } From ce8bc9b5f232ba793edce3fe9a8fc7f3b87173ef Mon Sep 17 00:00:00 2001 From: Thom Bruce Date: Mon, 30 Oct 2023 18:34:07 +0000 Subject: [PATCH 04/13] remove redundant code examples --- src/common_assets_demo.rs | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/common_assets_demo.rs b/src/common_assets_demo.rs index 24ae06d..4dcd4ed 100644 --- a/src/common_assets_demo.rs +++ b/src/common_assets_demo.rs @@ -8,10 +8,7 @@ pub struct CommonAssetsDemoPlugin; impl Plugin for CommonAssetsDemoPlugin { fn build(&self, app: &mut App) { app.add_plugins(RonAssetPlugin::::new(&["config.ron"])) - .add_systems( - OnEnter(GameState::StartMenu), - (spawn_config, spawn_config_again).run_if(in_state(GameState::StartMenu)), - ); + .add_systems(OnEnter(GameState::StartMenu), spawn_config); } } @@ -23,16 +20,6 @@ fn spawn_config(data: Res, configs: ResMut>) { } } -// It only works the FIRST time. I think because .remove() removes -// the data, it cannot be found again by a later system. -fn spawn_config_again(data: Res, configs: ResMut>) { - if let Some(config) = configs.get(&data.config.clone()) { - for position in &config.positions { - println!("{}", position[0]); - } - } -} - #[derive(serde::Deserialize, TypeUuid, TypePath)] #[uuid = "bdb624ed-62bc-447f-9f89-f361ed58748c"] pub struct Config { From bda62111b8e24e38d982bb09d1d753d1b5fd24ad Mon Sep 17 00:00:00 2001 From: Thom Bruce Date: Mon, 30 Oct 2023 18:43:29 +0000 Subject: [PATCH 05/13] set WindowMode on initial load using new settings loading system --- assets/verse.config.ron | 9 +-------- src/common_assets_demo.rs | 13 ++++++++----- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/assets/verse.config.ron b/assets/verse.config.ron index f5a8a0e..c5b8e30 100644 --- a/assets/verse.config.ron +++ b/assets/verse.config.ron @@ -1,10 +1,3 @@ ( - positions: [ - (142., 56., 0.), - (25., 132., 0.), - (123., 7., 0.), - (-61., 149., 0.), - (-96., -52., 0.), - (69., -189., 0.), - ] + window_mode: Fullscreen ) diff --git a/src/common_assets_demo.rs b/src/common_assets_demo.rs index 4dcd4ed..c319fac 100644 --- a/src/common_assets_demo.rs +++ b/src/common_assets_demo.rs @@ -1,5 +1,6 @@ use bevy::prelude::*; use bevy::reflect::{TypePath, TypeUuid}; +use bevy::window::WindowMode; use bevy_common_assets::ron::RonAssetPlugin; use crate::core::resources::{assets::DataAssets, state::GameState}; @@ -12,16 +13,18 @@ impl Plugin for CommonAssetsDemoPlugin { } } -fn spawn_config(data: Res, configs: ResMut>) { +fn spawn_config( + data: Res, + configs: ResMut>, + mut window: Query<&mut Window>, +) { if let Some(config) = configs.get(&data.config.clone()) { - for position in &config.positions { - println!("{}", position[0]); - } + window.single_mut().mode = config.window_mode; } } #[derive(serde::Deserialize, TypeUuid, TypePath)] #[uuid = "bdb624ed-62bc-447f-9f89-f361ed58748c"] pub struct Config { - positions: Vec<[f32; 3]>, + window_mode: WindowMode, } From d903f02f53e7a50e58cd89790c731e4de6d2c2e8 Mon Sep 17 00:00:00 2001 From: Thom Bruce Date: Mon, 30 Oct 2023 18:53:06 +0000 Subject: [PATCH 06/13] reorganize config setup into appropriately named modules --- assets/verse.config.ron | 2 +- src/common_assets_demo.rs | 30 ------------------------------ src/core/resources/assets.rs | 2 +- src/core/resources/config.rs | 17 +++++++++++++++++ src/core/resources/mod.rs | 1 + src/main.rs | 16 ++++++---------- 6 files changed, 26 insertions(+), 42 deletions(-) delete mode 100644 src/common_assets_demo.rs create mode 100644 src/core/resources/config.rs diff --git a/assets/verse.config.ron b/assets/verse.config.ron index c5b8e30..aba35d2 100644 --- a/assets/verse.config.ron +++ b/assets/verse.config.ron @@ -1,3 +1,3 @@ ( - window_mode: Fullscreen + window_mode: Windowed // Windowed, Fullscreen, BorderlessFullscreen, SizedFullscreen ) diff --git a/src/common_assets_demo.rs b/src/common_assets_demo.rs deleted file mode 100644 index c319fac..0000000 --- a/src/common_assets_demo.rs +++ /dev/null @@ -1,30 +0,0 @@ -use bevy::prelude::*; -use bevy::reflect::{TypePath, TypeUuid}; -use bevy::window::WindowMode; -use bevy_common_assets::ron::RonAssetPlugin; - -use crate::core::resources::{assets::DataAssets, state::GameState}; - -pub struct CommonAssetsDemoPlugin; -impl Plugin for CommonAssetsDemoPlugin { - fn build(&self, app: &mut App) { - app.add_plugins(RonAssetPlugin::::new(&["config.ron"])) - .add_systems(OnEnter(GameState::StartMenu), spawn_config); - } -} - -fn spawn_config( - data: Res, - configs: ResMut>, - mut window: Query<&mut Window>, -) { - if let Some(config) = configs.get(&data.config.clone()) { - window.single_mut().mode = config.window_mode; - } -} - -#[derive(serde::Deserialize, TypeUuid, TypePath)] -#[uuid = "bdb624ed-62bc-447f-9f89-f361ed58748c"] -pub struct Config { - window_mode: WindowMode, -} diff --git a/src/core/resources/assets.rs b/src/core/resources/assets.rs index 376d308..3b32276 100644 --- a/src/core/resources/assets.rs +++ b/src/core/resources/assets.rs @@ -1,7 +1,7 @@ use bevy::prelude::*; use bevy_asset_loader::prelude::*; -use crate::common_assets_demo::Config; +use super::config::Config; #[derive(AssetCollection, Resource)] pub struct DataAssets { diff --git a/src/core/resources/config.rs b/src/core/resources/config.rs new file mode 100644 index 0000000..2b8c47f --- /dev/null +++ b/src/core/resources/config.rs @@ -0,0 +1,17 @@ +use bevy::prelude::*; +use bevy::reflect::{TypePath, TypeUuid}; +use bevy::window::WindowMode; +use bevy_common_assets::ron::RonAssetPlugin; + +pub struct ConfigPlugin; +impl Plugin for ConfigPlugin { + fn build(&self, app: &mut App) { + app.add_plugins(RonAssetPlugin::::new(&["config.ron"])); + } +} + +#[derive(serde::Deserialize, TypeUuid, TypePath)] +#[uuid = "bdb624ed-62bc-447f-9f89-f361ed58748c"] +pub struct Config { + pub(crate) window_mode: WindowMode, +} diff --git a/src/core/resources/mod.rs b/src/core/resources/mod.rs index 87960ac..47a9ba1 100644 --- a/src/core/resources/mod.rs +++ b/src/core/resources/mod.rs @@ -1,4 +1,5 @@ pub mod assets; +pub mod config; pub mod despawn_timer; pub mod game_time; pub mod state; diff --git a/src/main.rs b/src/main.rs index 4bed410..616f9a2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,6 @@ use winit::window::Icon; #[cfg(debug_assertions)] use {bevy_inspector_egui::quick::WorldInspectorPlugin, bevy_rapier2d::prelude::*}; -mod common_assets_demo; mod core; mod inputs; mod shaders; @@ -19,9 +18,9 @@ mod ui; mod world; use crate::{ - common_assets_demo::CommonAssetsDemoPlugin, core::resources::{ assets::{AudioAssets, DataAssets, SpriteAssets, UiAssets}, + config::{Config, ConfigPlugin}, state::GameState, }, core::CorePlugin, @@ -55,13 +54,7 @@ fn main() { .set(ImagePlugin::default_nearest()), ); - app.add_plugins(( - CommonAssetsDemoPlugin, - CorePlugin, - ShipsPlugin, - WorldPlugin, - UiPlugin, - )); + app.add_plugins((ConfigPlugin, CorePlugin, ShipsPlugin, WorldPlugin, UiPlugin)); #[cfg(debug_assertions)] app.add_plugins(( @@ -93,9 +86,12 @@ fn main() { } /// The setup function -fn setup() { +fn setup(data: Res, configs: ResMut>, mut window: Query<&mut Window>) { // Good place to put window setup configs, like whether or not // the player has suggested the game be played fullscreen. + if let Some(config) = configs.get(&data.config.clone()) { + window.single_mut().mode = config.window_mode; + } } // Documented: From 996817ee8dc67982fba5dd8790e663c4d0ec4169 Mon Sep 17 00:00:00 2001 From: Thom Bruce Date: Mon, 30 Oct 2023 20:26:29 +0000 Subject: [PATCH 07/13] allow master volume to be set via config --- CHANGELOG.md | 1 + assets/verse.config.ron | 3 ++- src/core/resources/config.rs | 1 + src/core/resources/state.rs | 2 +- src/main.rs | 11 ++++++++--- src/ships/bullet.rs | 11 +++++++++-- src/ui/menus/start_menu.rs | 6 +++++- 7 files changed, 27 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb17208..9de60d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - bevy_common_assets allowing certain data to be loaded from asset files +- Allow window mode and master volume to be set via config file ### Changed diff --git a/assets/verse.config.ron b/assets/verse.config.ron index aba35d2..a31ef50 100644 --- a/assets/verse.config.ron +++ b/assets/verse.config.ron @@ -1,3 +1,4 @@ ( - window_mode: Windowed // Windowed, Fullscreen, BorderlessFullscreen, SizedFullscreen + window_mode: Windowed, // Windowed, Fullscreen, BorderlessFullscreen, SizedFullscreen + master_volume: 1.0, ) diff --git a/src/core/resources/config.rs b/src/core/resources/config.rs index 2b8c47f..6ea8a5b 100644 --- a/src/core/resources/config.rs +++ b/src/core/resources/config.rs @@ -14,4 +14,5 @@ impl Plugin for ConfigPlugin { #[uuid = "bdb624ed-62bc-447f-9f89-f361ed58748c"] pub struct Config { pub(crate) window_mode: WindowMode, + pub(crate) master_volume: f32, } diff --git a/src/core/resources/state.rs b/src/core/resources/state.rs index 6460536..f364f4f 100644 --- a/src/core/resources/state.rs +++ b/src/core/resources/state.rs @@ -55,7 +55,7 @@ fn game_setup( source: audios.ambience.clone(), settings: PlaybackSettings { mode: PlaybackMode::Loop, - volume: Volume::new_absolute(0.5), + volume: Volume::new_relative(0.5), ..default() }, }, diff --git a/src/main.rs b/src/main.rs index 616f9a2..0f83f16 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ #[allow(unused_imports)] use bevy::{ + audio::{AudioPlugin, VolumeLevel}, prelude::*, window::{Cursor, PrimaryWindow, WindowMode}, winit::WinitWindows, @@ -86,11 +87,15 @@ fn main() { } /// The setup function -fn setup(data: Res, configs: ResMut>, mut window: Query<&mut Window>) { - // Good place to put window setup configs, like whether or not - // the player has suggested the game be played fullscreen. +fn setup( + data: Res, + configs: ResMut>, + mut window: Query<&mut Window>, + mut volume: ResMut, +) { if let Some(config) = configs.get(&data.config.clone()) { window.single_mut().mode = config.window_mode; + volume.volume = VolumeLevel::new(config.master_volume); } } diff --git a/src/ships/bullet.rs b/src/ships/bullet.rs index e0c2e65..7e70a34 100644 --- a/src/ships/bullet.rs +++ b/src/ships/bullet.rs @@ -1,4 +1,7 @@ -use bevy::prelude::*; +use bevy::{ + audio::{PlaybackMode, Volume}, + prelude::*, +}; use bevy_rapier2d::prelude::*; use crate::core::resources::{ @@ -89,7 +92,11 @@ fn spawn_bullet( ActiveEvents::COLLISION_EVENTS, AudioBundle { source: audios.gun.clone(), - ..default() + settings: PlaybackSettings { + mode: PlaybackMode::Remove, + volume: Volume::new_relative(1.0), + ..default() + }, }, )); } diff --git a/src/ui/menus/start_menu.rs b/src/ui/menus/start_menu.rs index 7f2fad3..dcfb538 100644 --- a/src/ui/menus/start_menu.rs +++ b/src/ui/menus/start_menu.rs @@ -1,4 +1,7 @@ -use bevy::{audio::PlaybackMode, prelude::*}; +use bevy::{ + audio::{PlaybackMode, Volume}, + prelude::*, +}; use leafwing_input_manager::prelude::{ActionState, InputManagerPlugin}; use crate::{ @@ -37,6 +40,7 @@ fn init(mut commands: Commands, audios: Res) { source: audios.title_music.clone(), settings: PlaybackSettings { mode: PlaybackMode::Loop, + volume: Volume::new_relative(1.0), ..default() }, }, From 6e003b9f6886f56b2effa3f91dacf6a0c9d069d6 Mon Sep 17 00:00:00 2001 From: Thom Bruce Date: Mon, 30 Oct 2023 20:48:21 +0000 Subject: [PATCH 08/13] move unsorted image assets into images dir --- assets/{ => images}/VerseSquircle-256.png | 0 assets/{ => images}/grey_arrowUpWhite.png | 0 assets/{ => images}/verse.png | 0 src/core/resources/assets.rs | 2 +- src/main.rs | 2 +- src/ui/hud/indicator.rs | 2 +- 6 files changed, 3 insertions(+), 3 deletions(-) rename assets/{ => images}/VerseSquircle-256.png (100%) rename assets/{ => images}/grey_arrowUpWhite.png (100%) rename assets/{ => images}/verse.png (100%) diff --git a/assets/VerseSquircle-256.png b/assets/images/VerseSquircle-256.png similarity index 100% rename from assets/VerseSquircle-256.png rename to assets/images/VerseSquircle-256.png diff --git a/assets/grey_arrowUpWhite.png b/assets/images/grey_arrowUpWhite.png similarity index 100% rename from assets/grey_arrowUpWhite.png rename to assets/images/grey_arrowUpWhite.png diff --git a/assets/verse.png b/assets/images/verse.png similarity index 100% rename from assets/verse.png rename to assets/images/verse.png diff --git a/src/core/resources/assets.rs b/src/core/resources/assets.rs index 3b32276..295e8b1 100644 --- a/src/core/resources/assets.rs +++ b/src/core/resources/assets.rs @@ -80,6 +80,6 @@ pub struct UiAssets { #[asset(path = "fonts/Xolonium/Xolonium-Bold.ttf")] pub font: Handle, - #[asset(path = "verse.png")] + #[asset(path = "images/verse.png")] pub title: Handle, } diff --git a/src/main.rs b/src/main.rs index 0f83f16..74b4c78 100644 --- a/src/main.rs +++ b/src/main.rs @@ -114,7 +114,7 @@ fn set_window_icon( // here we use the `image` crate to load our icon data from a png file // this is not a very bevy-native solution, but it will do let (icon_rgba, icon_width, icon_height) = { - let image = image::open("assets/VerseSquircle-256.png") + let image = image::open("assets/images/VerseSquircle-256.png") .expect("Failed to open icon path") .into_rgba8(); let (width, height) = image.dimensions(); diff --git a/src/ui/hud/indicator.rs b/src/ui/hud/indicator.rs index 5e05294..e3a99d1 100644 --- a/src/ui/hud/indicator.rs +++ b/src/ui/hud/indicator.rs @@ -53,7 +53,7 @@ fn setup( for (entity, indicated) in entities_query.iter() { parent.spawn(( ImageBundle { - image: UiImage::new(asset_server.load("grey_arrowUpWhite.png")), + image: UiImage::new(asset_server.load("images/grey_arrowUpWhite.png")), style: Style { position_type: PositionType::Absolute, width: Val::Px(15.0), From 61944e1ffb3b085ab04a5d85168d8ec19774ec0c Mon Sep 17 00:00:00 2001 From: Thom Bruce Date: Mon, 30 Oct 2023 20:53:43 +0000 Subject: [PATCH 09/13] rename Config struct to GameConfig --- assets/verse.config.ron | 2 +- src/core/resources/assets.rs | 4 ++-- src/core/resources/config.rs | 4 ++-- src/main.rs | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/assets/verse.config.ron b/assets/verse.config.ron index a31ef50..3c3e782 100644 --- a/assets/verse.config.ron +++ b/assets/verse.config.ron @@ -1,4 +1,4 @@ -( +GameConfig( window_mode: Windowed, // Windowed, Fullscreen, BorderlessFullscreen, SizedFullscreen master_volume: 1.0, ) diff --git a/src/core/resources/assets.rs b/src/core/resources/assets.rs index 295e8b1..642c463 100644 --- a/src/core/resources/assets.rs +++ b/src/core/resources/assets.rs @@ -1,12 +1,12 @@ use bevy::prelude::*; use bevy_asset_loader::prelude::*; -use super::config::Config; +use super::config::GameConfig; #[derive(AssetCollection, Resource)] pub struct DataAssets { #[asset(path = "verse.config.ron")] - pub config: Handle, + pub config: Handle, } #[derive(AssetCollection, Resource)] diff --git a/src/core/resources/config.rs b/src/core/resources/config.rs index 6ea8a5b..33e5b26 100644 --- a/src/core/resources/config.rs +++ b/src/core/resources/config.rs @@ -6,13 +6,13 @@ use bevy_common_assets::ron::RonAssetPlugin; pub struct ConfigPlugin; impl Plugin for ConfigPlugin { fn build(&self, app: &mut App) { - app.add_plugins(RonAssetPlugin::::new(&["config.ron"])); + app.add_plugins(RonAssetPlugin::::new(&["config.ron"])); } } #[derive(serde::Deserialize, TypeUuid, TypePath)] #[uuid = "bdb624ed-62bc-447f-9f89-f361ed58748c"] -pub struct Config { +pub struct GameConfig { pub(crate) window_mode: WindowMode, pub(crate) master_volume: f32, } diff --git a/src/main.rs b/src/main.rs index 74b4c78..d926f98 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,7 +21,7 @@ mod world; use crate::{ core::resources::{ assets::{AudioAssets, DataAssets, SpriteAssets, UiAssets}, - config::{Config, ConfigPlugin}, + config::{ConfigPlugin, GameConfig}, state::GameState, }, core::CorePlugin, @@ -89,7 +89,7 @@ fn main() { /// The setup function fn setup( data: Res, - configs: ResMut>, + configs: ResMut>, mut window: Query<&mut Window>, mut volume: ResMut, ) { From f27499e5bd8832bcbd794bc66cdbfbaf3928189f Mon Sep 17 00:00:00 2001 From: Thom Bruce Date: Mon, 30 Oct 2023 21:00:17 +0000 Subject: [PATCH 10/13] add todos re sfx volume and setting configs as a game resource --- src/main.rs | 3 +++ src/ships/bullet.rs | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/main.rs b/src/main.rs index d926f98..438f3c6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -88,6 +88,9 @@ fn main() { /// The setup function fn setup( + // TODO: Consider setting config as a resource, so that we + // don't have to query it like this every time we want to + // reference some value. data: Res, configs: ResMut>, mut window: Query<&mut Window>, diff --git a/src/ships/bullet.rs b/src/ships/bullet.rs index 7e70a34..79dc294 100644 --- a/src/ships/bullet.rs +++ b/src/ships/bullet.rs @@ -94,6 +94,10 @@ fn spawn_bullet( source: audios.gun.clone(), settings: PlaybackSettings { mode: PlaybackMode::Remove, + // TODO: This should be relative to an SFX Volume setting + // which should in turn be relative to the master volume. + // Right now, this is just being set relative to the + // GlobalVolume (which is configurable as master_volume). volume: Volume::new_relative(1.0), ..default() }, From 3274edb43c86bfb7eb31bc25a8ee55785fd03aa3 Mon Sep 17 00:00:00 2001 From: Thom Bruce Date: Mon, 30 Oct 2023 22:28:45 +0000 Subject: [PATCH 11/13] load credits from new credits asset file --- CHANGELOG.md | 1 + assets/verse.credits.ron | 41 +++++ src/core/resources/assets.rs | 5 + src/ui/menus/credits.rs | 300 ++++++++++++++--------------------- 4 files changed, 162 insertions(+), 185 deletions(-) create mode 100644 assets/verse.credits.ron diff --git a/CHANGELOG.md b/CHANGELOG.md index 9de60d3..e10d3af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Gravitable component added allowing dynamic_orbit system to be applied to any entity +- Load credits from asset file ### Fixed diff --git a/assets/verse.credits.ron b/assets/verse.credits.ron new file mode 100644 index 0000000..740db06 --- /dev/null +++ b/assets/verse.credits.ron @@ -0,0 +1,41 @@ +Credits( + developed_by: "Thom Bruce", + title_font: ( + credit_title: "Edge of the Galaxy by Quinn Davis Type", + credit_meta: "FontSpace, Public Domain" + ), + art: [ + ( + credit_title: "Space Shooter Redux by Kenney", + credit_meta: "kenney.nl, CC0" + ), + ( + credit_title: "Ship Mixer by Kenney", + credit_meta: "kenney.nl" + ), + ( + credit_title: "Pixel Planets by Deep-Fold", + credit_meta: "itch.io, MIT" + ), + ( + credit_title: "Xolonium Typeface by Severin Meyer", + credit_meta: "Font Library, OFL (SIL Open Font License)" + ), + ], + music: [ + ( + credit_title: "Lightspeed by Beat Mekanik", + credit_meta: "Free Music Archive, CC BY" + ), + ( + credit_title: "Space Dust by Kirk Osamayo", + credit_meta: "Free Music Archive, CC BY" + ), + ], + audio: [ + ( + credit_title: "Impact Sounds by Kenney", + credit_meta: "kenney.nl, CC0" + ), + ] +) diff --git a/src/core/resources/assets.rs b/src/core/resources/assets.rs index 642c463..c87b8ba 100644 --- a/src/core/resources/assets.rs +++ b/src/core/resources/assets.rs @@ -1,12 +1,17 @@ use bevy::prelude::*; use bevy_asset_loader::prelude::*; +use crate::ui::menus::credits::Credits; + use super::config::GameConfig; #[derive(AssetCollection, Resource)] pub struct DataAssets { #[asset(path = "verse.config.ron")] pub config: Handle, + + #[asset(path = "verse.credits.ron")] + pub credits: Handle, } #[derive(AssetCollection, Resource)] diff --git a/src/ui/menus/credits.rs b/src/ui/menus/credits.rs index 43b7ef7..22d161f 100644 --- a/src/ui/menus/credits.rs +++ b/src/ui/menus/credits.rs @@ -1,8 +1,12 @@ -use bevy::prelude::*; +use bevy::{ + prelude::*, + reflect::{TypePath, TypeUuid}, +}; +use bevy_common_assets::ron::RonAssetPlugin; use crate::{ core::resources::{ - assets::UiAssets, + assets::{DataAssets, UiAssets}, state::{ForState, GameState}, }, ui::resources::top::Top, @@ -11,15 +15,39 @@ use crate::{ pub struct CreditsPlugin; impl Plugin for CreditsPlugin { fn build(&self, app: &mut App) { + app.add_plugins(RonAssetPlugin::::new(&["credits.ron"])); app.add_systems(OnEnter(GameState::Credits), setup); app.add_systems(Update, credits_system.run_if(in_state(GameState::Credits))); } } +#[derive(serde::Deserialize, TypeUuid, TypePath)] +#[uuid = "6763db47-17ca-4530-b604-94492c3a4c58"] +pub struct Credits { + developed_by: String, + title_font: Credit, + art: Vec, + music: Vec, + audio: Vec, +} + +#[derive(serde::Deserialize)] +pub struct Credit { + credit_title: String, + credit_meta: String, +} + #[derive(Component)] -pub struct Credits; +pub struct Scrolling; + +fn setup( + mut commands: Commands, + ui: Res, + data: Res, + credits: ResMut>, +) { + let credits = credits.get(&data.credits.clone()).unwrap(); -fn setup(mut commands: Commands, ui: Res) { commands .spawn(( NodeBundle { @@ -53,7 +81,7 @@ fn setup(mut commands: Commands, ui: Res) { }, ..default() }, - Credits, + Scrolling, // TODO: Initial value should be window Y + 25.0 Top(1000.0), )) @@ -75,7 +103,7 @@ fn setup(mut commands: Commands, ui: Res) { ..default() }, text: Text::from_section( - "Thom Bruce", + &credits.developed_by, TextStyle { font: ui.font.clone(), font_size: 20.0, @@ -105,7 +133,7 @@ fn setup(mut commands: Commands, ui: Res) { ..default() }, text: Text::from_section( - "Edge of the Galaxy by Quinn Davis Type", + &credits.title_font.credit_title, TextStyle { font: ui.font.clone(), font_size: 20.0, @@ -116,7 +144,7 @@ fn setup(mut commands: Commands, ui: Res) { },)); parent.spawn((TextBundle { text: Text::from_section( - "FontSpace, Public Domain", + &credits.title_font.credit_meta, TextStyle { font: ui.font.clone(), font_size: 14.0, @@ -140,110 +168,34 @@ fn setup(mut commands: Commands, ui: Res) { ), ..default() },)); - parent.spawn((TextBundle { - style: Style { - margin: UiRect::top(Val::Px(25.)), - ..default() - }, - text: Text::from_section( - "Space Shooter Redux by Kenney", - TextStyle { - font: ui.font.clone(), - font_size: 20.0, - color: Color::rgb_u8(0xCC, 0xCC, 0xCC), - }, - ), - ..default() - },)); - parent.spawn((TextBundle { - text: Text::from_section( - "kenney.nl, CC0", - TextStyle { - font: ui.font.clone(), - font_size: 14.0, - color: Color::rgb_u8(0xAA, 0xAA, 0xAA), - }, - ), - ..default() - },)); - parent.spawn((TextBundle { - style: Style { - margin: UiRect::top(Val::Px(25.)), - ..default() - }, - text: Text::from_section( - "Ship Mixer by Kenney", - TextStyle { - font: ui.font.clone(), - font_size: 20.0, - color: Color::rgb_u8(0xCC, 0xCC, 0xCC), - }, - ), - ..default() - },)); - parent.spawn((TextBundle { - text: Text::from_section( - "kenney.nl", - TextStyle { - font: ui.font.clone(), - font_size: 14.0, - color: Color::rgb_u8(0xAA, 0xAA, 0xAA), + for credit in credits.art.iter() { + parent.spawn((TextBundle { + style: Style { + margin: UiRect::top(Val::Px(25.)), + ..default() }, - ), - ..default() - },)); - parent.spawn((TextBundle { - style: Style { - margin: UiRect::top(Val::Px(25.)), + text: Text::from_section( + &credit.credit_title, + TextStyle { + font: ui.font.clone(), + font_size: 20.0, + color: Color::rgb_u8(0xCC, 0xCC, 0xCC), + }, + ), ..default() - }, - text: Text::from_section( - "Pixel Planets by Deep-Fold", - TextStyle { - font: ui.font.clone(), - font_size: 20.0, - color: Color::rgb_u8(0xCC, 0xCC, 0xCC), - }, - ), - ..default() - },)); - parent.spawn((TextBundle { - text: Text::from_section( - "itch.io, MIT", - TextStyle { - font: ui.font.clone(), - font_size: 14.0, - color: Color::rgb_u8(0xAA, 0xAA, 0xAA), - }, - ), - ..default() - },)); - parent.spawn((TextBundle { - style: Style { - margin: UiRect::top(Val::Px(25.)), + },)); + parent.spawn((TextBundle { + text: Text::from_section( + &credit.credit_meta, + TextStyle { + font: ui.font.clone(), + font_size: 14.0, + color: Color::rgb_u8(0xAA, 0xAA, 0xAA), + }, + ), ..default() - }, - text: Text::from_section( - "Xolonium Typeface by Severin Meyer", - TextStyle { - font: ui.font.clone(), - font_size: 20.0, - color: Color::rgb_u8(0xCC, 0xCC, 0xCC), - }, - ), - ..default() - },)); - parent.spawn((TextBundle { - text: Text::from_section( - "Font Library, OFL (SIL Open Font License)", - TextStyle { - font: ui.font.clone(), - font_size: 14.0, - color: Color::rgb_u8(0xAA, 0xAA, 0xAA), - }, - ), - ..default() - },)); + },)); + } parent.spawn((TextBundle { style: Style { margin: UiRect::top(Val::Px(50.)), @@ -259,58 +211,34 @@ fn setup(mut commands: Commands, ui: Res) { ), ..default() },)); - parent.spawn((TextBundle { - style: Style { - margin: UiRect::top(Val::Px(25.)), - ..default() - }, - text: Text::from_section( - "Lightspeed by Beat Mekanik", - TextStyle { - font: ui.font.clone(), - font_size: 20.0, - color: Color::rgb_u8(0xCC, 0xCC, 0xCC), + for credit in credits.music.iter() { + parent.spawn((TextBundle { + style: Style { + margin: UiRect::top(Val::Px(25.)), + ..default() }, - ), - ..default() - },)); - parent.spawn((TextBundle { - text: Text::from_section( - "Free Music Archive, CC BY", - TextStyle { - font: ui.font.clone(), - font_size: 14.0, - color: Color::rgb_u8(0xAA, 0xAA, 0xAA), - }, - ), - ..default() - },)); - parent.spawn((TextBundle { - style: Style { - margin: UiRect::top(Val::Px(25.)), + text: Text::from_section( + &credit.credit_title, + TextStyle { + font: ui.font.clone(), + font_size: 20.0, + color: Color::rgb_u8(0xCC, 0xCC, 0xCC), + }, + ), ..default() - }, - text: Text::from_section( - "Space Dust by Kirk Osamayo", - TextStyle { - font: ui.font.clone(), - font_size: 20.0, - color: Color::rgb_u8(0xCC, 0xCC, 0xCC), - }, - ), - ..default() - },)); - parent.spawn((TextBundle { - text: Text::from_section( - "Free Music Archive, CC BY", - TextStyle { - font: ui.font.clone(), - font_size: 14.0, - color: Color::rgb_u8(0xAA, 0xAA, 0xAA), - }, - ), - ..default() - },)); + },)); + parent.spawn((TextBundle { + text: Text::from_section( + &credit.credit_meta, + TextStyle { + font: ui.font.clone(), + font_size: 14.0, + color: Color::rgb_u8(0xAA, 0xAA, 0xAA), + }, + ), + ..default() + },)); + } parent.spawn((TextBundle { style: Style { margin: UiRect::top(Val::Px(50.)), @@ -326,39 +254,41 @@ fn setup(mut commands: Commands, ui: Res) { ), ..default() },)); - parent.spawn((TextBundle { - style: Style { - margin: UiRect::top(Val::Px(25.)), - ..default() - }, - text: Text::from_section( - "Impact Sounds by Kenney", - TextStyle { - font: ui.font.clone(), - font_size: 20.0, - color: Color::rgb_u8(0xCC, 0xCC, 0xCC), + for credit in credits.audio.iter() { + parent.spawn((TextBundle { + style: Style { + margin: UiRect::top(Val::Px(25.)), + ..default() }, - ), - ..default() - },)); - parent.spawn((TextBundle { - text: Text::from_section( - "kenney.nl, CC0", - TextStyle { - font: ui.font.clone(), - font_size: 14.0, - color: Color::rgb_u8(0xAA, 0xAA, 0xAA), - }, - ), - ..default() - },)); + text: Text::from_section( + &credit.credit_title, + TextStyle { + font: ui.font.clone(), + font_size: 20.0, + color: Color::rgb_u8(0xCC, 0xCC, 0xCC), + }, + ), + ..default() + },)); + parent.spawn((TextBundle { + text: Text::from_section( + &credit.credit_meta, + TextStyle { + font: ui.font.clone(), + font_size: 14.0, + color: Color::rgb_u8(0xAA, 0xAA, 0xAA), + }, + ), + ..default() + },)); + } }); }); } fn credits_system( time: Res