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