From b8003795fa951e809c9036f5451d94f58e37de07 Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Fri, 15 Nov 2024 23:45:58 -0500 Subject: [PATCH] game: create TopDown2dCamera controller, fix warning --- crates/lyra-game/src/input/action.rs | 2 +- crates/lyra-game/src/scene/mod.rs | 3 + .../src/scene/top_down_controller.rs | 100 ++++++++++++++++++ examples/2d/src/main.rs | 13 ++- 4 files changed, 110 insertions(+), 8 deletions(-) create mode 100644 crates/lyra-game/src/scene/top_down_controller.rs diff --git a/crates/lyra-game/src/input/action.rs b/crates/lyra-game/src/input/action.rs index 1ad1db2..7189834 100644 --- a/crates/lyra-game/src/input/action.rs +++ b/crates/lyra-game/src/input/action.rs @@ -493,7 +493,7 @@ impl ActionHandlerBuilder { //fn actions_system(world: &mut World) -> anyhow::Result<()> { fn actions_system( input_btns: Res>, - mut mouse_ev: EventReader, + mouse_ev: EventReader, mut handler: ResMut, ) -> anyhow::Result<()> { // clear the states of all axises each frame diff --git a/crates/lyra-game/src/scene/mod.rs b/crates/lyra-game/src/scene/mod.rs index c348d71..115133f 100644 --- a/crates/lyra-game/src/scene/mod.rs +++ b/crates/lyra-game/src/scene/mod.rs @@ -4,4 +4,7 @@ pub use camera::*; mod free_fly_camera; pub use free_fly_camera::*; +mod top_down_controller; +pub use top_down_controller::*; + pub use lyra_scene::*; \ No newline at end of file diff --git a/crates/lyra-game/src/scene/top_down_controller.rs b/crates/lyra-game/src/scene/top_down_controller.rs new file mode 100644 index 0000000..4da521c --- /dev/null +++ b/crates/lyra-game/src/scene/top_down_controller.rs @@ -0,0 +1,100 @@ +use std::ops::DerefMut; + +use glam::{EulerRot, Quat, Vec3}; +use lyra_ecs::{query::{Res, View}, Component}; +use lyra_math::Transform; +use lyra_reflect::Reflect; + +use crate::{game::App, input::ActionHandler, plugin::Plugin, DeltaTime}; + +use super::{CameraProjection, ACTLBL_LOOK_LEFT_RIGHT, ACTLBL_LOOK_ROLL, ACTLBL_LOOK_UP_DOWN, ACTLBL_MOVE_FORWARD_BACKWARD, ACTLBL_MOVE_LEFT_RIGHT, ACTLBL_MOVE_UP_DOWN}; + +#[derive(Clone, Component, Reflect)] +pub struct TopDown2dCamera { + pub speed: f32, + /// The zoom speed of the camera, set to `None` to disable zooming. + pub zoom_speed: Option, + /// The smallest scale of the orthographic projection view. + /// + /// When the scale of the projection approaches zero, the more zoomed in the camera + /// will appear. + pub max_zoom: f32, + pub min_zoom: f32, +} + +impl Default for TopDown2dCamera { + fn default() -> Self { + Self { + speed: 5.0, + zoom_speed: None, + max_zoom: 0.36, + min_zoom: 1.0, + } + } +} + +pub fn top_down_2d_camera_controller(delta_time: Res, handler: Res, view: View<(&mut Transform, &mut CameraProjection, &TopDown2dCamera)>) -> anyhow::Result<()> { + let delta_time = **delta_time; + for (mut transform, mut proj, controller) in view.into_iter() { + let left = transform.left(); + let up = Vec3::Y; + + let move_y = handler.get_axis_modifier(ACTLBL_MOVE_FORWARD_BACKWARD).unwrap_or(0.0); + let move_x = handler.get_axis_modifier(ACTLBL_MOVE_LEFT_RIGHT).unwrap_or(0.0); + let move_z = handler.get_axis_modifier(ACTLBL_MOVE_UP_DOWN); + + let mut velocity = Vec3::ZERO; + velocity += move_y * up; + velocity += move_x * left; + + if let (Some(zoom_speed), Some(move_z)) = (controller.zoom_speed, move_z) { + match proj.deref_mut() { + CameraProjection::Orthographic(ortho) => { + let m = move_z * zoom_speed * delta_time; + ortho.scale = (ortho.scale + m).clamp(controller.max_zoom, controller.min_zoom); + }, + _ => {} + } + } + + if velocity != Vec3::ZERO { + transform.translation += velocity.normalize() * controller.speed * delta_time; // TODO: speeding up + } + + let motion_x = handler.get_axis_modifier(ACTLBL_LOOK_LEFT_RIGHT).unwrap_or(0.0); + let motion_y = handler.get_axis_modifier(ACTLBL_LOOK_UP_DOWN).unwrap_or(0.0); + let motion_z = handler.get_axis_modifier(ACTLBL_LOOK_ROLL).unwrap_or(0.0); + + let mut camera_rot = Vec3::ZERO; + camera_rot.y -= motion_x; + camera_rot.x -= motion_y; + camera_rot.z -= motion_z; + + if camera_rot != Vec3::ZERO { + let look_velocity = camera_rot * delta_time; + + let (mut y, mut x, _) = transform.rotation.to_euler(EulerRot::YXZ); + x += look_velocity.x; + y += look_velocity.y; + x = x.clamp(-1.54, 1.54); + + // rotation is not commutative, keep this order to avoid unintended roll + transform.rotation = Quat::from_axis_angle(Vec3::Y, y) + * Quat::from_axis_angle(Vec3::X, x); + } + } + + Ok(()) +} + +/// A plugin that adds the top down 2d camera controller system to the world. +/// +/// It is expected that there is a [`TopDown2dCamera`] in the world, if there isn't, +/// the camera would not move. +pub struct TopDown2dCameraPlugin; + +impl Plugin for TopDown2dCameraPlugin { + fn setup(&mut self, app: &mut App) { + app.with_system("top_down_2d_camera_system", top_down_2d_camera_controller, &[]); + } +} \ No newline at end of file diff --git a/examples/2d/src/main.rs b/examples/2d/src/main.rs index f10a04d..f610013 100644 --- a/examples/2d/src/main.rs +++ b/examples/2d/src/main.rs @@ -9,7 +9,7 @@ use lyra_engine::{ math::{self, Transform, Vec3}, render::light::directional::DirectionalLight, scene::{ - system_update_world_transforms, Camera2dBundle, CameraProjection, FreeFly3dCamera, FreeFlyCameraPlugin, OrthographicProjection, ScaleMode, WorldTransform, ACTLBL_LOOK_LEFT_RIGHT, ACTLBL_LOOK_ROLL, ACTLBL_LOOK_UP_DOWN, ACTLBL_MOVE_FORWARD_BACKWARD, ACTLBL_MOVE_LEFT_RIGHT, ACTLBL_MOVE_UP_DOWN + system_update_world_transforms, Camera2dBundle, CameraProjection, OrthographicProjection, ScaleMode, TopDown2dCamera, TopDown2dCameraPlugin, WorldTransform, ACTLBL_LOOK_LEFT_RIGHT, ACTLBL_LOOK_ROLL, ACTLBL_LOOK_UP_DOWN, ACTLBL_MOVE_FORWARD_BACKWARD, ACTLBL_MOVE_LEFT_RIGHT, ACTLBL_MOVE_UP_DOWN }, sprite::{self, Sprite}, }; @@ -90,7 +90,7 @@ async fn main() { .with_plugin(setup_scene_plugin) .with_plugin(action_handler_plugin) //.with_plugin(camera_debug_plugin) - .with_plugin(FreeFlyCameraPlugin) + .with_plugin(TopDown2dCameraPlugin) .with_system( "system_update_world_transforms", system_update_world_transforms, @@ -162,16 +162,15 @@ fn setup_scene_plugin(app: &mut App) { world.spawn(( Camera2dBundle { projection: CameraProjection::Orthographic(OrthographicProjection { - //scale_mode: ScaleMode::Width(960.0), scale_mode: ScaleMode::Height(180.0), - //scale_mode: ScaleMode::Width(320.0), - //scale_mode: ScaleMode::Size(lyra_engine::math::Vec2::new(320.0, 180.0)), ..Default::default() }), ..Default::default() }, - //Transform::from_xyz(200.0, 120.0, 0.0), Transform::from_xyz(0.0, 0.0, 0.0), - FreeFly3dCamera::default(), + TopDown2dCamera { + zoom_speed: Some(0.1), + ..Default::default() + } )); }