-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy path04_camera_controls.rs
161 lines (156 loc) · 6.31 KB
/
04_camera_controls.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
use geng::prelude::*;
struct State {
geng: Geng,
camera: geng::Camera2d, // Store camera in the game state
framebuffer_size: vec2<f32>, // Save framebuffer size to access it outside of draw call
drag_start: Option<vec2<f32>>, // Store location that needs to stay under cursor
prev_touch_distance: f32,
prev_touch_angle: Angle,
cursor_pos: Option<vec2<f64>>,
touches: Vec<geng::Touch>,
}
impl State {
fn new(geng: &Geng) -> Self {
Self {
geng: geng.clone(),
camera: geng::Camera2d {
center: vec2(0.0, 0.0),
rotation: Angle::ZERO,
fov: Camera2dFov::Vertical(15.0),
},
framebuffer_size: vec2(1.0, 1.0),
prev_touch_distance: 0.0,
prev_touch_angle: Angle::ZERO,
drag_start: None,
cursor_pos: None,
touches: vec![],
}
}
}
impl geng::State for State {
fn update(&mut self, delta_time: f64) {
let delta_time = delta_time as f32;
// Rotating camera
if self.geng.window().is_key_pressed(geng::Key::Q) {
self.camera.rotation -= Angle::from_radians(delta_time);
}
if self.geng.window().is_key_pressed(geng::Key::E) {
self.camera.rotation += Angle::from_radians(delta_time);
}
}
fn draw(&mut self, framebuffer: &mut ugli::Framebuffer) {
self.framebuffer_size = framebuffer.size().map(|x| x as f32); // Save framebuffer size
ugli::clear(framebuffer, Some(Rgba::BLACK), None, None);
self.geng.default_font().draw(
framebuffer,
&self.camera,
"Scroll to zoom\nDrag LMB to move\nQ/E to rotate",
vec2::splat(geng::TextAlign::CENTER),
mat3::identity(),
Rgba::WHITE,
);
}
fn handle_event(&mut self, event: geng::Event) {
match event {
geng::Event::KeyPress {
key: geng::Key::Space,
} => {
*self = Self::new(&self.geng);
}
// Scrolling to zoom
geng::Event::Wheel { delta } => {
let fov = self.camera.fov.value_mut();
*fov = (*fov * 1.01f32.powf(-delta as f32)).clamp(1.0, 30.0);
}
// Drag start
geng::Event::MousePress {
button: geng::MouseButton::Left,
} => {
if let Some(position) = self.cursor_pos {
self.drag_start = Some(
self.camera
.screen_to_world(self.framebuffer_size, position.map(|x| x as f32)),
);
}
}
// Drag move
geng::Event::CursorMove { position } => {
self.cursor_pos = Some(position);
if let Some(start) = self.drag_start {
// Find current world position under cursor
let current_pos = self
.camera
.screen_to_world(self.framebuffer_size, position.map(|x| x as f32));
// Move camera so that start position is now under cursor
self.camera.center += start - current_pos;
}
}
// Drag end
geng::Event::MouseRelease {
button: geng::MouseButton::Left,
} => self.drag_start = None,
geng::Event::TouchStart(touch) => {
self.touches.push(touch);
if self.touches.len() == 1 {
self.drag_start = Some(self.camera.screen_to_world(
self.framebuffer_size,
self.touches[0].position.map(|x| x as f32),
));
}
if self.touches.len() == 2 {
let diff = self.touches[0].position - self.touches[1].position;
self.prev_touch_distance = diff.len() as f32;
self.prev_touch_angle = diff.map(|x| x as f32).arg();
self.drag_start = Some(self.camera.screen_to_world(
self.framebuffer_size,
(self.touches[0].position + self.touches[1].position).map(|x| x as f32)
/ 2.0,
));
}
}
geng::Event::TouchMove(touch) => {
if let Some(t) = self.touches.iter_mut().find(|t| t.id == touch.id) {
*t = touch;
}
if self.touches.len() == 1 {
if let Some(start) = self.drag_start {
let current_pos = self.camera.screen_to_world(
self.framebuffer_size,
self.touches[0].position.map(|x| x as f32),
);
self.camera.center += start - current_pos;
}
} else if self.touches.len() == 2 {
let diff = self.touches[0].position - self.touches[1].position;
let now_dist = diff.len() as f32;
*self.camera.fov.value_mut() /= now_dist / self.prev_touch_distance;
self.prev_touch_distance = now_dist;
let now_angle = diff.map(|x| x as f32).arg();
let angle_diff = (now_angle - self.prev_touch_angle).normalized_pi();
self.camera.rotation += angle_diff;
self.prev_touch_angle = now_angle;
if let Some(start) = self.drag_start {
let current_pos = self.camera.screen_to_world(
self.framebuffer_size,
(self.touches[0].position + self.touches[1].position).map(|x| x as f32)
/ 2.0,
);
self.camera.center += start - current_pos;
}
}
}
geng::Event::TouchEnd(touch) => {
self.touches.retain(|t| t.id != touch.id);
self.drag_start = None;
}
_ => {}
}
}
}
fn main() {
logger::init();
geng::setup_panic_handler();
Geng::run("Moving", |geng| async move {
geng.run_state(State::new(&geng)).await;
});
}