From 89ed6e93f645b049c135caf8377357fd180a1f7d Mon Sep 17 00:00:00 2001 From: Louis Capitanchik <contact@louiscap.co> Date: Sat, 1 Oct 2022 19:57:37 +0100 Subject: [PATCH] Add basic assets - Include dawnbringer sprites - Create basic spawner, spawn player - Fix splash screen scaling for virtual pixel sizes --- .gitignore | 4 ++- CREDITS | 7 +++++ README.md | 2 ++ assets/fonts/Kaph.ttf | 3 ++ assets/sprites/creatures.png | 3 ++ assets/sprites/environs.png | 3 ++ game_core/src/assets/startup.rs | 11 +++++++- game_core/src/debug.rs | 24 ++++++++++++++++ game_core/src/entities/lifecycle.rs | 10 +++++++ game_core/src/entities/mod.rs | 2 ++ game_core/src/entities/spawner.rs | 33 ++++++++++++++++++++++ game_core/src/lib.rs | 3 ++ game_core/src/main.rs | 3 +- game_core/src/splash_screen/systems.rs | 38 ++++++++++++++++++-------- game_core/src/system/graphics.rs | 3 ++ game_core/src/system/load_config.rs | 12 ++++---- game_core/src/system/mod.rs | 1 + game_core/src/system/resources.rs | 7 ++--- game_core/src/world/level_map.rs | 26 ++++++++++++++++++ game_core/src/world/mod.rs | 1 + 20 files changed, 172 insertions(+), 24 deletions(-) create mode 100644 CREDITS create mode 100644 assets/fonts/Kaph.ttf create mode 100644 assets/sprites/creatures.png create mode 100644 assets/sprites/environs.png create mode 100644 game_core/src/debug.rs create mode 100644 game_core/src/entities/lifecycle.rs create mode 100644 game_core/src/entities/mod.rs create mode 100644 game_core/src/entities/spawner.rs create mode 100644 game_core/src/system/graphics.rs create mode 100644 game_core/src/world/level_map.rs create mode 100644 game_core/src/world/mod.rs diff --git a/.gitignore b/.gitignore index 3ad33f1..bca9cf9 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,6 @@ .idea/ .vscode/ -dist/ \ No newline at end of file +dist/ + +*.tiled-session \ No newline at end of file diff --git a/CREDITS b/CREDITS new file mode 100644 index 0000000..6e4376f --- /dev/null +++ b/CREDITS @@ -0,0 +1,7 @@ +[fonts] + +Kaph - GGBotNet - https://ggbot.itch.io/kaph-font + +[sprites] + +Dawnlike - DragonDePlatino / Dawnbringer - https://opengameart.org/content/dawnlike-16x16-universal-rogue-like-tileset-v181 \ No newline at end of file diff --git a/README.md b/README.md index 5abf2c6..40aae88 100644 --- a/README.md +++ b/README.md @@ -52,5 +52,7 @@ The code source files found in this repository are covered by the license found The logo found in `assets/splash.png` is licensed under the following license for use only within the context of this project. +Asset creators are listed in CREDITS with any relevant licenses + <p xmlns:cc="http://creativecommons.org/ns#" xmlns:dct="http://purl.org/dc/terms/"><span property="dct:title">Microhacks Logo</span> by <span property="cc:attributionName">Microhacks Ltd</span> is licensed under <a href="http://creativecommons.org/licenses/by-nc-nd/4.0/?ref=chooser-v1" target="_blank" rel="license noopener noreferrer" style="display:inline-block;">CC BY-NC-ND 4.0</a></p> <img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/nc.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/nd.svg?ref=chooser-v1"> diff --git a/assets/fonts/Kaph.ttf b/assets/fonts/Kaph.ttf new file mode 100644 index 0000000..bf07998 --- /dev/null +++ b/assets/fonts/Kaph.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1dba90d6614e66d673e5e3e476195799727e120b6c922327289f0204d67c34d6 +size 406568 diff --git a/assets/sprites/creatures.png b/assets/sprites/creatures.png new file mode 100644 index 0000000..74d5c5a --- /dev/null +++ b/assets/sprites/creatures.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d169fb7508b4524311499cccb7bddec281189fdc3bd6fd8ffd66293a1e486291 +size 27025 diff --git a/assets/sprites/environs.png b/assets/sprites/environs.png new file mode 100644 index 0000000..3e42df8 --- /dev/null +++ b/assets/sprites/environs.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dfa6e683894dffe10ecbbd5fafd89a41985c2f08bf99e1a07927b4c67807f463 +size 130133 diff --git a/game_core/src/assets/startup.rs b/game_core/src/assets/startup.rs index cb6d71e..e848c5f 100644 --- a/game_core/src/assets/startup.rs +++ b/game_core/src/assets/startup.rs @@ -2,7 +2,7 @@ use bevy::asset::LoadState; use bevy::prelude::*; use iyes_loopless::prelude::NextState; -use crate::assets::AssetTypeLoader; +use crate::assets::{AssetTypeLoader, SpriteSheetConfig}; use crate::system::flow::AppState; pub fn start_preload_resources(mut commands: Commands) { @@ -14,6 +14,15 @@ pub fn start_preload_resources(mut commands: Commands) { pub fn start_load_resources(mut loader: AssetTypeLoader) { loader.load_images(&[("splash.png", "splash")]); loader.load_audio(&[("splash_sting.mp3", "splash_sting")]); + + let sheet_config = SpriteSheetConfig::squares(16, 64, 64); + loader.load_spritesheet( + &sheet_config, + &[ + ("sprites/environs.png", "environs"), + ("sprites/creatures.png", "creatures"), + ], + ); } pub fn check_load_resources(mut commands: Commands, loader: AssetTypeLoader) { diff --git a/game_core/src/debug.rs b/game_core/src/debug.rs new file mode 100644 index 0000000..0b87c5f --- /dev/null +++ b/game_core/src/debug.rs @@ -0,0 +1,24 @@ +use bevy::math::uvec2; +use bevy::prelude::*; +use iyes_loopless::prelude::AppLooplessStateExt; +use iyes_loopless::state::NextState; + +use crate::entities::spawner::EntitySpawner; +use crate::system::flow::AppState; + +pub fn spawn_player(mut spawner: EntitySpawner) { + log::info!("Spawning player"); + spawner.spawn_player(uvec2(2, 2)); +} + +pub fn skip_menu(mut commands: Commands) { + commands.insert_resource(NextState(AppState::InGame)); +} + +pub struct DebugPlugin; +impl Plugin for DebugPlugin { + fn build(&self, app: &mut App) { + app.add_enter_system(AppState::Menu, skip_menu) + .add_enter_system(AppState::InGame, spawn_player); + } +} diff --git a/game_core/src/entities/lifecycle.rs b/game_core/src/entities/lifecycle.rs new file mode 100644 index 0000000..4d105b2 --- /dev/null +++ b/game_core/src/entities/lifecycle.rs @@ -0,0 +1,10 @@ +use bevy::prelude::*; + +#[derive(Debug, Clone, Copy, Component)] +pub struct GameEntity; + +pub fn remove_game_entities(mut commands: Commands, query: Query<Entity, With<GameEntity>>) { + for entity in &query { + commands.entity(entity).despawn_recursive(); + } +} diff --git a/game_core/src/entities/mod.rs b/game_core/src/entities/mod.rs new file mode 100644 index 0000000..13037db --- /dev/null +++ b/game_core/src/entities/mod.rs @@ -0,0 +1,2 @@ +pub mod lifecycle; +pub mod spawner; diff --git a/game_core/src/entities/spawner.rs b/game_core/src/entities/spawner.rs new file mode 100644 index 0000000..ab539ea --- /dev/null +++ b/game_core/src/entities/spawner.rs @@ -0,0 +1,33 @@ +use bevy::ecs::system::SystemParam; +use bevy::prelude::*; + +use crate::assets::AssetHandles; +use crate::entities::lifecycle::GameEntity; +use crate::system::camera::ChaseCam; +use crate::system::graphics::LAYER_CREATURE; + +const PLAYER_SPRITE: usize = 2; + +#[derive(SystemParam)] +pub struct EntitySpawner<'w, 's> { + pub commands: Commands<'w, 's>, + pub handles: Res<'w, AssetHandles>, +} + +impl<'w, 's> EntitySpawner<'w, 's> { + pub fn spawn_player(&mut self, grid_position: UVec2) { + let mut entity = self.commands.spawn(); + + entity.insert(ChaseCam).insert(GameEntity); + + entity.insert_bundle(SpriteSheetBundle { + texture_atlas: self.handles.atlas("creatures"), + transform: Transform::from_translation(grid_position.as_vec2().extend(LAYER_CREATURE)), + sprite: TextureAtlasSprite { + index: PLAYER_SPRITE, + ..Default::default() + }, + ..Default::default() + }); + } +} diff --git a/game_core/src/lib.rs b/game_core/src/lib.rs index e0acb2f..aff8890 100644 --- a/game_core/src/lib.rs +++ b/game_core/src/lib.rs @@ -1,4 +1,7 @@ pub mod assets; +pub mod debug; +pub mod entities; pub mod multiplayer; pub mod splash_screen; pub mod system; +pub mod world; diff --git a/game_core/src/main.rs b/game_core/src/main.rs index 8d7c57b..879c003 100644 --- a/game_core/src/main.rs +++ b/game_core/src/main.rs @@ -1,10 +1,10 @@ use bevy::prelude::*; +use game_core::assets::AssetHandles; use game_core::system::flow::AppState; use game_core::system::resources::DefaultResourcesPlugin; use iyes_loopless::prelude::AppLooplessStateExt; use micro_musicbox::CombinedAudioPlugins; use remote_events::RemoteEventPlugin; -use game_core::assets::AssetHandles; fn main() { App::new() @@ -19,5 +19,6 @@ fn main() { game_core::multiplayer::OutgoingEvent, game_core::multiplayer::IncomingEvent, >::new()) + .add_plugin(game_core::debug::DebugPlugin) .run(); } diff --git a/game_core/src/splash_screen/systems.rs b/game_core/src/splash_screen/systems.rs index 1894942..c0c90b4 100644 --- a/game_core/src/splash_screen/systems.rs +++ b/game_core/src/splash_screen/systems.rs @@ -9,6 +9,7 @@ use crate::splash_screen::components::{ SplashAnimation, SplashAnimationBundle, SplashAnimationTimer, SplashAnimationType, }; use crate::system::flow::AppState; +use crate::system::load_config::initial_size; use crate::system::utilities::f32_min; use crate::system::window::WindowManager; @@ -36,14 +37,19 @@ pub fn setup_splash_screen( windows: WindowManager, mut music_box: MusicBox<AssetHandles>, ) { - let window_size = match windows.get_primary_window() { - Some(size) => size, - None => { - log::error!("Missing window for splash screen"); - commands.insert_resource(NextState(AppState::Menu)); - return; - } - }; + // Changed window scaling to auto, so layout is based on virtual pixel units, not + // window units + // + // let window_size = match windows.get_primary_window() { + // Some(size) => size, + // None => { + // log::error!("Missing window for splash screen"); + // commands.insert_resource(NextState(AppState::Menu)); + // return; + // } + // }; + + let window_size = initial_size(); let handle = match handles.images.get("splash") { Some(handle) => handle, @@ -59,11 +65,21 @@ pub fn setup_splash_screen( commands.insert_resource(ClearColor(Color::hex("001122").unwrap())); - let scale_factor = match window_size.width() > window_size.height() { - true => window_size.height() / image_data.texture_descriptor.size.height as f32, - false => window_size.width() / image_data.texture_descriptor.size.width as f32, + let image_size = image_data.texture_descriptor.size; + let scale_factor = match window_size.0 > window_size.1 { + true => window_size.1 / image_size.height as f32, + false => window_size.0 / image_size.width as f32, }; + log::info!( + "Splash scaling: s{:.3}; i({}x{}); w({}x{})", + scale_factor, + image_size.width, + image_size.height, + window_size.0, + window_size.1 + ); + image_data.sampler_descriptor = ImageSampler::linear(); music_box.play_sfx("splash_sting"); diff --git a/game_core/src/system/graphics.rs b/game_core/src/system/graphics.rs new file mode 100644 index 0000000..985f237 --- /dev/null +++ b/game_core/src/system/graphics.rs @@ -0,0 +1,3 @@ +pub const LAYER_TILE: f32 = 50.0; +pub const LAYER_ITEM: f32 = 300.0; +pub const LAYER_CREATURE: f32 = 400.0; diff --git a/game_core/src/system/load_config.rs b/game_core/src/system/load_config.rs index 4eba511..4221c06 100644 --- a/game_core/src/system/load_config.rs +++ b/game_core/src/system/load_config.rs @@ -10,7 +10,7 @@ mod setup { } pub fn initial_size() -> (f32, f32) { - (1280.0, 720.0) + (16.0 * 32.0, 16.0 * 18.0) } } @@ -22,8 +22,8 @@ mod setup { #[cfg(feature = "no_aspect")] pub fn initial_size() -> (f32, f32) { - static default_width: f32 = 1280.0; - static default_height: f32 = 720.0; + static default_width: f32 = 16.0 * 32.0; + static default_height: f32 = 16.0 * 18.0; web_sys::window() .and_then(|window: web_sys::Window| { @@ -45,9 +45,9 @@ mod setup { #[cfg(not(feature = "no_aspect"))] pub fn initial_size() -> (f32, f32) { - static default_width: f32 = 1280.0; - static default_height: f32 = 720.0; - static ratio: f32 = 1280.0 / 720.0; + static default_width: f32 = 16.0 * 32.0; + static default_height: f32 = 16.0 * 18.0; + static ratio: f32 = default_width / default_height; web_sys::window() .and_then(|window: web_sys::Window| { diff --git a/game_core/src/system/mod.rs b/game_core/src/system/mod.rs index 309ab32..2a69192 100644 --- a/game_core/src/system/mod.rs +++ b/game_core/src/system/mod.rs @@ -1,5 +1,6 @@ pub mod camera; pub mod flow; +pub mod graphics; pub mod load_config; pub mod resources; pub mod utilities; diff --git a/game_core/src/system/resources.rs b/game_core/src/system/resources.rs index dfb7d23..9ac587c 100644 --- a/game_core/src/system/resources.rs +++ b/game_core/src/system/resources.rs @@ -3,7 +3,6 @@ use bevy::prelude::*; use bevy::render::texture::ImageSettings; use bevy::window::PresentMode; -use crate::system::camera::spawn_orthographic_camera; use crate::system::load_config::{get_asset_path_string, initial_size}; pub struct DefaultResourcesPlugin; @@ -12,10 +11,10 @@ impl Plugin for DefaultResourcesPlugin { let (width, height) = initial_size(); app.insert_resource(WindowDescriptor { - width, - height, + width: width * 3.0, + height: height * 3.0, resizable: true, - title: String::from("Bevy 2D Template"), + title: String::from("Ludum Dare 51"), present_mode: PresentMode::AutoNoVsync, ..Default::default() }) diff --git a/game_core/src/world/level_map.rs b/game_core/src/world/level_map.rs new file mode 100644 index 0000000..b6e2ed7 --- /dev/null +++ b/game_core/src/world/level_map.rs @@ -0,0 +1,26 @@ +use std::ops::Deref; + +use bevy::math::UVec2; +use bevy::prelude::*; + +pub const WORLD_TILE_SIZE: f32 = 16.0; + +/// Track the location of an entity within a grid +#[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Component)] +#[repr(transparent)] +pub struct GridPosition(pub UVec2); +impl Deref for GridPosition { + type Target = UVec2; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +/// Take an entity's position on a grid, and sync it up to the transform used to render +/// the sprite +pub fn sync_grid_to_transform(mut query: Query<(&GridPosition, &mut Transform)>) { + for (position, mut transform) in &mut query { + transform.translation = ((position.as_vec2() * WORLD_TILE_SIZE) + (WORLD_TILE_SIZE / 2.0)) + .extend(transform.translation.z); + } +} diff --git a/game_core/src/world/mod.rs b/game_core/src/world/mod.rs new file mode 100644 index 0000000..c379ed7 --- /dev/null +++ b/game_core/src/world/mod.rs @@ -0,0 +1 @@ +pub mod level_map; -- GitLab