replicates bevy_flycam demo

This commit is contained in:
Joe Ardent 2021-11-05 22:32:55 -07:00
commit c7452bba11
6 changed files with 3569 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/target
.#*

3361
Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

9
Cargo.toml Normal file
View file

@ -0,0 +1,9 @@
[package]
name = "cyber_rider"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bevy = { path = "../bevy" }

152
src/flycam.rs Normal file
View file

@ -0,0 +1,152 @@
use bevy::app::{Events, ManualEventReader};
use bevy::input::mouse::MouseMotion;
use bevy::prelude::*;
// stolen with neither shame nor pity from git@github.com:sburris0/bevy_flycam.git, b90f6fc, which is copyright 2020 Spencer Burris
/// Keeps track of mouse motion events, pitch, and yaw
#[derive(Default)]
struct InputState {
reader_motion: ManualEventReader<MouseMotion>,
pitch: f32,
yaw: f32,
}
/// Mouse sensitivity and movement speed
pub struct MovementSettings {
pub sensitivity: f32,
pub speed: f32,
}
impl Default for MovementSettings {
fn default() -> Self {
Self {
sensitivity: 0.00012,
speed: 12.,
}
}
}
/// Used in queries when you want flycams and not other cameras
#[derive(Debug, Component)]
pub struct FlyCam;
/// Grabs/ungrabs mouse cursor
fn toggle_grab_cursor(window: &mut Window) {
window.set_cursor_lock_mode(!window.cursor_locked());
window.set_cursor_visibility(!window.cursor_visible());
}
/// Grabs the cursor when game first starts
fn initial_grab_cursor(mut windows: ResMut<Windows>) {
toggle_grab_cursor(windows.get_primary_mut().unwrap());
}
/// Spawns the `Camera3dBundle` to be controlled
fn setup_player(mut commands: Commands) {
commands
.spawn_bundle(PerspectiveCameraBundle {
transform: Transform::from_xyz(-2.0, 5.0, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
..Default::default()
})
.insert(FlyCam);
}
/// Handles keyboard input and movement
fn player_move(
keys: Res<Input<KeyCode>>,
time: Res<Time>,
windows: Res<Windows>,
settings: Res<MovementSettings>,
mut query: Query<(&FlyCam, &mut Transform)>,
) {
let window = windows.get_primary().unwrap();
for (_camera, mut transform) in query.iter_mut() {
let mut velocity = Vec3::ZERO;
let local_z = transform.local_z();
let forward = -Vec3::new(local_z.x, 0., local_z.z);
let right = Vec3::new(local_z.z, 0., -local_z.x);
for key in keys.get_pressed() {
if window.cursor_locked() {
match key {
KeyCode::W => velocity += forward,
KeyCode::S => velocity -= forward,
KeyCode::A => velocity -= right,
KeyCode::D => velocity += right,
KeyCode::Space => velocity += Vec3::Y,
KeyCode::LShift => velocity -= Vec3::Y,
_ => (),
}
}
}
velocity = velocity.normalize();
if !velocity.is_nan() {
transform.translation += velocity * time.delta_seconds() * settings.speed
}
}
}
/// Handles looking around if cursor is locked
fn player_look(
settings: Res<MovementSettings>,
windows: Res<Windows>,
mut state: ResMut<InputState>,
motion: Res<Events<MouseMotion>>,
mut query: Query<(&FlyCam, &mut Transform)>,
) {
let window = windows.get_primary().unwrap();
for (_camera, mut transform) in query.iter_mut() {
for ev in state.reader_motion.iter(&motion) {
if window.cursor_locked() {
// Using smallest of height or width ensures equal vertical and horizontal sensitivity
let window_scale = window.height().min(window.width());
state.pitch -= (settings.sensitivity * ev.delta.y * window_scale).to_radians();
state.yaw -= (settings.sensitivity * ev.delta.x * window_scale).to_radians();
}
state.pitch = state.pitch.clamp(-1.54, 1.54);
// Order is important to prevent unintended roll
transform.rotation = Quat::from_axis_angle(Vec3::Y, state.yaw)
* Quat::from_axis_angle(Vec3::X, state.pitch);
}
}
}
fn cursor_grab(keys: Res<Input<KeyCode>>, mut windows: ResMut<Windows>) {
let window = windows.get_primary_mut().unwrap();
if keys.just_pressed(KeyCode::Escape) {
toggle_grab_cursor(window);
}
}
/// Contains everything needed to add first-person fly camera behavior to your game
pub struct PlayerPlugin;
impl Plugin for PlayerPlugin {
fn build(&self, app: &mut App) {
app.init_resource::<InputState>()
.init_resource::<MovementSettings>()
.add_startup_system(setup_player.system())
.add_startup_system(initial_grab_cursor.system())
.add_system(player_move.system())
.add_system(player_look.system())
.add_system(cursor_grab.system());
}
}
/// Same as `PlayerPlugin` but does not spawn a camera
pub struct NoCameraPlayerPlugin;
impl Plugin for NoCameraPlayerPlugin {
fn build(&self, app: &mut App) {
app.init_resource::<InputState>()
.init_resource::<MovementSettings>()
.add_startup_system(initial_grab_cursor.system())
.add_system(player_move.system())
.add_system(player_look.system())
.add_system(cursor_grab.system());
}
}

1
src/lib.rs Normal file
View file

@ -0,0 +1 @@
pub mod flycam;

44
src/main.rs Normal file
View file

@ -0,0 +1,44 @@
use bevy::prelude::*;
use cyber_rider::flycam::MovementSettings;
use cyber_rider::flycam::PlayerPlugin;
// stolen with neither shame nor pity from git@github.com:sburris0/bevy_flycam.git, b90f6fc, which is copyright 2020 Spencer Burris
fn main() {
App::new()
.insert_resource(Msaa { samples: 4 })
.add_plugins(DefaultPlugins)
.add_plugin(PlayerPlugin)
.insert_resource(MovementSettings {
sensitivity: 0.00015, // default: 0.00012
speed: 12.0, // default: 12.0
})
.add_startup_system(setup.system())
.run();
}
/// set up a simple 3D scene
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// plane
commands.spawn_bundle(PbrBundle {
mesh: meshes.add(Mesh::from(shape::Plane { size: 5.0 })),
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
..Default::default()
});
// cube
commands.spawn_bundle(PbrBundle {
mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()),
transform: Transform::from_xyz(0.0, 0.5, 0.0),
..Default::default()
});
// light
commands.spawn_bundle(PointLightBundle {
transform: Transform::from_xyz(4.0, 8.0, 4.0),
..Default::default()
});
}