2025-11-28 20:39:09 +00:00
|
|
|
use macroquad::prelude::*;
|
|
|
|
|
|
|
|
|
|
const MOVE_SPEED: f32 = 1.0;
|
2025-12-09 15:47:53 +00:00
|
|
|
const LOOK_SPEED: f32 = 0.01;
|
2025-11-28 20:39:09 +00:00
|
|
|
|
|
|
|
|
pub struct FirstPersonCamera {
|
|
|
|
|
pub position: Vec3,
|
|
|
|
|
yaw: f32,
|
|
|
|
|
pitch: f32,
|
|
|
|
|
|
|
|
|
|
pub front: Vec3,
|
|
|
|
|
pub right: Vec3,
|
|
|
|
|
pub up: Vec3,
|
|
|
|
|
world_up: Vec3,
|
|
|
|
|
|
|
|
|
|
grabbed: bool,
|
|
|
|
|
last_mouse: Vec2,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl FirstPersonCamera {
|
|
|
|
|
pub fn new(position: Vec3) -> Self {
|
2025-12-08 21:18:04 +00:00
|
|
|
let yaw: f32 = 0.0;
|
|
|
|
|
let pitch: f32 = -0.25;
|
2025-11-28 20:39:09 +00:00
|
|
|
let world_up = vec3(0.0, 1.0, 0.0);
|
|
|
|
|
|
|
|
|
|
let front = vec3(
|
|
|
|
|
yaw.cos() * pitch.cos(),
|
|
|
|
|
pitch.sin(),
|
|
|
|
|
yaw.sin() * pitch.cos(),
|
|
|
|
|
)
|
|
|
|
|
.normalize();
|
|
|
|
|
|
|
|
|
|
let right = front.cross(world_up).normalize();
|
|
|
|
|
let up = right.cross(front).normalize();
|
|
|
|
|
|
|
|
|
|
let grabbed = true;
|
|
|
|
|
set_cursor_grab(grabbed);
|
|
|
|
|
show_mouse(!grabbed);
|
|
|
|
|
|
|
|
|
|
Self {
|
|
|
|
|
position,
|
|
|
|
|
yaw,
|
|
|
|
|
pitch,
|
|
|
|
|
front,
|
|
|
|
|
right,
|
|
|
|
|
up,
|
|
|
|
|
world_up,
|
|
|
|
|
grabbed,
|
|
|
|
|
last_mouse: mouse_position().into(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn update_vectors(&mut self) {
|
|
|
|
|
self.front = vec3(
|
|
|
|
|
self.yaw.cos() * self.pitch.cos(),
|
|
|
|
|
self.pitch.sin(),
|
|
|
|
|
self.yaw.sin() * self.pitch.cos(),
|
|
|
|
|
)
|
|
|
|
|
.normalize();
|
|
|
|
|
|
|
|
|
|
self.right = self.front.cross(self.world_up).normalize();
|
|
|
|
|
self.up = self.right.cross(self.front).normalize();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn handle_mouse(&mut self, delta: f32) {
|
|
|
|
|
let mouse: Vec2 = mouse_position().into();
|
|
|
|
|
let mouse_delta = mouse - self.last_mouse;
|
|
|
|
|
self.last_mouse = mouse;
|
|
|
|
|
|
|
|
|
|
if !self.grabbed {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.yaw += mouse_delta.x * delta * LOOK_SPEED;
|
|
|
|
|
self.pitch -= mouse_delta.y * delta * LOOK_SPEED;
|
|
|
|
|
|
|
|
|
|
// clamp pitch
|
|
|
|
|
self.pitch = self.pitch.clamp(-1.5, 1.5);
|
|
|
|
|
|
|
|
|
|
self.update_vectors();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn handle_keyboard(&mut self) {
|
|
|
|
|
if is_key_down(KeyCode::W) {
|
|
|
|
|
self.position += self.front * MOVE_SPEED;
|
|
|
|
|
}
|
|
|
|
|
if is_key_down(KeyCode::S) {
|
|
|
|
|
self.position -= self.front * MOVE_SPEED;
|
|
|
|
|
}
|
|
|
|
|
if is_key_down(KeyCode::A) {
|
|
|
|
|
self.position -= self.right * MOVE_SPEED;
|
|
|
|
|
}
|
|
|
|
|
if is_key_down(KeyCode::D) {
|
|
|
|
|
self.position += self.right * MOVE_SPEED;
|
|
|
|
|
}
|
|
|
|
|
if is_key_down(KeyCode::LeftShift) {
|
|
|
|
|
self.position += Vec3::Y * MOVE_SPEED;
|
|
|
|
|
}
|
|
|
|
|
if is_key_down(KeyCode::LeftControl) {
|
|
|
|
|
self.position -= Vec3::Y * MOVE_SPEED;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn update(&mut self, delta: f32) {
|
|
|
|
|
if is_key_pressed(KeyCode::Tab) {
|
|
|
|
|
self.grabbed = !self.grabbed;
|
|
|
|
|
set_cursor_grab(self.grabbed);
|
|
|
|
|
show_mouse(!self.grabbed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.handle_keyboard();
|
|
|
|
|
self.handle_mouse(delta);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn apply(&self) {
|
|
|
|
|
set_camera(&Camera3D {
|
|
|
|
|
position: self.position,
|
|
|
|
|
up: self.up,
|
|
|
|
|
target: self.position + self.front,
|
|
|
|
|
..Default::default()
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|