diff --git a/crates/border-wars/src/camera.rs b/crates/border-wars/src/camera.rs new file mode 100644 index 0000000..067da21 --- /dev/null +++ b/crates/border-wars/src/camera.rs @@ -0,0 +1,123 @@ +//! This module contains the camera systems responsible for movement and +//! scaling. + +use bevy::input::mouse::{MouseScrollUnit, MouseWheel}; +use bevy::prelude::*; + +use crate::CurrentScene; + +/// The speed of camera movement. +#[derive(Resource)] +struct CameraSpeedMouvement(f32); + +/// The speed of camera scaling. +#[derive(Resource)] +struct CameraSpeedScale(f32); + +/// The minimum scale of the camera. +#[derive(Resource)] +struct MinimumScale(f32); + +/// The maximum scale of the camera. +#[derive(Resource)] +struct MaximumScale(f32); + +/// Key settings for camera movement. +#[derive(Resource)] +pub struct KeysMovementSettings { + /// Key to move the camera up. + pub up: KeyCode, + + /// Key to move the camera down. + pub down: KeyCode, + + /// Key to move the camera right. + pub right: KeyCode, + + /// Key to move the camera left. + pub left: KeyCode, +} + +/// A Bevy plugin for the camera. +/// Allows camera movement with the keyboard and scaling with the mouse. +pub struct CameraPlugin; + +impl Plugin for CameraPlugin { + fn build(&self, app: &mut App) { + app.add_systems(Startup, init_camera) + .add_systems(Startup, init_resources_for_camera) + .add_systems(Update, movement_system.run_if(in_state(CurrentScene::Game))) + .add_systems(Update, scale_system.run_if(in_state(CurrentScene::Game))); + } +} + +/// Initializes the camera. +fn init_camera(mut commands: Commands) { + commands.spawn(Camera2dBundle::default()); +} + +/// Initializes the resources related to the camera. +/// +/// - [KeysMovementSettings]: The key settings for camera movement. +/// - [CameraSpeedMouvement]: The speed of camera movement. +/// - [CameraSpeedScale]: The speed of camera scaling. +/// - [MinimumScale]: The minimum scale of the camera. +/// - [MaximumScale]: The maximum scale of the camera. +fn init_resources_for_camera(mut commands: Commands) { + commands.insert_resource(KeysMovementSettings { + up: KeyCode::Z, + down: KeyCode::S, + right: KeyCode::D, + left: KeyCode::Q, + }); + + commands.insert_resource(CameraSpeedMouvement(10.0)); + commands.insert_resource(CameraSpeedScale(0.1)); + commands.insert_resource(MinimumScale(0.1)); + commands.insert_resource(MaximumScale(10.0)); +} + +/// Moves the camera with keyboard input. +fn movement_system( + mut query: Query<&mut Transform, With>, + keys: Res>, + keys_settings: Res, + movement_speed: Res, +) { + for mut transform in query.iter_mut() { + let mut target = Vec3::ZERO; + for key in keys.get_pressed() { + match *key { + value if value == keys_settings.up => target.y += movement_speed.0, + value if value == keys_settings.down => target.y -= movement_speed.0, + value if value == keys_settings.right => target.x += movement_speed.0, + value if value == keys_settings.left => target.x -= movement_speed.0, + _ => continue, + } + } + + transform.translation += target; + } +} + +/// Scales the view with mouse input. +fn scale_system( + mut scroll_event: EventReader, + mut query: Query<&mut OrthographicProjection, With>, + min_scale: Res, + max_scale: Res, + scale_speed: Res, +) { + for event in scroll_event.read() { + for mut projection in query.iter_mut() { + if event.unit != MouseScrollUnit::Line { + return; + } + + let future_scale = event.y.mul_add(scale_speed.0, projection.scale); + if min_scale.0 < future_scale && future_scale < max_scale.0 { + projection.scale = future_scale; + } + } + } +} diff --git a/crates/border-wars/src/lib.rs b/crates/border-wars/src/lib.rs index db4c6db..a4acdb8 100644 --- a/crates/border-wars/src/lib.rs +++ b/crates/border-wars/src/lib.rs @@ -2,6 +2,7 @@ use bevy::prelude::*; +pub mod camera; pub mod map; pub mod scenes; diff --git a/crates/border-wars/src/main.rs b/crates/border-wars/src/main.rs index 31bc6d8..b4676c1 100644 --- a/crates/border-wars/src/main.rs +++ b/crates/border-wars/src/main.rs @@ -4,6 +4,7 @@ use bevy::prelude::*; use border_wars::map::generation::{EndMapGeneration, MapGenerationPlugin, StartMapGeneration}; use border_wars::map::renderer::RendererPlugin; use border_wars::map::Tile; +use border_wars::camera::CameraPlugin; use border_wars::scenes::ScenesPlugin; fn setup(mut writer: EventWriter) { @@ -37,5 +38,6 @@ fn main() { Update, update.run_if(in_state(border_wars::CurrentScene::Game)), ) + .add_plugins(CameraPlugin) .run(); }