Skip to content

Commit

Permalink
basic camera controls
Browse files Browse the repository at this point in the history
  • Loading branch information
ChristopherBiscardi committed Dec 26, 2023
1 parent 5596641 commit f39c2c0
Show file tree
Hide file tree
Showing 5 changed files with 303 additions and 4 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ env:
# update with the name of the main binary
binary: candy-blocks
add_binaries_to_github_release: true
# todo: upload to itch
# itch_target: chrisbiscardi/candy-blocks
itch_target: chrisbiscardi/candy-blocks

jobs:
# Build for wasm
Expand Down
2 changes: 1 addition & 1 deletion src/brick/materials.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use bevy::{
asset::{embedded_asset, embedded_path},
asset::embedded_asset,
prelude::*,
render::render_resource::{AsBindGroup, ShaderRef},
};
Expand Down
289 changes: 289 additions & 0 deletions src/camera_controller.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,289 @@
use bevy::{
input::mouse::{
MouseMotion, MouseScrollUnit, MouseWheel,
},
prelude::*,
};

pub struct CameraControllerPlugin;

impl Plugin for CameraControllerPlugin {
fn build(&self, app: &mut App) {
app.insert_resource(RotateCamera(false))
.add_systems(
Update,
(mouse, camera_controller),
);
}
}

#[derive(Resource)]
struct RotateCamera(bool);

fn mouse(
mut windows: Query<&mut Window>,
mouse: Res<Input<MouseButton>>,
key: Res<Input<KeyCode>>,
mut rotate_camera: ResMut<RotateCamera>,
) {
if mouse.just_pressed(MouseButton::Right) {
*rotate_camera = RotateCamera(true);
}
if mouse.just_released(MouseButton::Right)
|| key.just_pressed(KeyCode::Escape)
{
*rotate_camera = RotateCamera(false);
}
}

/// Provides basic movement functionality to the attached camera
#[derive(Component, Clone)]
pub struct CameraController {
pub enabled: bool,
pub initialized: bool,
pub sensitivity: f32,
pub key_forward: KeyCode,
pub key_back: KeyCode,
pub key_left: KeyCode,
pub key_right: KeyCode,
pub key_up: KeyCode,
pub key_down: KeyCode,
pub key_run: KeyCode,
pub mouse_key_enable_mouse: MouseButton,
pub mouse_key_enable_mouse_pan: MouseButton,
pub keyboard_key_enable_mouse: KeyCode,
pub walk_speed: f32,
pub run_speed: f32,
pub friction: f32,
pub pitch: f32,
pub yaw: f32,
pub velocity: Vec3,
pub orbit_focus: Vec3,
pub orbit_mode: bool,
pub scroll_wheel_speed: f32,
pub lock_y: bool,
// pub low_bounds: Vec3,
// pub high_bounds: Vec3,
}

impl Default for CameraController {
fn default() -> Self {
Self {
enabled: true,
initialized: false,
sensitivity: 0.25,
key_forward: KeyCode::W,
key_back: KeyCode::S,
key_left: KeyCode::A,
key_right: KeyCode::D,
key_up: KeyCode::E,
key_down: KeyCode::Q,
key_run: KeyCode::ShiftLeft,
mouse_key_enable_mouse: MouseButton::Left,
mouse_key_enable_mouse_pan: MouseButton::Right,
keyboard_key_enable_mouse: KeyCode::M,
walk_speed: 5.0,
run_speed: 15.0,
friction: 0.5,
pitch: 0.0,
yaw: 0.0,
velocity: Vec3::ZERO,
orbit_focus: Vec3::ZERO,
orbit_mode: false,
scroll_wheel_speed: 0.1,
lock_y: false,
// low_bounds: Vec3::new(20., 5.0, 20.),
// high_bounds: Vec3::new(30., 10., 30.),
}
}
}

pub fn camera_controller(
time: Res<Time>,
mut mouse_events: EventReader<MouseMotion>,
mouse_button_input: Res<Input<MouseButton>>,
mut scroll_evr: EventReader<MouseWheel>,
key_input: Res<Input<KeyCode>>,
mut move_toggled: Local<bool>,
mut query: Query<
(&mut Transform, &mut CameraController),
With<Camera>,
>,
) {
let dt = time.delta_seconds();

if let Ok((mut transform, mut options)) =
query.get_single_mut()
{
if !options.initialized {
let (_roll, yaw, pitch) =
transform.rotation.to_euler(EulerRot::ZYX);
options.yaw = yaw;
options.pitch = pitch;
options.initialized = true;
}
if !options.enabled {
return;
}

let mut scroll_distance = 0.0;

// Handle scroll input
for ev in scroll_evr.read() {
match ev.unit {
MouseScrollUnit::Line => {
scroll_distance = ev.y;
}
MouseScrollUnit::Pixel => (),
}
}

// Handle mouse input
let mut mouse_delta = Vec2::ZERO;
if mouse_button_input
.pressed(options.mouse_key_enable_mouse)
|| *move_toggled
|| mouse_button_input
.pressed(options.mouse_key_enable_mouse_pan)
{
for mouse_event in mouse_events.read() {
mouse_delta += mouse_event.delta;
}
} else {
mouse_events.clear();
}

// Handle key input
let mut axis_input = Vec3::ZERO;

if key_input.pressed(options.key_forward) {
axis_input.z += 1.0;
}
if key_input.pressed(options.key_back) {
axis_input.z -= 1.0;
}
if key_input.pressed(options.key_right) {
axis_input.x += 1.0;
}
if key_input.pressed(options.key_left) {
axis_input.x -= 1.0;
}
if key_input.pressed(options.key_up) {
axis_input.y += 1.0;
}
if key_input.pressed(options.key_down) {
axis_input.y -= 1.0;
}
if key_input
.just_pressed(options.keyboard_key_enable_mouse)
{
*move_toggled = !*move_toggled;
}

// Apply movement update
if mouse_delta != Vec2::ZERO
&& mouse_button_input
.pressed(options.mouse_key_enable_mouse_pan)
{
//pan
options.velocity = Vec3::new(
-mouse_delta.x,
mouse_delta.y,
0.,
);
} else if axis_input != Vec3::ZERO {
let max_speed =
if key_input.pressed(options.key_run) {
options.run_speed
} else {
options.walk_speed
};
options.velocity =
axis_input.normalize() * max_speed;
} else {
let friction = options.friction.clamp(0.0, 1.0);
options.velocity *= 1.0 - friction;
if options.velocity.length_squared() < 1e-6 {
options.velocity = Vec3::ZERO;
}
}
let forward = transform.forward();
let right = transform.right();
let mut translation_delta =
options.velocity.x * dt * right
+ options.velocity.y * dt * Vec3::Y
+ options.velocity.z * dt * forward;
let mut scroll_translation = Vec3::ZERO;
if options.orbit_mode
&& options.scroll_wheel_speed > 0.0
{
scroll_translation = scroll_distance
* transform
.translation
.distance(options.orbit_focus)
* options.scroll_wheel_speed
* forward;
}
if options.lock_y {
translation_delta *= Vec3::new(1.0, 0.0, 1.0);
}
transform.translation +=
translation_delta + scroll_translation;
// bounds need to be calculated differently because bounding
// like this messes with the rotation *and* the zoom.
// transform.translation = transform
// .translation
// .min(options.high_bounds)
// .max(options.low_bounds);

options.orbit_focus += translation_delta;

if mouse_delta != Vec2::ZERO
&& (mouse_button_input
.pressed(options.mouse_key_enable_mouse)
|| *move_toggled)
{
let sensitivity = if options.orbit_mode {
options.sensitivity * 2.0
} else {
options.sensitivity
};
let (pitch, yaw) = (
(options.pitch
- mouse_delta.y
* 0.5
* sensitivity
* dt)
.clamp(
-0.99 * std::f32::consts::FRAC_PI_2,
0.99 * std::f32::consts::FRAC_PI_2,
),
options.yaw
- mouse_delta.x * sensitivity * dt,
);

// Apply look update
transform.rotation = Quat::from_euler(
EulerRot::ZYX,
0.0,
yaw,
pitch,
);
options.pitch = pitch;
options.yaw = yaw;

if options.orbit_mode {
let rot_matrix =
Mat3::from_quat(transform.rotation);
transform.translation = options.orbit_focus
+ rot_matrix.mul_vec3(Vec3::new(
0.0,
0.0,
options.orbit_focus.distance(
transform.translation,
),
));
}
}
}
}
9 changes: 9 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ use bevy::{
},
prelude::*,
};
use camera_controller::CameraController;
use std::f32::consts::PI;

pub mod brick;
pub mod camera_controller;
pub mod colors;
pub mod level;
pub mod materials;
Expand Down Expand Up @@ -54,5 +56,12 @@ pub fn setup(mut commands: Commands) {
},
BloomSettings::default(),
// CameraController::default(),
CameraController {
orbit_focus: Vec3::ZERO,
orbit_mode: true,
// scroll_wheel_speed: todo!(),
// lock_y: todo!(),
..default()
},
));
}
4 changes: 3 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use candy_blocks::{
highlight_colliding_cubes, BrickMaterialPlugin,
CustomMaterial,
},
camera_controller::CameraControllerPlugin,
level::{self, setup_game, GRID_AOC_TEST},
menu::MenuPlugin,
setup, AppState,
Expand Down Expand Up @@ -36,9 +37,10 @@ fn main() {
// CameraControllerPlugin,
TweeningPlugin,
DefaultPickingPlugins,
PhysicsDebugPlugin::default(),
// PhysicsDebugPlugin::default(),
MenuPlugin,
BrickMaterialPlugin,
CameraControllerPlugin,
))
.insert_resource(State::new(
DebugPickingMode::Disabled,
Expand Down

0 comments on commit f39c2c0

Please sign in to comment.