diff --git a/.gitignore b/.gitignore index 3ad33f15381af401366a6545020c9aaee92e0964..bca9cf9f69997da3ffdd87528b46c65c75507a80 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 0000000000000000000000000000000000000000..6e4376fcee3eff579d0808c74d020b78d6c5fc49 --- /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 5abf2c6d68757e6505f73028d25eeca704a8c808..40aae88cc52848bd24754fba9fef70578d6974c5 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 0000000000000000000000000000000000000000..bf079986090614d9483ebd2ead80c6070390293e --- /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 0000000000000000000000000000000000000000..74d5c5a3d2a7e1b48a8c8332e337f7b9894547f1 --- /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 0000000000000000000000000000000000000000..3e42df867d6619ccb465c23d20b714368400343d --- /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 cb6d71ed2de4f8479c254b106a5effea69d0b012..e848c5fff0f0bd6adce82aada13ccc0799812bde 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 0000000000000000000000000000000000000000..0b87c5f02f21ca9524bccaf402d200c86a5b2291 --- /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 0000000000000000000000000000000000000000..4d105b24723296807d15e7946b9c19f9827031e9 --- /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 0000000000000000000000000000000000000000..13037dbe39af29500d714cea5a78c818e1367c67 --- /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 0000000000000000000000000000000000000000..ab539eaeff6c77f6fa5ec52ab0a03095d35b4cde --- /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 e0acb2fac262674fb983e9880091120b5ad2a646..aff889092a604f6530bdc59a3d05060465c8e162 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 8d7c57b49e5d161c1501e1ccb56f4c3709154641..879c0037d6db3da1d399500c0de73ac2016df47f 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 1894942c7741b7865c187d05f6cfcf7156cc47c1..c0c90b444e47880b85519218c6e65cd406b6baf4 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 0000000000000000000000000000000000000000..985f237d96f38154c9d974d2b883cbfe2d47452e --- /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 4eba511274240a7a2e5f0e9938e09044e7a2d484..4221c06e7d68a555fa6b7721d297886efc31351d 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 309ab329d7595034fdc2a5fcbbe46f67f4859192..2a691923179309a9f74a937f691f5958e290bd96 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 dfb7d23f9db124be02033a3b44f26d5665a619e8..9ac587c915a74e3e59a82e30393655786d1701c4 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 0000000000000000000000000000000000000000..b6e2ed7be7c06a9cd0cddae1967c7097f11f93ba --- /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 0000000000000000000000000000000000000000..c379ed7d24b0e81501eff93d8ae2a4db3351a1ec --- /dev/null +++ b/game_core/src/world/mod.rs @@ -0,0 +1 @@ +pub mod level_map;