Editor fly camera
parent
4bc704aff0
commit
63fab851ac
@ -0,0 +1,127 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
/// Menu Plugin; empty struct for Plugin impl
|
||||
pub(crate) struct CameraPlugin;
|
||||
|
||||
impl Plugin for CameraPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_systems(
|
||||
Update,
|
||||
move_editor_fly_camera.run_if(any_with_component::<FlyCamera>),
|
||||
);
|
||||
app.add_systems(
|
||||
Update,
|
||||
rotate_editor_fly_camera.run_if(any_with_component::<FlyCamera>),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
pub(crate) struct FlyCamera;
|
||||
|
||||
/// Fly camera system for moving around like a drone
|
||||
/// TODO: Only if key is pressed!
|
||||
fn move_editor_fly_camera(
|
||||
mut cameras: Query<(&Camera, &mut Transform), With<FlyCamera>>,
|
||||
windows: Query<&Window>,
|
||||
primary_window: Query<Entity, With<PrimaryWindow>>,
|
||||
keys: Res<ButtonInput<KeyCode>>,
|
||||
time: Res<Time>,
|
||||
) {
|
||||
(keys.any_pressed([
|
||||
KeyCode::KeyW,
|
||||
KeyCode::KeyS,
|
||||
KeyCode::KeyA,
|
||||
KeyCode::KeyD,
|
||||
KeyCode::KeyQ,
|
||||
KeyCode::KeyE,
|
||||
]))
|
||||
.then(|| {
|
||||
// Iterate over all cameras
|
||||
cameras.iter_mut().for_each(|(c, mut t)| {
|
||||
// Determine which window this camera is attached to
|
||||
let target_window = match c.target {
|
||||
RenderTarget::Window(wr) => match wr {
|
||||
WindowRef::Entity(e) => Some(e),
|
||||
WindowRef::Primary => Some(primary_window.get_single().unwrap()),
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
let window = windows.get(target_window.unwrap()).unwrap();
|
||||
|
||||
// If the target window is focused
|
||||
window.focused.then(|| {
|
||||
let move_speed = if keys.pressed(KeyCode::ShiftLeft) {
|
||||
16.0
|
||||
} else {
|
||||
4.0
|
||||
};
|
||||
let mut delta = Vec3::ZERO;
|
||||
if keys.pressed(KeyCode::KeyW) {
|
||||
delta += t.forward() * move_speed * time.delta_seconds()
|
||||
}
|
||||
if keys.pressed(KeyCode::KeyS) {
|
||||
delta += t.back() * move_speed * time.delta_seconds()
|
||||
}
|
||||
if keys.pressed(KeyCode::KeyA) {
|
||||
delta += t.left() * move_speed * time.delta_seconds()
|
||||
}
|
||||
if keys.pressed(KeyCode::KeyD) {
|
||||
delta += t.right() * move_speed * time.delta_seconds()
|
||||
}
|
||||
if keys.pressed(KeyCode::KeyE) {
|
||||
delta += Vec3::Y * move_speed * time.delta_seconds()
|
||||
}
|
||||
if keys.pressed(KeyCode::KeyQ) {
|
||||
delta += Vec3::NEG_Y * move_speed * time.delta_seconds()
|
||||
}
|
||||
t.translation += delta;
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn rotate_editor_fly_camera(
|
||||
mut cameras: Query<(&Camera, &mut Transform), With<FlyCamera>>,
|
||||
windows: Query<&Window>,
|
||||
primary_window: Query<Entity, With<PrimaryWindow>>,
|
||||
mouse: Res<ButtonInput<MouseButton>>,
|
||||
mut cursor_events: EventReader<CursorMoved>,
|
||||
) {
|
||||
(cursor_events.len() > 0).then(|| {
|
||||
// Iterate over all cameras
|
||||
cameras.iter_mut().for_each(|(c, mut t)| {
|
||||
// Determine which window this camera is attached to
|
||||
let target_window = match c.target {
|
||||
RenderTarget::Window(wr) => match wr {
|
||||
WindowRef::Entity(e) => Some(e),
|
||||
WindowRef::Primary => Some(primary_window.get_single().unwrap()),
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
let window = windows.get(target_window.unwrap()).unwrap();
|
||||
if mouse.pressed(MouseButton::Middle) {
|
||||
cursor_events
|
||||
.read()
|
||||
.filter_map(|CursorMoved { delta, window, .. }| {
|
||||
(*window == target_window.unwrap()).then_some(delta)
|
||||
})
|
||||
.for_each(|delta| {
|
||||
if let Some(Vec2 { x, y }) = delta {
|
||||
// Cribbing from bevy_flycam
|
||||
// Link: https://github.com/sburris0/bevy_flycam/blob/baffe50e0961ad1491d467fa6ab5551f9f21db8f/src/lib.rs#L145-L151
|
||||
let (mut yaw, mut pitch, _) = t.rotation.to_euler(EulerRot::YXZ);
|
||||
let window_scale = window.height().min(window.width());
|
||||
let sensitivity = 0.00012;
|
||||
pitch -= (sensitivity * y * window_scale).to_radians();
|
||||
yaw -= (sensitivity * x * window_scale).to_radians();
|
||||
t.rotation = Quat::from_axis_angle(Vec3::Y, yaw)
|
||||
* Quat::from_axis_angle(Vec3::X, pitch);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
cursor_events.clear();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -1,5 +1,8 @@
|
||||
use bevy::prelude::*;
|
||||
|
||||
pub(crate) fn any_component_added<T: Component>(q: Query<Entity, Added<T>>) -> bool {
|
||||
///
|
||||
/// ECS scheduler active when an entity has a given component added
|
||||
///
|
||||
pub(crate) fn any_component_added<C: Component>(q: Query<Entity, Added<C>>) -> bool {
|
||||
!q.is_empty()
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue