fix: bullet ghost hits and refactor
This commit is contained in:
50
src/ui/camera.rs
Normal file
50
src/ui/camera.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy::input::mouse::{AccumulatedMouseMotion, MouseMotion};
|
||||
use bevy::ecs::query::QuerySingleError;
|
||||
|
||||
use super::cursor::CursorGrabState;
|
||||
|
||||
pub struct CameraPlugin;
|
||||
|
||||
impl Plugin for CameraPlugin
|
||||
{
|
||||
fn build(&self, app: &mut App)
|
||||
{
|
||||
app.add_systems(PreUpdate, do_camera_rotation
|
||||
.run_if(in_state(CursorGrabState(true)))
|
||||
.run_if(on_event::<MouseMotion>)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct CameraController
|
||||
{
|
||||
pub sensitivity: Vec2,
|
||||
}
|
||||
|
||||
fn do_camera_rotation(
|
||||
mut query: Query<(&CameraController, &mut Transform)>,
|
||||
mouse_motion: Res<AccumulatedMouseMotion>,
|
||||
) {
|
||||
let (controller, mut transform) = match query.get_single_mut() {
|
||||
Ok((controller, transform)) => (controller, transform),
|
||||
Err(QuerySingleError::NoEntities(_)) => return,
|
||||
Err(QuerySingleError::MultipleEntities(_)) => panic!("Multiple camera controllers found!"),
|
||||
};
|
||||
|
||||
if mouse_motion.delta == Vec2::ZERO {
|
||||
return;
|
||||
}
|
||||
|
||||
let (yaw, pitch, roll) = transform.rotation.to_euler(EulerRot::YXZ);
|
||||
|
||||
let yaw = yaw - mouse_motion.delta.x * controller.sensitivity.x;
|
||||
let pitch = pitch - mouse_motion.delta.y * controller.sensitivity.y;
|
||||
|
||||
const PITCH_LIMIT: f32 = std::f32::consts::FRAC_PI_2 - 0.0001;
|
||||
let pitch = pitch.clamp(-PITCH_LIMIT, PITCH_LIMIT);
|
||||
|
||||
transform.rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch, roll);
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
|
||||
use bevy::prelude::*;
|
||||
|
||||
// TODO: add a crosshair component which projects a crosshair to infinity.
|
||||
// For now, we'll just draw a crosshair in the center of the screen.
|
||||
// This causes a lot of warnings without a camera!
|
||||
|
||||
pub struct CrosshairPlugin;
|
||||
|
||||
impl Plugin for CrosshairPlugin
|
||||
|
||||
54
src/ui/cursor.rs
Normal file
54
src/ui/cursor.rs
Normal file
@@ -0,0 +1,54 @@
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy::input::{ButtonState, keyboard::KeyboardInput};
|
||||
use bevy::window::{CursorGrabMode, PrimaryWindow};
|
||||
|
||||
const CURSOR_TOGGLE_KEY: KeyCode = KeyCode::Escape;
|
||||
const CURSOR_TOGGLE_STATE: ButtonState = ButtonState::Released;
|
||||
|
||||
pub struct CursorPlugin;
|
||||
|
||||
impl Plugin for CursorPlugin
|
||||
{
|
||||
fn build(&self, app: &mut App)
|
||||
{
|
||||
app.insert_state(CursorGrabState(false));
|
||||
app.add_systems(PreUpdate, on_cursor_grab_toggled.in_set(CursorSet));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(SystemSet, Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
struct CursorSet;
|
||||
|
||||
#[derive(States, Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct CursorGrabState(pub bool);
|
||||
|
||||
fn on_cursor_grab_toggled(
|
||||
mut keyboard_events: EventReader<KeyboardInput>,
|
||||
mut window: Single<&mut Window, With<PrimaryWindow>>,
|
||||
cursor_state: Res<State<CursorGrabState>>,
|
||||
mut next_cursor_state: ResMut<NextState<CursorGrabState>>,
|
||||
) {
|
||||
let cursor_toggle_count = keyboard_events.read()
|
||||
.filter(|event| event.key_code == CURSOR_TOGGLE_KEY)
|
||||
.filter(|event| event.state == CURSOR_TOGGLE_STATE)
|
||||
.count();
|
||||
|
||||
if cursor_toggle_count % 2 == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
match cursor_state.get()
|
||||
{
|
||||
CursorGrabState(true) => {
|
||||
window.cursor_options.visible = false;
|
||||
window.cursor_options.grab_mode = CursorGrabMode::Locked;
|
||||
next_cursor_state.set(CursorGrabState(false));
|
||||
}
|
||||
CursorGrabState(false) => {
|
||||
window.cursor_options.visible = true;
|
||||
window.cursor_options.grab_mode = CursorGrabMode::None;
|
||||
next_cursor_state.set(CursorGrabState(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,22 @@
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy::app::PluginGroupBuilder;
|
||||
|
||||
mod crosshair;
|
||||
pub mod window;
|
||||
pub mod cursor;
|
||||
pub mod camera;
|
||||
pub mod crosshair;
|
||||
|
||||
pub struct UiPlugin;
|
||||
pub struct UiPlugins;
|
||||
|
||||
impl Plugin for UiPlugin
|
||||
impl PluginGroup for UiPlugins
|
||||
{
|
||||
fn build(&self, app: &mut App)
|
||||
fn build(self) -> PluginGroupBuilder
|
||||
{
|
||||
app.add_plugins(crosshair::CrosshairPlugin);
|
||||
PluginGroupBuilder::start::<Self>()
|
||||
.add(window::WindowPlugin)
|
||||
.add(cursor::CursorPlugin)
|
||||
.add(camera::CameraPlugin)
|
||||
.add(crosshair::CrosshairPlugin)
|
||||
}
|
||||
}
|
||||
|
||||
45
src/ui/window.rs
Normal file
45
src/ui/window.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy::window::{CursorGrabMode, PrimaryWindow, WindowResolution};
|
||||
|
||||
use super::cursor::CursorGrabState;
|
||||
|
||||
pub struct WindowPlugin;
|
||||
|
||||
impl Plugin for WindowPlugin
|
||||
{
|
||||
fn build(&self, app: &mut App)
|
||||
{
|
||||
app.add_systems(PreStartup, setup_window);
|
||||
app.add_systems(OnEnter(CursorGrabState(true)), on_cursor_grab_toggled);
|
||||
app.add_systems(OnEnter(CursorGrabState(false)), on_cursor_grab_toggled);
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_window(
|
||||
mut window: Query<&mut Window, With<PrimaryWindow>>,
|
||||
) {
|
||||
let mut window = window.single_mut();
|
||||
window.title = "Bevy FPS Game".to_string();
|
||||
window.resolution = WindowResolution::new(1920.0, 1080.0);
|
||||
window.position = WindowPosition::Centered(MonitorSelection::Primary);
|
||||
}
|
||||
|
||||
fn on_cursor_grab_toggled(
|
||||
mut window: Query<&mut Window, With<PrimaryWindow>>,
|
||||
cursor_state: Res<State<CursorGrabState>>,
|
||||
) {
|
||||
let mut window = window.single_mut();
|
||||
|
||||
match cursor_state.get()
|
||||
{
|
||||
CursorGrabState(true) => {
|
||||
window.cursor_options.visible = false;
|
||||
window.cursor_options.grab_mode = CursorGrabMode::Locked;
|
||||
}
|
||||
CursorGrabState(false) => {
|
||||
window.cursor_options.visible = true;
|
||||
window.cursor_options.grab_mode = CursorGrabMode::None;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user