diff --git a/game/src/camera.rs b/game/src/camera.rs new file mode 100644 index 0000000..e2fc46d --- /dev/null +++ b/game/src/camera.rs @@ -0,0 +1 @@ +pub mod camera_plugin; diff --git a/game/src/camera/camera_plugin.rs b/game/src/camera/camera_plugin.rs new file mode 100644 index 0000000..cdb2dd5 --- /dev/null +++ b/game/src/camera/camera_plugin.rs @@ -0,0 +1,83 @@ +use avian2d::prelude::*; +use bevy::{input::mouse::MouseWheel, prelude::*}; + +pub struct CameraPlugin; + +///Component that marks the Camera's current target +#[derive(Component)] +pub struct CameraTarget; + +///Component that marks the main camera +#[derive(Component)] +pub struct MainCamera; + +impl Plugin for CameraPlugin { + fn build(&self, app: &mut App) { + app.add_systems(Startup, setup_main_camera); + app.add_systems( + PostUpdate, + update_camera + .after(PhysicsSet::Sync) + .before(TransformSystem::TransformPropagate), + ); + app.add_systems(Update, zoom_camera); + } +} + +///Sets up a 2d camera and attaches the MainCamera marker to it +fn setup_main_camera(mut commands: Commands) { + commands.spawn((Camera2dBundle::default(), MainCamera)); +} + +///Update camera function will have the main camera follow any entity with the CameraTarget tag +fn update_camera( + mut camera_query: Query<&mut Transform, (With, Without)>, + target_query: Query<&Transform, (With, Without)>, +) { + let num_targets = target_query.iter().len(); + + if (num_targets > 1) { + error!("More than one entity with CameraTarget Component!"); + return; + } + + let Ok(mut camera) = camera_query.get_single_mut() else { + error!("Could not execute query for single MainCamera component"); + return; + }; + + let Ok(target) = target_query.get_single() else { + return; + }; + + let Vec3 { x, y, .. } = target.translation; + + let direction = Vec3::new(x, y, camera.translation.z); + + camera.translation = direction; +} + +///Camera Zooming Function, uses MouseWheel Scrolling up/down for zooming in/out +fn zoom_camera( + mut scroll_event: EventReader, + mut camera: Query<&mut OrthographicProjection, With>, +) { + //Zoom Sensitivity + let zoom_factor = 0.1; + + //Amount to zoom in this update cycle + let mut zoom_amount = 0.0; + + for event in scroll_event.read() { + zoom_amount += -event.y * zoom_factor + } + + if zoom_amount != 0.0 { + for mut projection in camera.iter_mut() { + projection.scale += zoom_amount; + + //This statement makes sure that the amount of zoom is capped, can change if need be + projection.scale = projection.scale.clamp(0.1, 5.0); + } + } +} diff --git a/game/src/main.rs b/game/src/main.rs index 814500f..a97476a 100644 --- a/game/src/main.rs +++ b/game/src/main.rs @@ -1,5 +1,6 @@ #![allow(unused)] mod animation; +mod camera; mod components; mod debug; mod movement; @@ -9,6 +10,7 @@ use crate::animation::animation_system::SpriteAnimationPlugin; use avian2d::prelude::*; use bevy::prelude::*; use bevy_ecs_ldtk::prelude::*; +use camera::camera_plugin::CameraPlugin; use debug::debug_plugin::DebugPlugin; use movement::plugin::CharacterControllerPlugin; use plugins::health_and_damage_plugin::HealthAndDamagePlugin; @@ -22,6 +24,7 @@ fn main() { //user plugins .add_plugins(HealthAndDamagePlugin) .add_plugins(DebugPlugin) + .add_plugins(CameraPlugin) .add_plugins(SpriteAnimationPlugin) .run(); }