Rotate camera with mouse
ci/woodpecker/push/build Pipeline was successful
Details
ci/woodpecker/push/build Pipeline was successful
Details
This commit is contained in:
parent
249b87afed
commit
f3c25b6370
|
@ -1,14 +1,21 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use edict::{World, Component};
|
||||
use lyra_engine::{math::{Vec3, Angle, Quat}, input::{InputButtons, KeyCode, MouseMotion}, ecs::{SimpleSystem, components::camera::CameraComponent, EventQueue}, game::Game, plugin::Plugin};
|
||||
use edict::{Component, World};
|
||||
use lyra_engine::{
|
||||
ecs::{components::camera::CameraComponent, EventQueue, SimpleSystem},
|
||||
game::Game,
|
||||
input::{InputButtons, KeyCode, MouseMotion},
|
||||
math::{Angle, Quat, Vec3},
|
||||
plugin::Plugin,
|
||||
};
|
||||
use tracing::debug;
|
||||
|
||||
#[derive(Clone, Component)]
|
||||
pub struct FreeFlyCamera {
|
||||
pub speed: f32,
|
||||
pub look_speed: f32,
|
||||
pub look_with_keys: bool
|
||||
pub mouse_sensitivity: f32,
|
||||
pub look_with_keys: bool,
|
||||
}
|
||||
|
||||
impl Default for FreeFlyCamera {
|
||||
|
@ -16,17 +23,19 @@ impl Default for FreeFlyCamera {
|
|||
Self {
|
||||
speed: 0.07,
|
||||
look_speed: 0.01,
|
||||
look_with_keys: false
|
||||
mouse_sensitivity: 0.03,
|
||||
look_with_keys: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FreeFlyCamera {
|
||||
pub fn new(speed: f32, look_speed: f32, look_with_keys: bool) -> Self {
|
||||
pub fn new(speed: f32, look_speed: f32, mouse_sensitivity: f32, look_with_keys: bool) -> Self {
|
||||
Self {
|
||||
speed,
|
||||
look_speed,
|
||||
look_with_keys
|
||||
mouse_sensitivity,
|
||||
look_with_keys,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,13 +46,15 @@ impl SimpleSystem for FreeFlyCameraController {
|
|||
fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> {
|
||||
let mut camera_rot = Vec3::default();
|
||||
|
||||
let keys = world.get_resource::<InputButtons<KeyCode>>()
|
||||
.map(|r| r.deref().clone());
|
||||
if keys.is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
let keys = keys.unwrap();
|
||||
let events = world
|
||||
.get_resource_mut::<EventQueue>()
|
||||
.and_then(|q| q.read_events::<MouseMotion>());
|
||||
|
||||
let keys = world
|
||||
.get_resource::<InputButtons<KeyCode>>()
|
||||
.map(|r| r.deref().clone());
|
||||
|
||||
if let Some(keys) = keys.as_ref() {
|
||||
if keys.is_pressed(KeyCode::Left) {
|
||||
camera_rot.y += 1.0;
|
||||
}
|
||||
|
@ -67,16 +78,19 @@ impl SimpleSystem for FreeFlyCameraController {
|
|||
if keys.is_pressed(KeyCode::Q) {
|
||||
camera_rot.z += 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
let camera_rot = camera_rot.normalize();
|
||||
|
||||
for (cam, fly) in world.query_mut::<(&mut CameraComponent, &mut FreeFlyCamera)>().iter_mut() {
|
||||
for (cam, fly) in world
|
||||
.query_mut::<(&mut CameraComponent, &mut FreeFlyCamera)>()
|
||||
.iter_mut()
|
||||
{
|
||||
let forward = cam.transform.forward();
|
||||
let left = cam.transform.left();
|
||||
let up = cam.transform.up();
|
||||
|
||||
// handle camera movement
|
||||
if let Some(keys) = keys.as_ref() {
|
||||
let mut velocity = Vec3::ZERO;
|
||||
|
||||
if keys.is_pressed(KeyCode::A) {
|
||||
velocity -= left;
|
||||
}
|
||||
|
@ -104,10 +118,21 @@ impl SimpleSystem for FreeFlyCameraController {
|
|||
if velocity != Vec3::ZERO {
|
||||
cam.transform.translation += velocity.normalize() * fly.speed;
|
||||
}
|
||||
}
|
||||
|
||||
if !camera_rot.is_nan() {
|
||||
let look_velocity = camera_rot.normalize() * fly.look_speed;
|
||||
cam.transform.rotation *= Quat::from_rotation_x(look_velocity.x) * Quat::from_rotation_y(look_velocity.y) * Quat::from_rotation_z(look_velocity.z);
|
||||
// handle camera rotation
|
||||
if let Some(mut events) = events.clone() {
|
||||
while let Some(motion) = events.pop_front() {
|
||||
camera_rot.x -= motion.delta.y * fly.mouse_sensitivity;
|
||||
camera_rot.y -= motion.delta.x * fly.mouse_sensitivity;
|
||||
}
|
||||
}
|
||||
|
||||
if camera_rot != Vec3::ZERO {
|
||||
let look_velocity = camera_rot * fly.look_speed;
|
||||
cam.transform.rotation *= Quat::from_rotation_x(look_velocity.x)
|
||||
* Quat::from_rotation_y(look_velocity.y)
|
||||
* Quat::from_rotation_z(look_velocity.z);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,11 +23,11 @@ pub const INDICES: &[u16] = &[
|
|||
#[async_std::main]
|
||||
async fn main() {
|
||||
let setup_sys = |world: &mut World| -> anyhow::Result<()> {
|
||||
/* {
|
||||
{
|
||||
let mut window_options = world.get_resource_mut::<Ct<WindowOptions>>().unwrap();
|
||||
window_options.cursor_grab = CursorGrabMode::Confined;
|
||||
window_options.cursor_visible = false;
|
||||
} */
|
||||
}
|
||||
|
||||
let mut resman = world.get_resource_mut::<ResourceManager>().unwrap();
|
||||
//let diffuse_texture = resman.request::<Texture>("assets/happy-tree.png").unwrap();
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
use edict::Component;
|
||||
|
||||
use crate::{math::{Angle, Transform}, render::camera::CameraProjectionMode};
|
||||
|
||||
#[derive(Clone, Component)]
|
||||
pub struct FreeFlyCamera {
|
||||
pub transform: Transform,
|
||||
pub fov: Angle,
|
||||
pub mode: CameraProjectionMode,
|
||||
pub speed: f32,
|
||||
}
|
||||
|
||||
impl Default for FreeFlyCamera {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl FreeFlyCamera {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
transform: Transform::default(),
|
||||
fov: Angle::Degrees(45.0),
|
||||
mode: CameraProjectionMode::Perspective,
|
||||
speed: 1.5,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,3 +2,4 @@ pub mod mesh;
|
|||
pub mod model;
|
||||
pub mod transform;
|
||||
pub mod camera;
|
||||
pub mod free_fly_camera;
|
31
src/game.rs
31
src/game.rs
|
@ -2,7 +2,7 @@ use std::{sync::Arc, collections::VecDeque};
|
|||
|
||||
use async_std::task::block_on;
|
||||
|
||||
use tracing::{info, error, Level};
|
||||
use tracing::{info, error, Level, debug};
|
||||
use tracing_appender::non_blocking;
|
||||
use tracing_subscriber::{
|
||||
layer::SubscriberExt,
|
||||
|
@ -12,7 +12,7 @@ use tracing_subscriber::{
|
|||
|
||||
use winit::{window::{WindowBuilder, Window}, event::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode, DeviceEvent}, event_loop::{EventLoop, ControlFlow}};
|
||||
|
||||
use crate::{render::renderer::{Renderer, BasicRenderer}, input_event::InputEvent, ecs::{SimpleSystem, SystemDispatcher, EventQueue, Events}, plugin::Plugin};
|
||||
use crate::{render::{renderer::{Renderer, BasicRenderer}, window::WindowOptions}, input_event::InputEvent, ecs::{SimpleSystem, SystemDispatcher, EventQueue, Events}, plugin::Plugin, change_tracker::Ct};
|
||||
|
||||
pub struct Controls<'a> {
|
||||
pub world: &'a mut edict::World,
|
||||
|
@ -91,21 +91,6 @@ impl GameLoop {
|
|||
Some(ControlFlow::Exit)
|
||||
},
|
||||
|
||||
// TODO: Create system for this? or maybe merge into input system, idk
|
||||
InputEvent::CursorEntered { .. } => {
|
||||
let state = self.world.with_resource(WindowState::new);
|
||||
state.is_cursor_inside_window = true;
|
||||
|
||||
None
|
||||
},
|
||||
|
||||
InputEvent::CursorLeft { .. } => {
|
||||
let state = self.world.with_resource(WindowState::new);
|
||||
state.is_cursor_inside_window = false;
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
_ => {
|
||||
//debug!("Got unhandled input event: \"{:?}\"", event);
|
||||
|
||||
|
@ -122,16 +107,20 @@ impl GameLoop {
|
|||
*control_flow = ControlFlow::Poll;
|
||||
match event {
|
||||
Event::DeviceEvent { device_id, event: DeviceEvent::MouseMotion { delta } } => {
|
||||
//debug!("motion: {delta:?}");
|
||||
// convert a MouseMotion event to an InputEvent
|
||||
// make sure that the mouse is inside the window and the mouse has focus before reporting mouse motion
|
||||
let trigger = matches!(self.world.get_resource::<WindowState>(), Some(window_state)
|
||||
if window_state.is_focused && window_state.is_cursor_inside_window);
|
||||
/* let trigger = matches!(self.world.get_resource::<WindowState>(), Some(window_state)
|
||||
if window_state.is_focused && window_state.is_cursor_inside_window); */
|
||||
|
||||
let trigger = matches!(self.world.get_resource::<Ct<WindowOptions>>(), Some(window)
|
||||
if window.focused && window.cursor_inside_window);
|
||||
|
||||
if trigger {
|
||||
let event_queue = self.world.with_resource(Events::<InputEvent>::new);
|
||||
let mut event_queue = self.world.get_resource_mut::<EventQueue>().unwrap();
|
||||
|
||||
let input_event = InputEvent::MouseMotion { device_id, delta, };
|
||||
event_queue.push_back(input_event);
|
||||
event_queue.trigger_event(input_event);
|
||||
}
|
||||
},
|
||||
Event::WindowEvent {
|
||||
|
|
|
@ -258,8 +258,6 @@ impl InputSystem {
|
|||
delta: Vec2::new(delta.0 as f32, delta.1 as f32)
|
||||
};
|
||||
|
||||
debug!("delta: {:?}", delta);
|
||||
|
||||
event_queue.trigger_event(delta);
|
||||
},
|
||||
InputEvent::CursorMoved { position, .. } => {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::sync::Arc;
|
||||
use std::{sync::Arc, collections::VecDeque};
|
||||
|
||||
use glam::{Vec2, IVec2};
|
||||
use tracing::{warn, error};
|
||||
|
@ -6,7 +6,7 @@ use winit::{window::{Window, Fullscreen}, dpi::{LogicalPosition, LogicalSize, Ph
|
|||
|
||||
pub use winit::window::{CursorGrabMode, CursorIcon, Icon, Theme, WindowButtons, WindowLevel};
|
||||
|
||||
use crate::{plugin::Plugin, change_tracker::Ct};
|
||||
use crate::{plugin::Plugin, change_tracker::Ct, ecs::EventQueue, input_event::InputEvent};
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub enum WindowMode {
|
||||
|
@ -171,6 +171,12 @@ pub struct WindowOptions {
|
|||
/// Change the window level.
|
||||
/// This is just a hint to the OS, and the system could ignore it.
|
||||
pub level: WindowLevel,
|
||||
|
||||
/// Get/set the window's focused state.
|
||||
pub focused: bool,
|
||||
|
||||
/// Get whether or not the cursor is inside the window.
|
||||
pub cursor_inside_window: bool,
|
||||
}
|
||||
|
||||
impl Default for WindowOptions {
|
||||
|
@ -198,6 +204,8 @@ impl Default for WindowOptions {
|
|||
title: "Lyra Engine Game".to_string(),
|
||||
icon: None,
|
||||
level: WindowLevel::Normal,
|
||||
focused: false,
|
||||
cursor_inside_window: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -252,10 +260,11 @@ fn set_cursor_grab(window: &Window, grab: &mut CursorGrabMode) -> anyhow::Result
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// if the window is set to confine the cursor, and the cursor is invisible,
|
||||
/// set the cursor position to the center of the screen.
|
||||
/// if the window is set to confine the cursor, the cursor is invisible,
|
||||
/// and the window is focused, set the cursor position to the center of the screen.
|
||||
fn center_mouse(window: &Window, options: &WindowOptions) {
|
||||
if options.cursor_grab == CursorGrabMode::Confined && !options.cursor_visible {
|
||||
if options.cursor_grab == CursorGrabMode::Confined && !options.cursor_visible
|
||||
&& options.focused {
|
||||
let size = window.inner_size();
|
||||
let middle = PhysicalPosition {
|
||||
x: size.width / 2,
|
||||
|
@ -269,11 +278,14 @@ fn window_updater_system(world: &mut edict::World) -> anyhow::Result<()> {
|
|||
if let (Some(window), Some(opts)) = (world.get_resource::<Arc<Window>>(), world.get_resource::<Ct<WindowOptions>>()) {
|
||||
// if the options changed, update the window
|
||||
if opts.peek_changed() {
|
||||
drop(opts); // avoid attempting to get a RefMut when we already have a Ref out.
|
||||
drop(opts); // drop the Ref, we're about to get a RefMut
|
||||
|
||||
// now we can get it mutable, this will trigger the ChangeTracker, so it will be reset at the end of this scope.
|
||||
let mut opts = world.get_resource_mut::<Ct<WindowOptions>>().unwrap();
|
||||
|
||||
if opts.focused {
|
||||
window.focus_window();
|
||||
}
|
||||
window.set_content_protected(opts.content_protected);
|
||||
set_cursor_grab(&window, &mut opts.cursor_grab)?;
|
||||
match window.set_cursor_hittest(opts.cursor_hittest) {
|
||||
|
@ -324,6 +336,31 @@ fn window_updater_system(world: &mut edict::World) -> anyhow::Result<()> {
|
|||
|
||||
center_mouse(&window, &opts);
|
||||
} else {
|
||||
drop(opts); // drop the Ref, we're about to get a RefMut
|
||||
let mut opts = world.get_resource_mut::<Ct<WindowOptions>>().unwrap();
|
||||
|
||||
if let Some(event_queue) = world.get_resource_mut::<EventQueue>() {
|
||||
if let Some(mut events) = event_queue.read_events::<InputEvent>() {
|
||||
while let Some(ev) = events.pop_front() {
|
||||
match ev {
|
||||
InputEvent::CursorEntered { .. } => {
|
||||
opts.cursor_inside_window = true;
|
||||
},
|
||||
InputEvent::CursorLeft { .. } => {
|
||||
opts.cursor_inside_window = false;
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update the stored state of the window to match the actual window
|
||||
|
||||
opts.focused = window.has_focus();
|
||||
|
||||
opts.reset();
|
||||
|
||||
center_mouse(&window, &opts);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue