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 bevy::prelude::*;
|
||||||
|
use crate::camera::GameCameraPlugin;
|
||||||
use crate::grid::Grid;
|
use crate::grid::Grid;
|
||||||
use crate::simulation::SimulationPlugin;
|
use crate::simulation::SimulationPlugin;
|
||||||
|
|
||||||
|
|
@ -7,12 +8,12 @@ use crate::view::ViewPlugin;
|
||||||
pub mod simulation;
|
pub mod simulation;
|
||||||
pub mod view;
|
pub mod view;
|
||||||
pub mod grid;
|
pub mod grid;
|
||||||
|
pub mod camera;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
.add_plugins(ViewPlugin)
|
.add_plugins((ViewPlugin,SimulationPlugin,GameCameraPlugin))
|
||||||
.add_plugins(SimulationPlugin)
|
|
||||||
.insert_resource(Grid::cube(16))
|
.insert_resource(Grid::cube(16))
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ impl Plugin for GameViewPlugin {
|
||||||
app.add_systems(PreStartup, debug_setup_grid)
|
app.add_systems(PreStartup, debug_setup_grid)
|
||||||
.init_resource::<CubeStages>()
|
.init_resource::<CubeStages>()
|
||||||
.init_resource::<TileMaterials>()
|
.init_resource::<TileMaterials>()
|
||||||
.add_systems(Startup, (setup_view_cubes, scene.spawn()))
|
.add_systems(Startup, setup_view_cubes)
|
||||||
.add_systems(Update, update_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 {
|
pub fn cube(position: Vec3,index: usize,mesh: Handle<Mesh>) -> impl Scene {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue