Add collision detection, reaction, and gravity.

This commit is contained in:
Joe Ardent 2022-01-06 23:58:38 -08:00
parent 2885be2003
commit f53cd2f848
2 changed files with 73 additions and 68 deletions

View file

@ -15,17 +15,12 @@ use heron::{
pub const PLANET_RADIUS: f32 = 75.0; pub const PLANET_RADIUS: f32 = 75.0;
const PLAYER_DIST: f32 = PLANET_RADIUS + 100.0; const PLAYER_DIST: f32 = PLANET_RADIUS + 100.0;
const CAM_DIST: f32 = 30.0; const CAM_DIST: f32 = 50.0;
#[derive(Component, Default)] #[derive(Component, Default)]
struct PlayerState { struct PlayerState {
velocity: Vec3, velocity: Vec3,
} colliding: bool,
#[derive(Default)]
struct UpState {
player_up: Vec3,
cam_up: Vec3,
} }
#[derive(Default)] #[derive(Default)]
@ -49,7 +44,7 @@ impl Default for MovementSettings {
Self { Self {
sensitivity: 1.0, sensitivity: 1.0,
accel: 40., accel: 40.,
drag: 0.05, drag: 0.0005,
gravity: 10.0, gravity: 10.0,
} }
} }
@ -123,28 +118,20 @@ fn setup_dbg_ui(mut commands: Commands, asset_server: Res<AssetServer>) {
.insert(UpText); .insert(UpText);
} }
fn dbg_ui_system(state: Res<UpState>, mut query: Query<&mut Text, With<UpText>>) { fn ui_system(pstate_query: Query<&PlayerState>, mut text_query: Query<&mut Text, With<UpText>>) {
let cos = state.player_up.dot(state.cam_up); let mut text = text_query.single_mut();
let pstate = pstate_query.single();
let mut text = query.single_mut(); text.sections[0].value = format!("{:.2}", pstate.velocity.length());
text.sections[0].value = format!(
"up: {:?}\ncam_up: {:?}\ntheta: {:.2}",
state.player_up,
state.cam_up,
cos.acos().to_degrees()
);
} }
fn player_move( fn player_move(
time: Res<Time>, time: Res<Time>,
_settings: Res<MovementSettings>, mut bike_query: Query<(&mut Transform, &PlayerState), Without<FlyCam>>,
mut up_state: ResMut<UpState>,
mut bike_query: Query<(&mut Transform, &mut PlayerState), Without<FlyCam>>,
mut cam_query: Query<(&mut Transform, &FlyCam), Without<PlayerState>>, mut cam_query: Query<(&mut Transform, &FlyCam), Without<PlayerState>>,
) { ) {
let dt = time.delta_seconds(); let dt = time.delta_seconds();
let (mut bike_xform, mut player_state) = bike_query.single_mut(); let (mut bike_xform, player_state) = bike_query.single_mut();
let up = bike_xform.translation.normalize(); let up = bike_xform.translation.normalize();
let cam_up = bike_xform.up(); let cam_up = bike_xform.up();
let cos = up.dot(cam_up); let cos = up.dot(cam_up);
@ -170,15 +157,9 @@ fn player_move(
} }
if player_state.velocity.is_finite() { if player_state.velocity.is_finite() {
//state.velocity += -up * settings.gravity * dt;
bike_xform.translation += player_state.velocity * dt; bike_xform.translation += player_state.velocity * dt;
} else {
//state.velocity = -up * settings.gravity * dt;
} }
up_state.cam_up = cam_up;
up_state.player_up = up;
let (mut cam_xform, _) = cam_query.single_mut(); let (mut cam_xform, _) = cam_query.single_mut();
cam_xform.translation = bike_xform.translation + (up * CAM_DIST); cam_xform.translation = bike_xform.translation + (up * CAM_DIST);
cam_xform.look_at(bike_xform.translation, Vec3::Y); cam_xform.look_at(bike_xform.translation, Vec3::Y);
@ -247,26 +228,49 @@ fn player_look(
transform.rotate(rotation); transform.rotate(rotation);
//dbg!(&vel);
pstate.velocity = vel; pstate.velocity = vel;
} }
fn cursor_grab( fn collision_detection(
keys: Res<Input<KeyCode>>, mut events: EventReader<CollisionEvent>,
mut windows: ResMut<Windows>, mut query: Query<&mut PlayerState>,
mut query: Query<(&FlyCam, &mut Transform)>,
) { ) {
let window = windows.get_primary_mut().unwrap(); let mut pstate = query.single_mut();
if keys.just_pressed(KeyCode::L) {
let (_, mut transform) = query.single_mut(); for event in events.iter() {
*transform.as_mut() = transform.looking_at(Vec3::ZERO, Vec3::Y); if let CollisionEvent::Started(_, _) = event {
pstate.colliding = true;
} else {
pstate.colliding = false;
}
} }
if keys.just_pressed(KeyCode::U) { }
let lock = !window.cursor_locked();
window.set_cursor_lock_mode(lock); fn gravity_collision_reaction(
window.set_cursor_visibility(lock); time: Res<Time>,
settings: Res<MovementSettings>,
mut query: Query<(&mut PlayerState, &Transform)>,
) {
let dt = time.delta_seconds();
let g = settings.gravity;
let (mut pstate, xform) = query.single_mut();
// first gravity
let down = -xform.translation.normalize();
let dvel = down * g * dt;
let mut vel = if pstate.velocity.is_finite() {
pstate.velocity + dvel
} else {
dvel
};
// now see if we're currently colliding
if pstate.colliding {
let dvel = down * vel.dot(down) * 1.02;
vel -= dvel;
} }
pstate.velocity = vel;
} }
/// Contains everything needed to add first-person fly camera behavior to your /// Contains everything needed to add first-person fly camera behavior to your
@ -277,12 +281,12 @@ impl Plugin for PlayerPlugin {
app.init_resource::<PlayerState>() app.init_resource::<PlayerState>()
.init_resource::<MovementSettings>() .init_resource::<MovementSettings>()
.init_resource::<InputState>() .init_resource::<InputState>()
.init_resource::<UpState>()
.add_startup_system(setup_player) .add_startup_system(setup_player)
.add_startup_system(setup_dbg_ui) .add_startup_system(setup_dbg_ui)
.add_system(dbg_ui_system) .add_system(ui_system)
.add_system(player_move.label("move")) .add_system(player_move.label("move"))
.add_system(player_look.after("move")) .add_system(player_look.after("move"))
.add_system(cursor_grab); .add_system(collision_detection)
.add_system(gravity_collision_reaction);
} }
} }

View file

@ -1,13 +1,8 @@
use bevy::prelude::*; use bevy::prelude::*;
use cyber_rider::flycam::{MovementSettings, PlayerPlugin, PLANET_RADIUS}; use cyber_rider::flycam::{MovementSettings, PlayerPlugin, PLANET_RADIUS};
use heron::prelude::*;
/* const LIGHT_RANGE: f32 = PLANET_RADIUS * 0.6;
stolen with neither shame nor pity from
git@github.com:sburris0/bevy_flycam.git, b90f6fc, which is copyright 2020
Spencer Burris
*/
const LIGHT_RANGE: f32 = PLANET_RADIUS * 2.2;
const LIGHT_DIST: f32 = PLANET_RADIUS * 1.2; const LIGHT_DIST: f32 = PLANET_RADIUS * 1.2;
fn main() { fn main() {
@ -15,6 +10,7 @@ fn main() {
.insert_resource(Msaa { samples: 4 }) .insert_resource(Msaa { samples: 4 })
.add_plugins(DefaultPlugins) .add_plugins(DefaultPlugins)
.add_plugin(PlayerPlugin) .add_plugin(PlayerPlugin)
.add_plugin(PhysicsPlugin::default())
.insert_resource(MovementSettings { .insert_resource(MovementSettings {
sensitivity: 0.3, // default: 1.0 sensitivity: 0.3, // default: 1.0
accel: 20.0, // default: 40.0 accel: 20.0, // default: 40.0
@ -43,21 +39,21 @@ fn setup(
mut materials: ResMut<Assets<StandardMaterial>>, mut materials: ResMut<Assets<StandardMaterial>>,
) { ) {
let red_light = PointLight { let red_light = PointLight {
intensity: 5_000.0, intensity: 1_000.0,
range: LIGHT_RANGE, range: LIGHT_RANGE,
color: Color::RED, color: Color::RED,
..Default::default() ..Default::default()
}; };
let blue_light = PointLight { let blue_light = PointLight {
intensity: 5_000.0, intensity: 1_000.0,
range: LIGHT_RANGE, range: LIGHT_RANGE,
color: Color::BLUE, color: Color::BLUE,
..Default::default() ..Default::default()
}; };
let purple_light = PointLight { let purple_light = PointLight {
intensity: 5_000.0, intensity: 1_000.0,
range: LIGHT_RANGE, range: LIGHT_RANGE,
color: Color::PURPLE, color: Color::PURPLE,
..Default::default() ..Default::default()
@ -69,20 +65,25 @@ fn setup(
}); });
// world // world
commands.spawn_bundle(PbrBundle { commands
mesh: meshes.add(Mesh::from(shape::Icosphere { .spawn_bundle(PbrBundle {
radius: PLANET_RADIUS, mesh: meshes.add(Mesh::from(shape::Icosphere {
subdivisions: 6, radius: PLANET_RADIUS,
})), subdivisions: 6,
material: materials.add(StandardMaterial { })),
base_color: Color::GRAY, material: materials.add(StandardMaterial {
metallic: 0.7, base_color: Color::GRAY,
perceptual_roughness: 0.5, metallic: 0.7,
..Default::default() perceptual_roughness: 0.5,
}), ..Default::default()
}),
..Default::default() ..Default::default()
}); })
.insert(RigidBody::Static)
.insert(CollisionShape::Sphere {
radius: PLANET_RADIUS,
});
// east light // east light
commands commands