diff --git a/.gitignore b/.gitignore index b83d222..808a09c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target/ +/assets/Sunny Land Collection Files/ diff --git a/src/camera.rs b/src/camera.rs new file mode 100644 index 0000000..ab4c02a --- /dev/null +++ b/src/camera.rs @@ -0,0 +1,101 @@ +use bevy::prelude::*; +use bevy_ecs_ldtk::prelude::*; + +use crate::player::Player; + +const ASPECT_RATIO: f32 = 16. / 9.; + +#[allow(clippy::type_complexity)] +pub fn camera_fit_inside_current_level( + mut camera_query: Query< + ( + &mut bevy::render::camera::OrthographicProjection, + &mut Transform, + ), + Without, + >, + player_query: Query<&Transform, With>, + level_query: Query<(&Transform, &LevelIid), (Without, Without)>, + ldtk_projects: Query<&Handle>, + level_selection: Res, + ldtk_project_assets: Res>, +) { + if let Ok(Transform { + translation: player_translation, + .. + }) = player_query.get_single() + { + let player_translation = *player_translation; + + let (mut orthographic_projection, mut camera_transform) = camera_query.single_mut(); + + for (level_transform, level_iid) in &level_query { + let ldtk_project = ldtk_project_assets + .get(ldtk_projects.single()) + .expect("Project should be loaded if level has spawned"); + + let level = ldtk_project + .get_raw_level_by_iid(&level_iid.to_string()) + .expect("Spawned level should exist in LDtk project"); + + if level_selection.is_match(&LevelIndices::default(), level) { + let level_ratio = level.px_wid as f32 / level.px_hei as f32; + orthographic_projection.viewport_origin = Vec2::ZERO; + if level_ratio > ASPECT_RATIO { + // level is wider than the screen + let height = (level.px_hei as f32 / 9.).round() * 9.; + let width = height * ASPECT_RATIO; + orthographic_projection.scaling_mode = + bevy::render::camera::ScalingMode::Fixed { width, height }; + camera_transform.translation.x = + (player_translation.x - level_transform.translation.x - width / 4.) + .clamp(0., level.px_wid as f32 - width); + camera_transform.translation.y = 0.; + } else { + // level is taller than the screen + let width = (level.px_wid as f32 / 16.).round() * 16.; + let height = width / ASPECT_RATIO; + orthographic_projection.scaling_mode = + bevy::render::camera::ScalingMode::Fixed { width, height }; + camera_transform.translation.y = + (player_translation.y - level_transform.translation.y - height / 4.) + .clamp(0., level.px_hei as f32 - height); + camera_transform.translation.x = 0.; + } + + camera_transform.translation.x += level_transform.translation.x; + camera_transform.translation.y += level_transform.translation.y; + } + } + } +} +const CAMERA_DECAY_RATE: f32 = 2.; +fn update_camera( + mut camera_query: Query< + ( + &mut bevy::render::camera::OrthographicProjection, + &mut Transform, + ), + Without, + >, + player_query: Query<&Transform, With>, + time: Res