Touchpad-friendly controls (#2)

Adds `Shift` as an alternate modifier for FPS-style camera rotation, and binds
wheel events to camera zoom/dolly.

An attempt was made to translate 2D scroll events on a touchpad to camera
panning (this is what Blender does, and it's smooth as butter), but Bevy and/or
`winit` and/or the browser is doing some weird preprocessing of those events
before we're able to read them, which makes that unfeasible for now. That issue
has been documented with a `FIXME` comment.
This commit is contained in:
Danny McGee
2023-10-06 16:36:38 -04:00
committed by GitHub
parent 699c1baa4b
commit 57d64f08f0
+58 -2
View File
@@ -1,4 +1,8 @@
use bevy::{input::mouse::MouseMotion, prelude::*, utils::HashSet};
use bevy::{
input::mouse::{MouseMotion, MouseWheel},
prelude::*,
utils::HashSet,
};
pub struct StudioInputPlugin;
@@ -45,6 +49,7 @@ impl From<CameraMotion> for Action {
// TODO: Make the bindings of raw device inputs to InputActions configurable
fn translate_bevy_events(
mouse_motion: EventReader<MouseMotion>,
mut mouse_wheel: EventReader<MouseWheel>,
mouse_buttons: Res<Input<MouseButton>>,
keyboard: Res<Input<KeyCode>>,
mut input: EventWriter<InputAction>,
@@ -123,7 +128,25 @@ fn translate_bevy_events(
input.send(InputAction(
Lifecycle::Stop,
CameraMotion::Rotate(Vec2::ZERO).into(),
))
));
}
// Alt Camera Rotation (designed for laptop)
else if keyboard.pressed(KeyCode::ShiftLeft) {
let lifecycle = if keyboard.just_pressed(KeyCode::ShiftLeft) {
Lifecycle::Start
} else {
Lifecycle::Ongoing
};
let delta = read_mouse_delta(mouse_motion);
input.send(InputAction(lifecycle, CameraMotion::Rotate(delta).into()));
}
// Stop Camera Rotation
else if keyboard.just_released(KeyCode::ShiftLeft) {
input.send(InputAction(
Lifecycle::Stop,
CameraMotion::Rotate(Vec2::ZERO).into(),
));
}
// Camera Translation (FPS-like)
@@ -174,6 +197,39 @@ fn translate_bevy_events(
CameraMotion::Translate(Vec3::ZERO).into(),
));
}
// Wheel zoom
for &MouseWheel { y, .. } in mouse_wheel.iter() {
// info!("wheel: ({x}, {y}) [{unit:?}]");
// let rem_x = (100. / x).abs() % 1.;
// let rem_y = (100. / y).abs() % 1.;
// if (rem_x.is_nan() || rem_x < 1e-5_f32) && (rem_y.is_nan() || rem_y < 1e-5_f32) {
input.send(InputAction(
Lifecycle::Ongoing,
CameraMotion::Zoom(y).into(),
));
// } else {
// FIXME: I had high hopes for this, but the input translation from
// Bevy / winit is herky-jerky-janky af. It seems to be
// trying to force the wheel to only emit one axis at a time,
// unless the user makes a really deliberate diagonal motion
// to start. But even then, it makes bizarre jumps
// intermittently instead of just translating the input
// motion directly.
//
// I Was hoping to achieve something like what Blender does
// with touchpad input to pan, but it doesn't look like
// that's going to be possible without bypassing bevy::input
// and reading the system events directly. We may want to do
// that eventually, but not today.
// input.send(InputAction(
// Lifecycle::Ongoing,
// CameraMotion::Pan(vec2(x, y)).into(),
// ));
// }
}
}
#[inline]