diff --git a/src/lib.rs b/src/lib.rs index 5ae15d1..a8772b9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,17 +1,15 @@ -use bevy::prelude::*; +use bevy::{prelude::*, window::WindowResized}; mod events; mod performance_matrix; mod systems; -use systems::level::LevelId; +use systems::level::{LevelId, Tilesheet}; pub struct SokobanPlugin; impl Plugin for SokobanPlugin { fn build(&self, app: &mut App) { - // app.add_plugins(DefaultPlugins); - // #[cfg(debug_assertions)] app.add_plugins(performance_matrix::PerformanceMatrixPlugin); @@ -25,10 +23,20 @@ impl Plugin for SokobanPlugin { ); app.add_systems( Update, - systems::level::respawn.run_if(resource_changed_or_removed::()), + ( + systems::level::respawn.run_if(resource_changed_or_removed::()), + systems::camera::handle_window_resized_event.run_if(on_event::()), + systems::camera::handle_reset_camera_scale_event + .run_if(on_event::()), + systems::camera::handle_reset_camera_translate_event + .run_if(on_event::()), + ) + .chain(), ); - app.init_resource::() - .init_resource::(); + app.init_resource::().init_resource::(); + + app.add_event::() + .add_event::(); } } diff --git a/src/systems/camera.rs b/src/systems/camera.rs index 4939e8e..5c77156 100644 --- a/src/systems/camera.rs +++ b/src/systems/camera.rs @@ -1,13 +1,57 @@ use bevy::prelude::*; +use bevy::window::WindowResized; use crate::events; +use crate::systems::level::{Level, Tilesheet}; /// Sets up the main 2D camera. pub fn setup(mut commands: Commands) { commands.spawn(Camera2dBundle::default()); } -pub fn handle_reset_camera_scale_event(mut event_reader: EventReader) { - event_reader.clear(); - todo!() +pub fn handle_reset_camera_scale_event( + mut events: EventReader, + mut projection: Query<&mut OrthographicProjection>, + tilesheet: Res, + level: Query<&Level>, + window: Query<&Window>, +) { + events.clear(); + + let level = level.single(); + let size = tilesheet.tile_size.x * level.dimensions().map(|x| x as f32); + + let window = window.single(); + let width_scale = size.x / window.resolution.width(); + let height_scale = size.y / window.resolution.height(); + let scale = if width_scale > height_scale { + width_scale + } else { + height_scale + }; + projection.single_mut().scale = scale / 0.9; +} + +pub fn handle_reset_camera_translate_event( + mut events: EventReader, + tilesheet: Res, + level: Query<&Level>, + mut camera: Query<&mut Transform, With>, +) { + events.clear(); + + let level = level.single(); + let size = tilesheet.tile_size.x * level.dimensions().map(|x| x as f32); + + let mut camera = camera.single_mut(); + camera.translation.x = (size.x - tilesheet.tile_size.x) / 2.0; + camera.translation.y = -(size.y - tilesheet.tile_size.y) / 2.0; +} + +pub fn handle_window_resized_event( + mut events: EventReader, + mut reset_camera_scale_events: EventWriter, +) { + events.clear(); + reset_camera_scale_events.send_default(); } diff --git a/src/systems/level.rs b/src/systems/level.rs index df14183..473f941 100644 --- a/src/systems/level.rs +++ b/src/systems/level.rs @@ -1,8 +1,11 @@ use std::fs; use bevy::{prelude::*, utils::HashMap}; +use nalgebra::Vector2; use soukoban::Tiles; +use crate::events; + #[derive(Component, Deref, DerefMut)] pub struct Level(soukoban::Level); @@ -17,7 +20,7 @@ impl Default for LevelId { #[derive(Resource)] pub struct Tilesheet { - tile_size: Vec2, + pub tile_size: Vec2, tile_info: HashMap, handle: Handle, layout_handle: Handle, @@ -58,6 +61,8 @@ pub fn respawn( level_id: Res, tilesheet: Res, query: Query>, + mut reset_camera_scale_events: EventWriter, + mut reset_camera_translate_events: EventWriter, ) { if let Ok(entity) = query.get_single() { commands.entity(entity).despawn_recursive(); @@ -68,19 +73,37 @@ pub fn respawn( level_id.0, ) .unwrap(); - commands.spawn(Level(level)).with_children(|parent| { - let z = 0.0; - let index = 0; - parent.spawn((SpriteSheetBundle { - atlas: TextureAtlas { - layout: tilesheet.layout_handle.clone(), - index, - }, - texture: tilesheet.handle.clone(), - transform: Transform::from_xyz(0.0, 0.0, z), - ..default() - },)); - }); + commands + .spawn((Level(level.clone()), TransformBundle::default())) + .with_children(|parent| { + for y in 0..level.dimensions().y { + for x in 0..level.dimensions().x { + let position = Vector2::new(x, y); + if level[position].is_empty() { + continue; + } + for tile in level[position] { + let (index, z) = tilesheet.tile_info[&tile]; + parent.spawn(SpriteSheetBundle { + atlas: TextureAtlas { + layout: tilesheet.layout_handle.clone(), + index, + }, + texture: tilesheet.handle.clone(), + transform: Transform::from_xyz( + x as f32 * tilesheet.tile_size.x, + -y as f32 * tilesheet.tile_size.y, + z, + ), + ..default() + }); + } + } + } + }); + + reset_camera_scale_events.send_default(); + reset_camera_translate_events.send_default(); println!("Level #{}", level_id.0) }