feat: Camera control
This commit is contained in:
parent
dea1b8599a
commit
8373b10ac1
3 changed files with 112 additions and 35 deletions
108
src/camera.rs
Normal file
108
src/camera.rs
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
use bevy::{input::mouse::{AccumulatedMouseMotion, AccumulatedMouseScroll}, prelude::*};
|
||||
use crate::grid::Grid;
|
||||
use std::{f32::consts::FRAC_PI_2,ops::Range};
|
||||
|
||||
pub struct GameCameraPlugin;
|
||||
|
||||
impl Plugin for GameCameraPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_systems(Startup, scene.spawn())
|
||||
.add_systems(Update, orbit);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Component)]
|
||||
pub struct CameraOrbit {
|
||||
pub distance: f32,
|
||||
pub pitch_speed: f32,
|
||||
pub pitch_range: Range<f32>,
|
||||
pub yaw_speed: f32,
|
||||
pub center_offset: Vec3,
|
||||
pub vertical_offset_speed: f32,
|
||||
pub horizontal_offset_speed: f32,
|
||||
}
|
||||
|
||||
impl Default for CameraOrbit {
|
||||
fn default() -> Self {
|
||||
let limit = FRAC_PI_2 - 0.01;
|
||||
Self {
|
||||
distance: 20.,
|
||||
yaw_speed: 0.004,
|
||||
pitch_speed: 0.004,
|
||||
pitch_range: -limit..limit,
|
||||
center_offset: Vec3::ZERO,
|
||||
vertical_offset_speed: 0.05,
|
||||
horizontal_offset_speed: 0.05,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scene() -> impl SceneList {
|
||||
bsn_list![
|
||||
camera(),
|
||||
sun()
|
||||
]
|
||||
}
|
||||
|
||||
pub fn camera() -> impl Scene {
|
||||
bsn! {
|
||||
Camera3d
|
||||
template(
|
||||
|ctx| {
|
||||
let grid = ctx.resource::<Grid>();
|
||||
let center = grid.size.as_vec3() * 0.5;
|
||||
Ok(Transform::from_xyz(
|
||||
center.x + grid.size.x as f32 * 1.2,
|
||||
grid.size.y as f32 * 1.2,
|
||||
center.z + grid.size.z as f32 * 1.2).looking_at(center, Vec3::Y))
|
||||
}
|
||||
)
|
||||
CameraOrbit
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sun() -> impl Scene {
|
||||
bsn!{
|
||||
DirectionalLight {
|
||||
illuminance: 8_000.0,
|
||||
shadow_maps_enabled: false,
|
||||
}
|
||||
template_value(Transform::from_xyz(10.0, 30.0, 10.0).looking_at(Vec3::ZERO, Vec3::Y))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn orbit(
|
||||
camera: Single<(&mut Transform,&mut CameraOrbit)>,
|
||||
mouse_buttons: Res<ButtonInput<MouseButton>>,
|
||||
mouse_motion: Res<AccumulatedMouseMotion>,
|
||||
mouse_scroll: Res<AccumulatedMouseScroll>,
|
||||
grid: Res<Grid>) {
|
||||
|
||||
let (mut transform, mut orbit) = camera.into_inner();
|
||||
|
||||
if mouse_buttons.pressed(MouseButton::Right) {
|
||||
let delta = mouse_motion.delta;
|
||||
let (yaw, pitch, roll) = transform.rotation.to_euler(EulerRot::YXZ);
|
||||
|
||||
let pitch = (pitch - delta.y * orbit.pitch_speed).clamp(orbit.pitch_range.start, orbit.pitch_range.end);
|
||||
let yaw = yaw - delta.x * orbit.yaw_speed;
|
||||
|
||||
transform.rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch, roll);
|
||||
}
|
||||
if mouse_buttons.pressed(MouseButton::Middle) {
|
||||
let delta = mouse_motion.delta;
|
||||
|
||||
let new_offset = transform.up() * delta.y * orbit.vertical_offset_speed - transform.right() * delta.x * orbit.horizontal_offset_speed;
|
||||
orbit.center_offset += new_offset;
|
||||
}
|
||||
|
||||
let center = grid.size.as_vec3() * 0.5;
|
||||
let min_distance = vec3(
|
||||
center.x + grid.size.x as f32 * 1.2,
|
||||
grid.size.y as f32 * 1.2,
|
||||
center.z + grid.size.z as f32 * 1.2).length();
|
||||
|
||||
orbit.distance = (orbit.distance-mouse_scroll.delta.y).max(min_distance);
|
||||
|
||||
transform.translation = center + orbit.center_offset -transform.forward() * orbit.distance;
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
use bevy::prelude::*;
|
||||
use crate::camera::GameCameraPlugin;
|
||||
use crate::grid::Grid;
|
||||
use crate::simulation::SimulationPlugin;
|
||||
|
||||
|
|
@ -7,12 +8,12 @@ use crate::view::ViewPlugin;
|
|||
pub mod simulation;
|
||||
pub mod view;
|
||||
pub mod grid;
|
||||
pub mod camera;
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_plugins(ViewPlugin)
|
||||
.add_plugins(SimulationPlugin)
|
||||
.add_plugins((ViewPlugin,SimulationPlugin,GameCameraPlugin))
|
||||
.insert_resource(Grid::cube(16))
|
||||
.run();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ impl Plugin for GameViewPlugin {
|
|||
app.add_systems(PreStartup, debug_setup_grid)
|
||||
.init_resource::<CubeStages>()
|
||||
.init_resource::<TileMaterials>()
|
||||
.add_systems(Startup, (setup_view_cubes, scene.spawn()))
|
||||
.add_systems(Startup, setup_view_cubes)
|
||||
.add_systems(Update, update_cubes);
|
||||
}
|
||||
}
|
||||
|
|
@ -84,38 +84,6 @@ pub fn setup_view_cubes(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn scene() -> impl SceneList {
|
||||
bsn_list![
|
||||
camera(),
|
||||
sun()
|
||||
]
|
||||
}
|
||||
|
||||
pub fn camera() -> impl Scene {
|
||||
bsn! {
|
||||
Camera3d
|
||||
template(
|
||||
|ctx| {
|
||||
let grid = ctx.resource::<Grid>();
|
||||
let center = grid.size.as_vec3() * 0.5;
|
||||
Ok(Transform::from_xyz(
|
||||
center.x + grid.size.x as f32 * 1.5,
|
||||
grid.size.y as f32 * 1.5,
|
||||
center.z + grid.size.z as f32 * 1.5).looking_at(center, Vec3::Y))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sun() -> impl Scene {
|
||||
bsn!{
|
||||
DirectionalLight {
|
||||
illuminance: 8_000.0,
|
||||
shadow_maps_enabled: false,
|
||||
}
|
||||
template_value(Transform::from_xyz(10.0, 30.0, 10.0).looking_at(Vec3::ZERO, Vec3::Y))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn cube(position: Vec3,index: usize,mesh: Handle<Mesh>) -> impl Scene {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue