Skip to main content

macroquad_ply/experimental/camera/
mouse.rs

1use crate::prelude::screen_width;
2use crate::prelude::*;
3use crate::Vec2;
4
5/// 2D camera that can be controlled by mouse. Offset and scale can be changed.
6///
7/// Note: You can get a [`Camera2D`] using `let cam2d: Camera2D = (&cam).into();
8#[derive(Debug, Copy, Clone)]
9pub struct Camera {
10    pub offset: Vec2,
11    pub scale: f32,
12
13    last_mouse_pos: Vec2,
14}
15
16impl Default for Camera {
17    fn default() -> Self {
18        Self::new(Vec2::ZERO, 1.0)
19    }
20}
21
22impl Camera {
23    pub const fn new(offset: Vec2, scale: f32) -> Self {
24        Self {
25            offset,
26            scale,
27
28            last_mouse_pos: Vec2::new(0., 0.),
29        }
30    }
31
32    /// If `wheel_value` has positive value, scale cam around point `center` by factor `scale_factor`.
33    /// If `wheel_value` is negative, then scale by `1.0/scale_factor`. If `wheel_value` equals `0.0` or `scale_factor` equals `1.0`, nothing happens.
34    pub fn scale_wheel(&mut self, center: Vec2, wheel_value: f32, scale_factor: f32) {
35        if wheel_value > 0. {
36            self.scale_mul(center, scale_factor);
37        } else if wheel_value < 0. {
38            self.scale_mul(center, 1.0 / scale_factor);
39        }
40    }
41
42    /// Adds `mul_to_scale` to current scale of cam. Scale is changed around point `center`.
43    pub fn scale_mul(&mut self, center: Vec2, mul_to_scale: f32) {
44        self.scale_new(center, self.scale * mul_to_scale);
45    }
46
47    /// Replace current scale of camera with `new_scale`. Scale is changed around point `center`.
48    pub fn scale_new(&mut self, center: Vec2, new_scale: f32) {
49        self.offset = (self.offset - center) * (new_scale / self.scale) + center;
50        self.scale = new_scale;
51    }
52
53    /// Update camera position by new mouse position. This method must be run at every frame. `should_offset` controls if the camera should actually move or not.
54    ///
55    /// Note: It's better to use [`mouse_position_local`] with this method, otherwise if you use [`mouse_position`] the movement is way too big.
56    pub fn update(&mut self, mouse_pos: Vec2, should_offset: bool) {
57        if should_offset {
58            self.offset += mouse_pos - self.last_mouse_pos;
59        }
60        self.last_mouse_pos = mouse_pos;
61    }
62}
63
64impl From<&Camera> for Camera2D {
65    fn from(val: &Camera) -> Self {
66        let aspect = screen_width() / screen_height();
67        Camera2D {
68            zoom: vec2(val.scale, -val.scale * aspect),
69            offset: vec2(val.offset.x, -val.offset.y),
70            target: vec2(0., 0.),
71            rotation: 0.,
72
73            render_target: None,
74            viewport: None,
75        }
76    }
77}