Add camera movement
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
use std::mem;
|
||||
|
||||
use winit::{
|
||||
event::{ElementState, KeyEvent},
|
||||
keyboard::{KeyCode, PhysicalKey},
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct InputState {
|
||||
mouse_delta_x: f64,
|
||||
mouse_delta_y: f64,
|
||||
|
||||
pub forward: bool,
|
||||
pub backwards: bool,
|
||||
pub left: bool,
|
||||
pub right: bool,
|
||||
pub up: bool,
|
||||
pub down: bool,
|
||||
}
|
||||
|
||||
impl InputState {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn add_mouse_motion(&mut self, dx: f64, dy: f64) {
|
||||
self.mouse_delta_x += dx;
|
||||
self.mouse_delta_y += dy;
|
||||
}
|
||||
|
||||
pub fn mouse_delta(&mut self) -> (f64, f64) {
|
||||
let dx = mem::replace(&mut self.mouse_delta_x, 0.0);
|
||||
let dy = mem::replace(&mut self.mouse_delta_y, 0.0);
|
||||
(dx, dy)
|
||||
}
|
||||
|
||||
pub fn key_event(&mut self, event: KeyEvent) {
|
||||
let PhysicalKey::Code(key) = event.physical_key else {
|
||||
return;
|
||||
};
|
||||
let pressed = event.state == ElementState::Pressed;
|
||||
|
||||
match key {
|
||||
KeyCode::KeyW => self.forward = pressed,
|
||||
KeyCode::KeyS => self.backwards = pressed,
|
||||
KeyCode::KeyA => self.left = pressed,
|
||||
KeyCode::KeyD => self.right = pressed,
|
||||
KeyCode::Space => self.up = pressed,
|
||||
KeyCode::ShiftLeft => self.down = pressed,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+63
-17
@@ -5,6 +5,7 @@ use std::{process::ExitCode, sync::Arc, time::Instant};
|
||||
|
||||
use error::Error;
|
||||
use glam::Vec3;
|
||||
use input::InputState;
|
||||
use render::{
|
||||
asset::{AssetLoader, TextureLoadStage},
|
||||
Renderer,
|
||||
@@ -14,11 +15,12 @@ use winit::{
|
||||
dpi::PhysicalSize,
|
||||
event::{DeviceEvent, DeviceId, StartCause, WindowEvent},
|
||||
event_loop::{ActiveEventLoop, EventLoop},
|
||||
window::{Window, WindowId},
|
||||
window::{CursorGrabMode, Window, WindowId},
|
||||
};
|
||||
use world::{Chunk, ChunkGenerator, NoiseChunkGenerator, World};
|
||||
use world::{camera::Camera, ChunkGenerator, NoiseChunkGenerator, World};
|
||||
|
||||
pub mod error;
|
||||
pub mod input;
|
||||
pub mod render;
|
||||
pub mod world;
|
||||
|
||||
@@ -27,9 +29,10 @@ pub struct Engine {
|
||||
renderer: Option<Renderer>,
|
||||
assets: Option<AssetLoader<TextureLoadStage>>,
|
||||
world: Option<World>,
|
||||
camera_position: Vec3,
|
||||
input: InputState,
|
||||
camera: Camera,
|
||||
generator: Box<dyn ChunkGenerator>,
|
||||
start: Instant,
|
||||
last_frame: Instant,
|
||||
}
|
||||
|
||||
impl Engine {
|
||||
@@ -41,6 +44,10 @@ impl Engine {
|
||||
.with_inner_size(PhysicalSize::new(800, 600));
|
||||
|
||||
let window = Arc::new(event_loop.create_window(window_attributes)?);
|
||||
|
||||
window.set_cursor_grab(CursorGrabMode::Locked).ok();
|
||||
window.set_cursor_visible(false);
|
||||
|
||||
let render = Renderer::from_window(window.clone(), assets)?;
|
||||
|
||||
self.window = Some(window);
|
||||
@@ -49,6 +56,42 @@ impl Engine {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update_camera(&mut self, dt: f64) {
|
||||
const SENSITIVITY: f64 = 0.15;
|
||||
const HORIZONTAL_SPEED: f32 = 17.5;
|
||||
const VERTICAL_SPEED: f32 = 15.0;
|
||||
|
||||
let (mouse_dx, mouse_dy) = self.input.mouse_delta();
|
||||
let mouse_dx = mouse_dx * dt * SENSITIVITY;
|
||||
let mouse_dy = mouse_dy * dt * SENSITIVITY;
|
||||
|
||||
self.camera.turn(mouse_dy as f32, mouse_dx as f32);
|
||||
|
||||
let want_dz = self.input.forward as i32 - self.input.backwards as i32;
|
||||
let want_dx = self.input.right as i32 - self.input.left as i32;
|
||||
let want_dy = self.input.up as i32 - self.input.down as i32;
|
||||
|
||||
if want_dx == 0 && want_dy == 0 && want_dz == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let want_horizontal_vector = if want_dx != 0 || want_dz != 0 {
|
||||
let look_vector = self.camera.horizontal_look_vector();
|
||||
let right_vector = look_vector.cross(Vec3::Y);
|
||||
((want_dx as f32) * right_vector + (want_dz as f32) * look_vector).normalize()
|
||||
} else {
|
||||
Vec3::ZERO
|
||||
};
|
||||
|
||||
let want_vertical_vector = (want_dy as f32) * Vec3::Y;
|
||||
|
||||
let horizontal_vector = want_horizontal_vector * dt as f32 * HORIZONTAL_SPEED;
|
||||
let vertical_vector = want_vertical_vector * dt as f32 * VERTICAL_SPEED;
|
||||
|
||||
self.camera
|
||||
.move_towards(horizontal_vector + vertical_vector);
|
||||
}
|
||||
}
|
||||
|
||||
impl ApplicationHandler for Engine {
|
||||
@@ -99,24 +142,23 @@ impl ApplicationHandler for Engine {
|
||||
}
|
||||
}
|
||||
WindowEvent::RedrawRequested => {
|
||||
let frame_delta = self.last_frame.elapsed();
|
||||
self.last_frame = Instant::now();
|
||||
let frame_dt = frame_delta.as_secs_f64();
|
||||
self.update_camera(frame_dt);
|
||||
|
||||
if let (Some(render), Some(world)) = (self.renderer.as_mut(), self.world.as_mut()) {
|
||||
let delta = self.start.elapsed();
|
||||
let dt = delta.as_secs_f64();
|
||||
let camera_position = self.camera.position();
|
||||
|
||||
self.camera_position = Vec3::new(
|
||||
(dt.cos() * 32.0) as f32 + (Chunk::SIZE / 2) as f32,
|
||||
48.0,
|
||||
(dt.sin() * 32.0) as f32 + (Chunk::SIZE / 2) as f32,
|
||||
);
|
||||
world.update_with_camera(camera_position, &mut *self.generator);
|
||||
|
||||
world.update_with_camera(self.camera_position, &mut *self.generator);
|
||||
|
||||
if let Err(error) = render.render(self.camera_position, world) {
|
||||
if let Err(error) = render.render(&mut self.camera, world) {
|
||||
log::error!("Render error: {error}");
|
||||
event_loop.exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
WindowEvent::KeyboardInput { event, .. } => self.input.key_event(event),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
@@ -129,7 +171,10 @@ impl ApplicationHandler for Engine {
|
||||
) {
|
||||
let _ = event_loop;
|
||||
let _ = device_id;
|
||||
let _ = event;
|
||||
|
||||
if let DeviceEvent::MouseMotion { delta } = event {
|
||||
self.input.add_mouse_motion(delta.0, delta.1);
|
||||
}
|
||||
}
|
||||
|
||||
fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
|
||||
@@ -156,9 +201,10 @@ fn run() -> Result<(), Error> {
|
||||
renderer: None,
|
||||
assets: Some(loader),
|
||||
world: Some(world),
|
||||
camera_position: Vec3::ZERO,
|
||||
camera: Camera::new(),
|
||||
input: InputState::new(),
|
||||
generator: Box::new(NoiseChunkGenerator::from_seed(1234)),
|
||||
start: Instant::now(),
|
||||
last_frame: Instant::now(),
|
||||
};
|
||||
|
||||
event_loop.run_app(&mut engine)?;
|
||||
|
||||
+12
-10
@@ -4,7 +4,7 @@ use std::{
|
||||
};
|
||||
|
||||
use asset::{AssetLoader, TextureLoadStage};
|
||||
use glam::{Mat4, Vec3};
|
||||
use glam::Mat4;
|
||||
use mesh::WorldMeshState;
|
||||
use util::{Allocators, ViewportExt};
|
||||
use vertex::InputVertex;
|
||||
@@ -38,7 +38,7 @@ use winit::window::Window;
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
world::{Chunk, ChunkCoords, World},
|
||||
world::{camera::Camera, Chunk, ChunkCoords, World},
|
||||
};
|
||||
|
||||
pub mod asset;
|
||||
@@ -241,7 +241,7 @@ impl Renderer {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn render(&mut self, camera_position: Vec3, world: &mut World) -> Result<(), Error> {
|
||||
pub fn render(&mut self, camera: &mut Camera, world: &mut World) -> Result<(), Error> {
|
||||
self.fps.new_frame();
|
||||
self.fps.update();
|
||||
|
||||
@@ -270,15 +270,16 @@ impl Renderer {
|
||||
|
||||
let model = Mat4::IDENTITY;
|
||||
let projection = Mat4::perspective_rh_gl(45.0f32.to_radians(), aspect, 0.01, 1000.0);
|
||||
let view = camera.transform();
|
||||
|
||||
fn make_view(camera: Vec3, target: Vec3) -> Mat4 {
|
||||
Mat4::look_at_rh(camera, target, Vec3::Y)
|
||||
}
|
||||
// fn make_view(camera: Vec3, target: Vec3) -> Mat4 {
|
||||
// Mat4::look_at_rh(camera, target, Vec3::Y)
|
||||
// }
|
||||
|
||||
let view = make_view(
|
||||
camera_position,
|
||||
Vec3::new((Chunk::SIZE / 2) as f32, 32.0, (Chunk::SIZE / 2) as f32),
|
||||
);
|
||||
// let view = make_view(
|
||||
// camera_position,
|
||||
// Vec3::new((Chunk::SIZE / 2) as f32, 32.0, (Chunk::SIZE / 2) as f32),
|
||||
// );
|
||||
|
||||
let set0 = {
|
||||
let uniform_buffer = self
|
||||
@@ -352,6 +353,7 @@ impl Renderer {
|
||||
(x as i32 + Chunk::SIZE as i32 / 2) / Chunk::SIZE as i32
|
||||
}
|
||||
|
||||
let camera_position = camera.position();
|
||||
let camera_cx = cpos(camera_position.x);
|
||||
let camera_cz = cpos(camera_position.z);
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
use glam::{EulerRot, Mat4, Vec3, Vec4, Vec4Swizzles};
|
||||
|
||||
pub struct Camera {
|
||||
position: Vec3,
|
||||
yaw: f32,
|
||||
pitch: f32,
|
||||
|
||||
transform: Mat4,
|
||||
dirty: bool,
|
||||
}
|
||||
|
||||
impl Camera {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
position: Vec3::ZERO,
|
||||
yaw: 0.0,
|
||||
pitch: 0.0,
|
||||
transform: Mat4::IDENTITY,
|
||||
dirty: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn position(&self) -> Vec3 {
|
||||
self.position
|
||||
}
|
||||
|
||||
pub fn move_to(&mut self, position: Vec3) {
|
||||
self.position = position;
|
||||
self.dirty = true;
|
||||
}
|
||||
|
||||
pub fn move_towards(&mut self, delta: Vec3) {
|
||||
self.position += delta;
|
||||
self.dirty = true;
|
||||
}
|
||||
|
||||
pub fn turn(&mut self, pitch: f32, yaw: f32) {
|
||||
self.pitch += pitch;
|
||||
self.yaw += yaw;
|
||||
self.dirty = true;
|
||||
}
|
||||
|
||||
pub fn horizontal_look_vector(&self) -> Vec3 {
|
||||
Vec3::new(self.yaw.cos(), 0.0, self.yaw.sin())
|
||||
}
|
||||
|
||||
pub fn look_vector(&self) -> Vec3 {
|
||||
(Mat4::from_euler(EulerRot::XYZ, 0.0, -self.yaw, -self.pitch)
|
||||
* Vec4::new(1.0, 0.0, 0.0, 0.0))
|
||||
.xyz()
|
||||
}
|
||||
|
||||
pub fn transform(&mut self) -> &Mat4 {
|
||||
if self.dirty {
|
||||
let look_vector = self.look_vector();
|
||||
self.transform = Mat4::look_to_rh(self.position, look_vector, Vec3::Y);
|
||||
}
|
||||
|
||||
&self.transform
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use bitflags::bitflags;
|
||||
|
||||
pub mod camera;
|
||||
pub mod chunk;
|
||||
pub mod feature;
|
||||
pub mod generator;
|
||||
|
||||
Reference in New Issue
Block a user