Skip to content

Commit

Permalink
integrate bevy_fly_camera code to improve camera system
Browse files Browse the repository at this point in the history
  • Loading branch information
bbarker committed Dec 11, 2023
1 parent f0282b5 commit ae877c0
Show file tree
Hide file tree
Showing 11 changed files with 240 additions and 132 deletions.
3 changes: 1 addition & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ webbrowser = { version = "0.8", features = ["hardened"] }
# keep the following in sync with Bevy's dependencies
winit = { version = "0.28.7", default-features = false }
image = { version = "0.24", default-features = false }
bevy_voxel_world = "0.3.3"
bevy_voxel_world = {git = "https://github.com/splashdust/bevy_voxel_world.git", rev = "115bd34"} # "0.3.3"
noise = "0.8.2"
lazy_static = "1.4.0"
strum = "0.25.0"
Expand Down
1 change: 1 addition & 0 deletions credits/CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@
* Game [project template](https://github.com/NiklasEi/bevy_game_template) - Nikl (`@nikl_me@mastodon.online`)
* Voxel World Plugin ([bevy_voxel_world](https://github.com/splashdust/bevy_voxel_world))
- `splashdust` (Joacim Magnusson)
* [bevy_fly_camera](https://github.com/mcpar-land/bevy_fly_camera) - modified and used in codebase (MIT license).
* [Bevy](https://bevyengine.org/) - The Bevy Team!
* The Rust programming language
51 changes: 0 additions & 51 deletions src/actions/game_control.rs

This file was deleted.

40 changes: 20 additions & 20 deletions src/actions/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
use bevy::prelude::*;

use crate::actions::game_control::{get_movement, GameControl};
use crate::game_control::{GameControl, MovementControl};
use crate::GameState;

mod game_control;

//pub const FOLLOW_EPSILON: f32 = 5.;

pub struct ActionsPlugin;
Expand All @@ -22,7 +20,7 @@ impl Plugin for ActionsPlugin {

#[derive(Default, Resource)]
pub struct Actions {
pub player_movement: Option<Vec3>,
pub player_movement: Vec<MovementControl>,
pub left_click_crosshair: bool,
pub open_menu: bool,
}
Expand All @@ -35,14 +33,18 @@ pub fn set_playing_actions(
//player: Query<&Transform, With<Player>>,
//camera: Query<(&Camera, &GlobalTransform), With<Camera2d>>,
) {
let player_movement = Vec3::new(
get_movement(GameControl::Right, &keyboard_input, &mouse_input)
- get_movement(GameControl::Left, &keyboard_input, &mouse_input),
get_movement(GameControl::Space, &keyboard_input, &mouse_input)
- get_movement(GameControl::C, &keyboard_input, &mouse_input),
get_movement(GameControl::Up, &keyboard_input, &mouse_input)
- get_movement(GameControl::Down, &keyboard_input, &mouse_input),
);
let game_controls_from_keys: Vec<GameControl> = keyboard_input
.get_pressed()
.filter_map(|key_code| GameControl::from_key_code(*key_code))
.collect();
let game_controls_from_mouse: Vec<GameControl> = mouse_input
.get_pressed()
.filter_map(|mouse_button| GameControl::from_mouse_button(*mouse_button))
.collect();
actions.player_movement = game_controls_from_keys
.iter()
.filter_map(|key_code| GameControl::movement_control(key_code.clone()))
.collect();

/*if let Some(touch_position) = touch_input.first_pressed_position() {
let (camera, camera_transform) = camera.single();
Expand All @@ -54,13 +56,11 @@ pub fn set_playing_actions(
}
}
}*/
actions.left_click_crosshair = game_controls_from_mouse
.iter()
.any(|x| *x == GameControl::ClickTarget);

if player_movement != Vec3::ZERO {
actions.player_movement = Some(player_movement.normalize());
} else {
actions.player_movement = None;
}

actions.left_click_crosshair = GameControl::ClickTarget.pressed(&keyboard_input, &mouse_input);
actions.open_menu = GameControl::OpenMenu.pressed(&keyboard_input, &mouse_input);
actions.open_menu = game_controls_from_keys
.iter()
.any(|x| *x == GameControl::OpenMenu);
}
4 changes: 2 additions & 2 deletions src/audio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ fn control_flying_sound(
if let Some(instance) = audio_instances.get_mut(&audio.0) {
match instance.state() {
PlaybackState::Paused { .. } => {
if actions.player_movement.is_some() {
if !actions.player_movement.is_empty() {
instance.resume(AudioTween::default());
}
}
PlaybackState::Playing { .. } => {
if actions.player_movement.is_none() {
if actions.player_movement.is_empty() {
instance.pause(AudioTween::default());
}
}
Expand Down
186 changes: 159 additions & 27 deletions src/camera_handler.rs
Original file line number Diff line number Diff line change
@@ -1,50 +1,182 @@
use crate::actions::*;
use crate::game_control::*;
use crate::player::Player;
use crate::GameState;
use bevy::{input::mouse::MouseMotion, prelude::*, window::CursorGrabMode};
use bevy_voxel_world::prelude::*;

use crate::GameState;

pub struct CameraHandlerPlugin;

/// This plugin makes the camera move
/// Camera logic is only active during the State `GameState::Playing`
impl Plugin for CameraHandlerPlugin {
fn build(&self, app: &mut App) {
app.add_systems(OnEnter(GameState::Playing), setup_mouse)
.add_systems(Update, move_camera.run_if(in_state(GameState::Playing)));
.add_systems(
Update,
mouse_motion_system.run_if(in_state(GameState::Playing)),
)
.add_systems(
Update,
camera_movement_system.run_if(in_state(GameState::Playing)),
);
}
}

fn move_camera(
mut motion_evr: EventReader<MouseMotion>,
#[derive(Component)]
pub struct FlyCamera {
/// The speed the FlyCamera accelerates at. Defaults to `1.5`
pub accel: f32,
/// The maximum speed the FlyCamera can move at. Defaults to `0.5`
pub max_speed: f32,
/// The sensitivity of the FlyCamera's motion based on mouse movement. Defaults to `3.0`
pub sensitivity: f32,
/// The amount of deceleration to apply to the camera's motion. Defaults to `1.0`
pub friction: f32,
/// The current pitch of the FlyCamera in degrees. This value is always up-to-date, enforced by [FlyCameraPlugin](struct.FlyCameraPlugin.html)
pub pitch: f32,
/// The current pitch of the FlyCamera in degrees. This value is always up-to-date, enforced by [FlyCameraPlugin](struct.FlyCameraPlugin.html)
pub yaw: f32,
/// The current velocity of the FlyCamera. This value is always up-to-date, enforced by [FlyCameraPlugin](struct.FlyCameraPlugin.html)
pub velocity: Vec3,
pub enabled: bool,
}
impl Default for FlyCamera {
fn default() -> Self {
Self {
accel: 1.5,
max_speed: 0.5,
sensitivity: 3.0,
friction: 1.0,
pitch: 0.0,
yaw: 0.0,
velocity: Vec3::ZERO,
enabled: true,
}
}
}

fn setup_mouse(mut windows: Query<&mut Window>) {
let mut window = windows.single_mut();

window.cursor.visible = false;
window.cursor.grab_mode = CursorGrabMode::Locked;
}

fn forward_vector(rotation: &Quat) -> Vec3 {
rotation.mul_vec3(Vec3::Z).normalize()
}

fn forward_walk_vector(rotation: &Quat) -> Vec3 {
let f = forward_vector(rotation);

Vec3::new(f.x, 0.0, f.z).normalize()
}

fn strafe_vector(rotation: &Quat) -> Vec3 {
// Rotate it 90 degrees to get the strafe direction
Quat::from_rotation_y(90.0f32.to_radians())
.mul_vec3(forward_walk_vector(rotation))
.normalize()
}

fn camera_movement_system(
time: Res<Time>,
mut cam_transform: Query<&mut Transform, With<VoxelWorldCamera>>,
actions: Res<Actions>,
mut player_query: Query<&mut Transform, With<Player>>,
mut query: Query<(&mut FlyCamera, &mut Transform), (With<VoxelWorldCamera>, Without<Player>)>,
) {
motion_evr.read().for_each(|ev| {
let rotation_speed = 0.1; // Adjust this value as needed
for (mut options, mut transform) in query.iter_mut() {
let (axis_h, axis_v, axis_float) = if options.enabled {
(
movement_axis(&actions, MovementControl::Right, MovementControl::Left),
movement_axis(
&actions,
MovementControl::Backward,
MovementControl::Forward,
),
movement_axis(&actions, MovementControl::Up, MovementControl::Down),
)
} else {
(0.0, 0.0, 0.0)
};

let rotation = transform.rotation;
let accel: Vec3 = (strafe_vector(&rotation) * axis_h)
+ (forward_walk_vector(&rotation) * axis_v)
+ (Vec3::Y * axis_float);
let accel: Vec3 = if accel.length() != 0.0 {
accel.normalize() * options.accel
} else {
Vec3::ZERO
};

let friction: Vec3 = if options.velocity.length() != 0.0 {
options.velocity.normalize() * -1.0 * options.friction
} else {
Vec3::ZERO
};

// Calculate the new rotation based on mouse input
let delta_x = -(ev.delta.x * time.delta_seconds() * rotation_speed);
let delta_y = -(ev.delta.y * time.delta_seconds() * rotation_speed);
options.velocity += accel * time.delta_seconds();

// Get the current rotation of the camera
let mut camera_transform = cam_transform.single_mut();
let current_rotation = camera_transform.rotation;
// clamp within max speed
if options.velocity.length() > options.max_speed {
options.velocity = options.velocity.normalize() * options.max_speed;
}

// Create new rotations for x and y axes
let rotation_x = Quat::from_rotation_x(delta_y);
let rotation_y = Quat::from_rotation_y(delta_x);
let delta_friction = friction * time.delta_seconds();

// Combine the new rotations with the current rotation
let new_rotation = current_rotation * rotation_x * rotation_y;
options.velocity =
if (options.velocity + delta_friction).signum() != options.velocity.signum() {
Vec3::ZERO
} else {
options.velocity + delta_friction
};

// Update the camera's rotation
camera_transform.rotation = new_rotation;
})
transform.translation += options.velocity;
if let Ok(mut player_transform) = player_query.get_single_mut() {
player_transform.translation += options.velocity;
}
}
}

fn setup_mouse(mut windows: Query<&mut Window>) {
let mut window = windows.single_mut();
fn mouse_motion_system(
time: Res<Time>,
mut mouse_motion_event_reader: EventReader<MouseMotion>,
mut query: Query<(&mut FlyCamera, &mut Transform)>,
) {
let mut delta: Vec2 = Vec2::ZERO;
for event in mouse_motion_event_reader.read() {
delta += event.delta;
}
if delta.is_nan() {
return;
}

window.cursor.visible = false;
window.cursor.grab_mode = CursorGrabMode::Locked;
for (mut options, mut transform) in query.iter_mut() {
if !options.enabled {
continue;
}
options.yaw -= delta.x * options.sensitivity * time.delta_seconds();
options.pitch += delta.y * options.sensitivity * time.delta_seconds();

options.pitch = options.pitch.clamp(-89.0, 89.9);
// println!("pitch: {}, yaw: {}", options.pitch, options.yaw);

let yaw_radians = options.yaw.to_radians();
let pitch_radians = options.pitch.to_radians();

transform.rotation = Quat::from_axis_angle(Vec3::Y, yaw_radians)
* Quat::from_axis_angle(-Vec3::X, pitch_radians);
}
}

pub fn movement_axis(actions: &Res<Actions>, plus: MovementControl, minus: MovementControl) -> f32 {
let mut axis = 0.0;
if actions.player_movement.contains(&plus) {
axis += 1.0;
}
if actions.player_movement.contains(&minus) {
axis -= 1.0;
}
axis
}
Loading

0 comments on commit ae877c0

Please sign in to comment.