bevy_orbit_controls/
lib.rs1use bevy::input::mouse::MouseMotion;
24use bevy::input::mouse::MouseScrollUnit::{Line, Pixel};
25use bevy::input::mouse::MouseWheel;
26use bevy::prelude::*;
27use bevy::render::camera::Camera;
28
29const LINE_TO_PIXEL_RATIO: f32 = 0.1;
30
31pub struct OrbitCamera {
32 pub x: f32,
33 pub y: f32,
34 pub distance: f32,
35 pub center: Vec3,
36 pub rotate_sensitivity: f32,
37 pub zoom_sensitivity: f32,
38}
39
40impl Default for OrbitCamera {
41 fn default() -> Self {
42 OrbitCamera {
43 x: 0.0,
44 y: 0.0,
45 distance: 5.0,
46 center: Vec3::ZERO,
47 rotate_sensitivity: 1.0,
48 zoom_sensitivity: 0.8,
49 }
50 }
51}
52
53impl OrbitCamera {
54 pub fn new(dist: f32, center: Vec3) -> OrbitCamera {
55 OrbitCamera {
56 x: 0.0,
57 y: 0.0,
58 distance: dist,
59 center,
60 rotate_sensitivity: 1.0,
61 zoom_sensitivity: 0.8,
62 }
63 }
64}
65
66pub struct OrbitCameraPlugin;
67impl OrbitCameraPlugin {
68 fn mouse_motion_system(
69 time: Res<Time>,
70 mut mouse_motion_events: EventReader<MouseMotion>,
71 mouse_button_input: Res<Input<MouseButton>>,
72 mut query: Query<(&mut OrbitCamera, &mut Transform, &mut Camera)>,
73 ) {
74 let mut delta = Vec2::ZERO;
75 for event in mouse_motion_events.iter() {
76 delta += event.delta;
77 }
78 for (mut camera, mut transform, _) in query.iter_mut() {
79 if mouse_button_input.pressed(MouseButton::Left) {
80 camera.x -= delta.x * camera.rotate_sensitivity * time.delta_seconds();
81 camera.y -= delta.y * camera.rotate_sensitivity * time.delta_seconds();
82
83 camera.y = camera.y.max(0.01).min(3.13);
84
85 let rot = Quat::from_axis_angle(Vec3::Y, camera.x)
86 * Quat::from_axis_angle(-Vec3::X, camera.y);
87 transform.translation =
88 (rot * Vec3::new(0.0, 1.0, 0.0)) * camera.distance + camera.center;
89 transform.look_at(camera.center, Vec3::Y);
90 }
91 }
92 }
93
94 fn zoom_system(
95 mut mouse_wheel_events: EventReader<MouseWheel>,
96 mut query: Query<(&mut OrbitCamera, &mut Transform, &mut Camera)>,
97 ) {
98 let mut total = 0.0;
99 for event in mouse_wheel_events.iter() {
100 total += event.y
101 * match event.unit {
102 Line => 1.0,
103 Pixel => LINE_TO_PIXEL_RATIO,
104 };
105 }
106 for (mut camera, mut transform, _) in query.iter_mut() {
107 camera.distance *= camera.zoom_sensitivity.powf(total);
108 let translation = &mut transform.translation;
109 *translation =
110 (*translation - camera.center).normalize() * camera.distance + camera.center;
111 }
112 }
113}
114impl Plugin for OrbitCameraPlugin {
115 fn build(&self, app: &mut AppBuilder) {
116 app
117 .add_system(Self::mouse_motion_system.system())
118 .add_system(Self::zoom_system.system());
119 }
120}