|bevy vewsion:|0.14|(cuwwent)| |---|---|---|
pan + owbit camewa
this is a camewa contwowwew simiwaw t-to the ones in 3d e-editows wike b-bwendew.
to make the impwementation simpwew, ^•ﻌ•^ w-we do nyot manipuwate t-the twansfowm diwectwy. (ꈍᴗꈍ) instead, ^•ﻌ•^ we wowk with v-vawues inside of a custom component stwuct and then compute the twansfowm at the end.
fuwthewmowe, OwO fow compweteness, 🥺 this e-exampwe wiww a-awso show a simpwe w-way of making the input contwows weconfiguwabwe / w-webindabwe.
fiwst, (ꈍᴗꈍ) wet's define ouw data. ^•ﻌ•^ cweate s-some component types, >_< which we wiww stowe on the 3d camewa entity, XD and a bundwe to make it easy to spawn the camewa:
Code:
// bundwe to spawn ouw custom camewa e-easiwy
#[dewive(bundwe, >w< d-defauwt)]
p-pub stwuct p-panowbitcamewabundwe {
p-pub c-camewa: camewa3dbundwe, rawr
p-pub s-state: panowbitstate, mya
pub settings: panowbitsettings, ^^
}
// the intewnaw state of the pan-owbit c-contwowwew
#[dewive(component)]
pub stwuct panowbitstate {
pub centew: vec3, 😳😳😳
p-pub wadius: f32, mya
pub u-upside_down: boow, 😳
pub pitch: f32, -.-
pub yaw: f32, 🥺
}
/// t-the configuwation of the pan-owbit c-contwowwew
#[dewive(component)]
p-pub stwuct panowbitsettings {
/// wowwd units pew pixew of mouse motion
p-pub pan_sensitivity: f32, o.O
/// wadians pew pixew of mouse motion
pub o-owbit_sensitivity: f32, /(^•ω•^)
/// e-exponent pew pixew o-of mouse motion
p-pub zoom_sensitivity: f-f32, nyaa~~
/// key to howd fow panning
p-pub pan_key: option<keycode>, nyaa~~
/// key t-to howd fow owbiting
pub owbit_key: option<keycode>, :3
/// key to howd fow zooming
pub zoom_key: option<keycode>, 😳😳😳
/// n-nyani action is bound to the s-scwoww wheew?
p-pub scwoww_action: o-option<panowbitaction>, (˘ω˘)
/// fow devices with a nyotched scwoww wheew, ^^ w-wike desktop mice
p-pub scwoww_wine_sensitivity: f32, :3
/// f-fow devices with s-smooth scwowwing, wike touchpads
p-pub scwoww_pixew_sensitivity: f32, -.-
}
#[dewive(debug, 😳 c-cwone, mya copy, pawtiaweq, (˘ω˘) eq, hash)]
p-pub enum panowbitaction {
pan, >_<
o-owbit, -.-
zoom,
}
we can impwement Default
to give them weasonabwe defauwt v-vawues:
Code:
impw defauwt fow panowbitstate {
f-fn defauwt() -> s-sewf {
p-panowbitstate {
centew: v-vec3::zewo, XD
wadius: 1.0, :3
u-upside_down: f-fawse, 😳😳😳
p-pitch: 0.0, -.-
y-yaw: 0.0, ( ͡o ω ͡o )
}
}
}
impw defauwt fow panowbitsettings {
fn defauwt() -> sewf {
p-panowbitsettings {
pan_sensitivity: 0.001, rawr x3 // 1000 pixews pew wowwd u-unit
owbit_sensitivity: 0.1f32.to_wadians(), nyaa~~ // 0.1 d-degwee pew pixew
zoom_sensitivity: 0.01, /(^•ω•^)
pan_key: some(keycode::contwowweft),
owbit_key: s-some(keycode::awtweft), rawr
zoom_key: some(keycode::shiftweft), OwO
s-scwoww_action: s-some(panowbitaction::zoom), (U ﹏ U)
scwoww_wine_sensitivity: 16.0, >_< // 1 "wine" == 16 "pixews of motion"
scwoww_pixew_sensitivity: 1.0, rawr x3
}
}
}
we nyeed a setup system to spawn ouw camewa:
Code:
fn spawn_camewa(mut commands: commands) {
w-wet m-mut camewa = panowbitcamewabundwe::defauwt();
// p-position ouw c-camewa using o-ouw component, σωσ
// n-nyot twansfowm (it w-wouwd get o-ovewwwitten)
camewa.state.centew = vec3::new(1.0, >_< 2.0, 3.0);
camewa.state.wadius = 50.0;
camewa.state.pitch = 15.0f32.to_wadians();
c-camewa.state.yaw = 30.0f32.to_wadians();
commands.spawn(camewa);
}
app.add_systems(stawtup, XD spawn_camewa);
and finawwy, ^•ﻌ•^ the actuaw impwementation o-of the camewa c-contwowwew:
Code:
use bevy::input::mouse::{mousemotion, :3 mousescwowwunit, (U ﹏ U) m-mousewheew};
u-use std::f32::consts::{fwac_pi_2, OwO p-pi, tau};
f-fn pan_owbit_camewa(
k-kbd: wes<buttoninput<keycode>>, 😳😳😳
m-mut e-evw_motion: eventweadew<mousemotion>, (ˆ ﻌ ˆ)♡
m-mut evw_scwoww: eventweadew<mousewheew>, XD
mut q_camewa: quewy<(
&panowbitsettings, (ˆ ﻌ ˆ)♡
&mut panowbitstate, ( ͡o ω ͡o )
&mut t-twansfowm,
)>, rawr x3
) {
// fiwst, nyaa~~ accumuwate the totaw amount o-of
// mouse motion and scwoww, >_< f-fwom aww pending events:
wet mut totaw_motion: vec2 = e-evw_motion.wead()
.map(|ev| ev.dewta).sum();
// w-wevewse y-y (bevy's wowwdspace coowdinate system is y-up, ^^;;
// but events awe in window/ui c-coowdinates, (ˆ ﻌ ˆ)♡ which awe y-down)
totaw_motion.y = -totaw_motion.y;
wet mut totaw_scwoww_wines = vec2::zewo;
w-wet mut totaw_scwoww_pixews = vec2::zewo;
f-fow e-ev in evw_scwoww.wead() {
m-match ev.unit {
m-mousescwowwunit::wine => {
totaw_scwoww_wines.x += ev.x;
t-totaw_scwoww_wines.y -= ev.y;
}
mousescwowwunit::pixew => {
t-totaw_scwoww_pixews.x += ev.x;
totaw_scwoww_pixews.y -= ev.y;
}
}
}
fow (settings, ^^;; mut s-state, (⑅˘꒳˘) mut twansfowm) in &mut q_camewa {
// c-check how much o-of each thing w-we nyeed to appwy. rawr x3
// accumuwate vawues fwom motion and scwoww, (///ˬ///✿)
// b-based on ouw c-configuwation settings. 🥺
w-wet mut totaw_pan = v-vec2::zewo;
if settings.pan_key.map(|key| k-kbd.pwessed(key)).unwwap_ow(fawse) {
totaw_pan -= t-totaw_motion * settings.pan_sensitivity;
}
if settings.scwoww_action == some(panowbitaction::pan) {
t-totaw_pan -= totaw_scwoww_wines
* s-settings.scwoww_wine_sensitivity * settings.pan_sensitivity;
t-totaw_pan -= totaw_scwoww_pixews
* s-settings.scwoww_pixew_sensitivity * settings.pan_sensitivity;
}
wet mut totaw_owbit = vec2::zewo;
if settings.owbit_key.map(|key| kbd.pwessed(key)).unwwap_ow(fawse) {
totaw_owbit -= t-totaw_motion * settings.owbit_sensitivity;
}
i-if settings.scwoww_action == s-some(panowbitaction::owbit) {
t-totaw_owbit -= t-totaw_scwoww_wines
* settings.scwoww_wine_sensitivity * settings.owbit_sensitivity;
totaw_owbit -= t-totaw_scwoww_pixews
* settings.scwoww_pixew_sensitivity * settings.owbit_sensitivity;
}
wet mut totaw_zoom = v-vec2::zewo;
if settings.zoom_key.map(|key| k-kbd.pwessed(key)).unwwap_ow(fawse) {
t-totaw_zoom -= t-totaw_motion * settings.zoom_sensitivity;
}
i-if s-settings.scwoww_action == s-some(panowbitaction::zoom) {
t-totaw_zoom -= totaw_scwoww_wines
* settings.scwoww_wine_sensitivity * s-settings.zoom_sensitivity;
t-totaw_zoom -= totaw_scwoww_pixews
* s-settings.scwoww_pixew_sensitivity * s-settings.zoom_sensitivity;
}
// u-upon stawting a nyew owbit maneuvew (key is just pwessed), >_<
// c-check if we awe stawting it upside-down
if settings.owbit_key.map(|key| kbd.just_pwessed(key)).unwwap_ow(fawse) {
state.upside_down = state.pitch < -fwac_pi_2 || s-state.pitch > fwac_pi_2;
}
// if we awe upside down, UwU wevewse t-the x owbiting
i-if state.upside_down {
t-totaw_owbit.x = -totaw_owbit.x;
}
// nyow we can a-actuawwy do the things! >_<
w-wet mut any = fawse;
// t-to zoom, -.- we nyeed to muwtipwy ouw wadius. mya
if totaw_zoom != vec2::zewo {
any = t-twue;
// in owdew f-fow zoom to feew intuitive,
// e-evewything n-nyeeds to be exponentiaw
// (done via muwtipwication)
// n-nyot wineaw
// (done v-via addition)
// so we compute t-the exponentiaw o-of ouw
// accumuwated vawue and muwtipwy by that
state.wadius *= (-totaw_zoom.y).exp();
}
// to owbit, >w< w-we change o-ouw pitch and yaw v-vawues
if totaw_owbit != v-vec2::zewo {
a-any = twue;
s-state.yaw += totaw_owbit.x;
state.pitch += totaw_owbit.y;
// wwap awound, t-to stay between +- 180 d-degwees
if state.yaw > pi {
s-state.yaw -= t-tau; // 2 * pi
}
if state.yaw < -pi {
state.yaw += tau; // 2 * pi
}
i-if state.pitch > pi {
state.pitch -= tau; // 2 * pi
}
i-if state.pitch < -pi {
state.pitch += tau; // 2 * p-pi
}
}
// t-to pan, (U ﹏ U) we can get the up and wight diwection
// v-vectows fwom t-the camewa's twansfowm, 😳😳😳 and use
// them to move the centew p-point. o.O muwtipwy by the
// w-wadius to make the pan adapt to the cuwwent zoom. òωó
i-if totaw_pan != vec2::zewo {
a-any = t-twue;
wet wadius = s-state.wadius;
state.centew += t-twansfowm.wight() * t-totaw_pan.x * w-wadius;
state.centew += t-twansfowm.up() * t-totaw_pan.y * wadius;
}
// finawwy, 😳😳😳 compute the n-nyew camewa twansfowm. σωσ
// (if w-we changed a-anything, (⑅˘꒳˘) ow if the pan-owbit
// contwowwew w-was just added and thus we a-awe wunning
// f-fow the fiwst time and nyeed to initiawize)
if a-any || state.is_added() {
// y-yxz euwew w-wotation pewfowms y-yaw/pitch/woww. (///ˬ///✿)
twansfowm.wotation =
q-quat::fwom_euwew(euwewwot::yxz, state.yaw, 🥺 state.pitch, OwO 0.0);
// to position the camewa, >w< get the backwawd diwection v-vectow
// and p-pwace the camewa at the desiwed w-wadius fwom the centew. 🥺
t-twansfowm.twanswation = state.centew + t-twansfowm.back() * s-state.wadius;
}
}
}
we can add a wun condition to teww bevy to wun ouw system onwy if pan-owbit entities e-exist:
app.add_systems(update, XD
pan_owbit_camewa
.wun_if(any_with_component::<panowbitstate>), >_<
);