Merge pull request #37 from kristoferssolo/feature/camera

This commit is contained in:
Kristofers Solo 2025-01-17 12:12:51 +02:00 committed by GitHub
commit 48a39d4430
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 73 additions and 15 deletions

64
src/camera.rs Normal file
View File

@ -0,0 +1,64 @@
use bevy::{input::mouse::MouseWheel, prelude::*};
use crate::constants::{BASE_ZOOM_SPEED, DISTANCE_SCALE_FACTOR, MAX_ZOOM, MIN_ZOOM};
pub(super) fn plugin(app: &mut App) {
app.add_systems(Update, camera_zoom);
}
#[derive(Debug, Reflect, Component)]
#[reflect(Component)]
pub struct MainCamera;
pub fn spawn_camera(mut commands: Commands) {
commands.spawn((
Name::new("Camera"),
MainCamera,
Camera3d::default(),
Transform::from_xyz(200., 200., 0.).looking_at(Vec3::ZERO, Vec3::Y),
// Render all UI to this camera.
// Not strictly necessary since we only use one camera,
// but if we don't use this component, our UI will disappear as soon
// as we add another camera. This includes indirect ways of adding cameras like using
// [ui node outlines](https://bevyengine.org/news/bevy-0-14/#ui-node-outline-gizmos)
// for debugging. So it's good to have this here for future-proofing.
IsDefaultUiCamera,
));
}
fn camera_zoom(
mut query: Query<&mut Transform, With<MainCamera>>,
mut scrool_evr: EventReader<MouseWheel>,
keyboard: Res<ButtonInput<KeyCode>>,
time: Res<Time>,
) {
let Ok(mut transform) = query.get_single_mut() else {
return;
};
let current_distance = transform.translation.length();
// Calculate zoom speed based on distance
let distance_multiplier = (current_distance / MIN_ZOOM).powf(DISTANCE_SCALE_FACTOR);
let adjusted_zoom_speed = BASE_ZOOM_SPEED * distance_multiplier;
let mut zoom_delta = 0.0;
if keyboard.pressed(KeyCode::Equal) || keyboard.pressed(KeyCode::NumpadAdd) {
zoom_delta += adjusted_zoom_speed * time.delta_secs() * 25.;
}
if keyboard.pressed(KeyCode::Minus) || keyboard.pressed(KeyCode::NumpadSubtract) {
zoom_delta -= adjusted_zoom_speed * time.delta_secs() * 25.;
}
for ev in scrool_evr.read() {
zoom_delta += ev.y * adjusted_zoom_speed;
}
if zoom_delta != 0.0 {
let forward = transform.translation.normalize();
let new_distance = (current_distance - zoom_delta).clamp(MIN_ZOOM, MAX_ZOOM);
transform.translation = forward * new_distance;
}
}

View File

@ -12,3 +12,9 @@ pub const BASE_TIME_SCORE: usize = 100;
pub const FLOOR_DIFFICULTY_MULTIPLIER: f32 = 1.2; // Higher floors are exponentially harder pub const FLOOR_DIFFICULTY_MULTIPLIER: f32 = 1.2; // Higher floors are exponentially harder
pub const MIN_TIME_MULTIPLIER: f32 = 0.1; // Minimum score multiplier for time pub const MIN_TIME_MULTIPLIER: f32 = 0.1; // Minimum score multiplier for time
pub const TIME_REFERENCE_SECONDS: f32 = 60.0; // Reference time for score calculation pub const TIME_REFERENCE_SECONDS: f32 = 60.0; // Reference time for score calculation
// Constants for camera control
pub const BASE_ZOOM_SPEED: f32 = 10.0;
pub const MIN_ZOOM: f32 = 50.0;
pub const MAX_ZOOM: f32 = 2500.0;
pub const DISTANCE_SCALE_FACTOR: f32 = 0.5; // Adjust this to control how much distance affects zoom speed

View File

@ -1,5 +1,6 @@
pub mod asset_tracking; pub mod asset_tracking;
pub mod audio; pub mod audio;
pub mod camera;
pub mod constants; pub mod constants;
#[cfg(feature = "dev")] #[cfg(feature = "dev")]
pub mod dev_tools; pub mod dev_tools;
@ -16,6 +17,7 @@ use bevy::{
audio::{AudioPlugin, Volume}, audio::{AudioPlugin, Volume},
prelude::*, prelude::*,
}; };
use camera::spawn_camera;
use constants::TITLE; use constants::TITLE;
use theme::{palette::rose_pine, prelude::ColorScheme}; use theme::{palette::rose_pine, prelude::ColorScheme};
@ -71,6 +73,7 @@ impl Plugin for AppPlugin {
player::plugin, player::plugin,
hint::plugin, hint::plugin,
stats::plugin, stats::plugin,
camera::plugin,
)); ));
// Enable dev tools for dev builds. // Enable dev tools for dev builds.
@ -92,21 +95,6 @@ enum AppSet {
Update, Update,
} }
fn spawn_camera(mut commands: Commands) {
commands.spawn((
Name::new("Camera"),
Camera3d::default(),
Transform::from_xyz(200., 200., 0.).looking_at(Vec3::ZERO, Vec3::Y),
// Render all UI to this camera.
// Not strictly necessary since we only use one camera,
// but if we don't use this component, our UI will disappear as soon
// as we add another camera. This includes indirect ways of adding cameras like using
// [ui node outlines](https://bevyengine.org/news/bevy-0-14/#ui-node-outline-gizmos)
// for debugging. So it's good to have this here for future-proofing.
IsDefaultUiCamera,
));
}
fn load_background(mut commands: Commands) { fn load_background(mut commands: Commands) {
let colorcheme = rose_pine::RosePineDawn::Base; let colorcheme = rose_pine::RosePineDawn::Base;
commands.insert_resource(ClearColor(colorcheme.to_color())); commands.insert_resource(ClearColor(colorcheme.to_color()));