checkpoint

This commit is contained in:
Joe Ardent 2024-07-18 14:55:09 -07:00
parent aef303ca71
commit dd65741d7b
11 changed files with 115 additions and 61 deletions

View file

@ -29,15 +29,18 @@ impl Plugin for CyberActionPlugin {
.register_type::<CyberLean>() .register_type::<CyberLean>()
.register_type::<CatControllerSettings>() .register_type::<CatControllerSettings>()
.add_plugins((PhysicsPlugins::default(), FrameTimeDiagnosticsPlugin)) .add_plugins((PhysicsPlugins::default(), FrameTimeDiagnosticsPlugin))
.insert_resource(SubstepCount(24)) .insert_resource(SubstepCount(6))
.add_systems( .add_systems(
Update, Update,
( (
gravity, set_gravity,
#[cfg(feature = "inspector")] clear_forces,
calculate_lean,
apply_lean,
//#[cfg(feature = "inspector")]
debug_bodies, debug_bodies,
(cyber_lean, suspension, falling_cat, input_forces).after(clear_forces), )
), .chain(),
); );
} }
} }

View file

@ -1,15 +1,14 @@
use std::f32::consts::{FRAC_PI_3, FRAC_PI_4}; use std::f32::consts::{FRAC_PI_3, FRAC_PI_4};
use avian3d::{ use avian3d::{
collision::Collisions,
dynamics::solver::xpbd::AngularConstraint, dynamics::solver::xpbd::AngularConstraint,
prelude::{ prelude::{
ColliderMassProperties, ExternalForce, ExternalTorque, Gravity, LinearVelocity, ColliderMassProperties, Collision, ExternalForce, ExternalTorque, Gravity, LinearVelocity,
PrismaticJoint, RigidBodyQuery, PrismaticJoint, RigidBodyQuery,
}, },
}; };
#[cfg(feature = "inspector")] use bevy::prelude::{EventReader, Quat, Query, Res, ResMut, Time, Transform, Vec3, With, Without};
use bevy::prelude::Entity;
use bevy::prelude::{Quat, Query, Res, ResMut, Time, Transform, Vec3, With, Without};
use super::{CatControllerSettings, CatControllerState, CyberLean, MovementSettings}; use super::{CatControllerSettings, CatControllerState, CyberLean, MovementSettings};
use crate::{ use crate::{
@ -38,7 +37,7 @@ fn rotate_point(pt: &Vec3, rot: &Quat) -> Vec3 {
} }
/// The gravity vector points from the cyberbike to the center of the planet. /// The gravity vector points from the cyberbike to the center of the planet.
pub(super) fn gravity( pub(super) fn set_gravity(
xform: Query<&Transform, With<CyberBikeBody>>, xform: Query<&Transform, With<CyberBikeBody>>,
settings: Res<MovementSettings>, settings: Res<MovementSettings>,
@ -46,20 +45,25 @@ pub(super) fn gravity(
) { ) {
let xform = xform.single(); let xform = xform.single();
*gravity = Gravity(xform.translation.normalize() * -settings.gravity); *gravity = Gravity(xform.translation.normalize() * -settings.gravity);
// clear all external forces
} }
pub(super) fn clear_forces(mut forces: Query<(&mut ExternalForce, &mut ExternalTorque)>) { pub(super) fn clear_forces(
for (mut force, mut torque) in forces.iter_mut() { mut forces: Query<(Option<&mut ExternalForce>, Option<&mut ExternalTorque>)>,
) {
for (force, torque) in forces.iter_mut() {
if let Some(mut force) = force {
force.clear(); force.clear();
}
if let Some(mut torque) = torque {
torque.clear(); torque.clear();
} }
}
} }
pub(super) fn suspension( pub(super) fn suspension(
movment_settings: Res<MovementSettings>, movment_settings: Res<MovementSettings>,
wheel_config: Res<WheelConfig>, wheel_config: Res<WheelConfig>,
time: Res<Time>,
mass: Query<&ColliderMassProperties, With<CyberBikeBody>>, mass: Query<&ColliderMassProperties, With<CyberBikeBody>>,
mut axels: Query<(&mut ExternalForce, &CyberSpring, &Transform)>, mut axels: Query<(&mut ExternalForce, &CyberSpring, &Transform)>,
) { ) {
@ -68,17 +72,19 @@ pub(super) fn suspension(
} else { } else {
1.0 1.0
}; };
let dt = time.delta_seconds();
let gravity = movment_settings.gravity; let gravity = movment_settings.gravity;
let mag = -wheel_config.stiffness * mass * gravity; let mag = -wheel_config.stiffness * mass * gravity * dt;
for (mut force, spring, xform) in axels.iter_mut() { for (mut force, spring, xform) in axels.iter_mut() {
let spring = mag * spring.0; let spring = mag * spring.0;
let spring = xform.translation + spring; let spring = xform.translation + spring;
let _ = force.apply_force(spring); bevy::log::info!("suspension force: {spring:?}");
//let _ = force.apply_force(spring);
} }
} }
/// The desired lean angle, given steering input and speed. /// The desired lean angle, given steering input and speed.
pub(super) fn cyber_lean( pub(super) fn calculate_lean(
bike_state: Query<(&LinearVelocity, &Transform), With<CyberBikeBody>>, bike_state: Query<(&LinearVelocity, &Transform), With<CyberBikeBody>>,
wheels: Query<&Transform, With<CyberWheel>>, wheels: Query<&Transform, With<CyberWheel>>,
input: Res<InputState>, input: Res<InputState>,
@ -104,7 +110,7 @@ pub(super) fn cyber_lean(
} }
/// PID-based controller for stabilizing attitude; keeps the cyberbike upright. /// PID-based controller for stabilizing attitude; keeps the cyberbike upright.
pub(super) fn falling_cat( pub(super) fn apply_lean(
mut bike_query: Query<(&Transform, &mut ExternalTorque, &mut CatControllerState)>, mut bike_query: Query<(&Transform, &mut ExternalTorque, &mut CatControllerState)>,
time: Res<Time>, time: Res<Time>,
settings: Res<CatControllerSettings>, settings: Res<CatControllerSettings>,
@ -132,7 +138,7 @@ pub(super) fn falling_cat(
} }
/// Apply forces to the cyberbike as a result of input. /// Apply forces to the cyberbike as a result of input.
pub(super) fn input_forces( pub(super) fn apply_inputs(
settings: Res<MovementSettings>, settings: Res<MovementSettings>,
input: Res<InputState>, input: Res<InputState>,
time: Res<Time>, time: Res<Time>,
@ -159,7 +165,8 @@ pub(super) fn input_forces(
let thrust = xform.forward() * input.throttle * settings.accel; let thrust = xform.forward() * input.throttle * settings.accel;
let point = xform.translation + *xform.back(); let point = xform.translation + *xform.back();
let _ = *forces.apply_force_at_point(dt * thrust, point, mass.center_of_mass.0); //let _ = *forces.apply_force_at_point(dt * thrust, point,
// mass.center_of_mass.0);
// brake + thrust // brake + thrust
for mut motor in braking_query.iter_mut() { for mut motor in braking_query.iter_mut() {
@ -188,10 +195,41 @@ pub(super) fn input_forces(
fork.align_orientation(&mut axle, &mut bike, diff, &mut compliance, 1.0, dt); fork.align_orientation(&mut axle, &mut bike, diff, &mut compliance, 1.0, dt);
} }
#[cfg(feature = "inspector")] //#[cfg(feature = "inspector")]
pub(super) fn debug_bodies(bodies: Query<(Entity, RigidBodyQuery)>) { mod inspector {
for (entity, rbq) in bodies.iter().filter(|(_, r)| r.rb.is_dynamic()) { use bevy::prelude::Entity;
let line = format!("{entity:?} at {:?}", rbq.current_position());
use super::*;
pub(crate) fn debug_bodies(
bodies: Query<(Entity, RigidBodyQuery)>,
mut collisions: EventReader<Collision>,
) {
let bodies: Vec<_> = bodies.iter().collect();
for i in 0..(bodies.len()) {
let (ent, ref rb) = bodies[i];
let cur_pos = rb.current_position();
let mut max = 0.0f32;
let mut min = f32::MAX;
for j in 0..(bodies.len()) {
if j == i {
continue;
}
let (_, ref other) = bodies[j];
let dist = (cur_pos - other.current_position()).length();
max = max.max(dist);
min = min.min(dist);
}
let line = format!("{ent:?} at {cur_pos:?} -- min: {min}, max: {max}");
bevy::log::info!(line); bevy::log::info!(line);
} }
for Collision(contacts) in collisions.read() {
bevy::log::info!(
"Entities {:?} and {:?} are colliding",
contacts.entity1,
contacts.entity2,
);
}
}
} }
//#[cfg(feature = "inspector")]
pub(super) use inspector::debug_bodies;

View file

@ -4,8 +4,8 @@ use bevy::{
scene::SceneBundle, scene::SceneBundle,
}; };
use super::{spawn_wheels, CyberBikeBody, Meshterial, WheelConfig, BIKE_BODY_COLLISION_GROUP}; use super::{spawn_wheels, CyberBikeBody, Meshterial, WheelConfig};
use crate::{action::CatControllerState, planet::PLANET_RADIUS}; use crate::{action::CatControllerState, planet::PLANET_RADIUS, ColliderGroups};
pub(super) fn spawn_cyberbike( pub(super) fn spawn_cyberbike(
mut commands: Commands, mut commands: Commands,
@ -32,8 +32,8 @@ pub(super) fn spawn_cyberbike(
..Default::default() ..Default::default()
}; };
let (membership, filter) = BIKE_BODY_COLLISION_GROUP; let bike_collision_group =
let bike_collision_group = CollisionLayers::new(membership, filter); CollisionLayers::new(ColliderGroups::BikeBody, ColliderGroups::Planet);
let scene = asset_server.load("cb-no-y_up.glb#Scene0"); let scene = asset_server.load("cb-no-y_up.glb#Scene0");
@ -50,7 +50,7 @@ pub(super) fn spawn_cyberbike(
SleepingDisabled, SleepingDisabled,
CyberBikeBody, CyberBikeBody,
CatControllerState::default(), CatControllerState::default(),
ColliderDensity(0.6), ColliderDensity(0.06),
LinearDamping(0.1), LinearDamping(0.1),
AngularDamping(2.0), AngularDamping(2.0),
LinearVelocity::ZERO, LinearVelocity::ZERO,
@ -66,5 +66,7 @@ pub(super) fn spawn_cyberbike(
}) })
.id(); .id();
bevy::log::info!("bike body: {bike:?}");
spawn_wheels(&mut commands, bike, &xform, &wheel_conf, &mut meshterials); spawn_wheels(&mut commands, bike, &xform, &wheel_conf, &mut meshterials);
} }

View file

@ -10,8 +10,8 @@ use bevy::{
pub(crate) use self::components::*; pub(crate) use self::components::*;
use self::{body::spawn_cyberbike, wheels::spawn_wheels}; use self::{body::spawn_cyberbike, wheels::spawn_wheels};
pub const BIKE_BODY_COLLISION_GROUP: (u32, u32) = (0b01, 0b01); pub const BIKE_BODY_COLLISION_GROUP: (u32, u32) = (1, 1);
pub const BIKE_WHEEL_COLLISION_GROUP: (u32, u32) = (0b10, 0b10); pub const BIKE_WHEEL_COLLISION_GROUP: (u32, u32) = (2, 2);
type Meshterial<'a> = ( type Meshterial<'a> = (
ResMut<'a, Assets<Mesh>>, ResMut<'a, Assets<Mesh>>,

View file

@ -1,10 +1,8 @@
use avian3d::prelude::*; use avian3d::prelude::*;
use bevy::prelude::{Torus as Tire, *}; use bevy::prelude::{Torus as Tire, *};
use super::{ use super::{CyberFork, CyberSpring, CyberSteering, CyberWheel, Meshterial, WheelConfig};
CyberFork, CyberSpring, CyberSteering, CyberWheel, Meshterial, WheelConfig, use crate::ColliderGroups;
BIKE_WHEEL_COLLISION_GROUP,
};
pub fn spawn_wheels( pub fn spawn_wheels(
commands: &mut Commands, commands: &mut Commands,
@ -13,11 +11,11 @@ pub fn spawn_wheels(
conf: &WheelConfig, conf: &WheelConfig,
meshterials: &mut Meshterial, meshterials: &mut Meshterial,
) { ) {
let (membership, filter) = BIKE_WHEEL_COLLISION_GROUP; let wheels_collision_group =
let wheels_collision_group = CollisionLayers::new(membership, filter); CollisionLayers::new(ColliderGroups::Wheels, ColliderGroups::Planet);
let wheel_y = conf.y; let wheel_y = conf.y;
let not_sleeping = SleepingDisabled; let not_sleeping = SleepingDisabled;
let ccd = SweptCcd::NON_LINEAR.include_dynamic(false); let ccd = SweptCcd::LINEAR.include_dynamic(false);
let limits = conf.limits; let limits = conf.limits;
let (meshes, materials) = meshterials; let (meshes, materials) = meshterials;
let rake_vec: Vec3 = Vec3::new(0.0, 1.0, 0.57).normalize(); // about 30 degrees of rake let rake_vec: Vec3 = Vec3::new(0.0, 1.0, 0.57).normalize(); // about 30 degrees of rake
@ -82,6 +80,7 @@ pub fn spawn_wheels(
SpatialBundle::default(), SpatialBundle::default(),
RigidBody::Dynamic, RigidBody::Dynamic,
ColliderDensity(0.1), ColliderDensity(0.1),
CollisionMargin(0.1),
AngularVelocity::ZERO, AngularVelocity::ZERO,
ExternalTorque::ZERO, ExternalTorque::ZERO,
)) ))
@ -91,43 +90,40 @@ pub fn spawn_wheels(
.id(); .id();
let spring = CyberSpring(suspension_axis); let spring = CyberSpring(suspension_axis);
let axel = if let Some(steering) = steering { let axle = if let Some(steering) = steering {
commands.spawn(( commands.spawn((
RigidBody::Dynamic, RigidBody::Dynamic,
ExternalForce::ZERO, ExternalForce::ZERO,
steering, steering,
spring, spring,
Collider::sphere(0.1), MassPropertiesBundle::new_computed(&Collider::sphere(0.1), 0.1),
ColliderDensity(0.1),
CollisionLayers::from_bits(0, 0),
)) ))
} else { } else {
commands.spawn(( commands.spawn((
RigidBody::Dynamic, RigidBody::Dynamic,
ExternalForce::ZERO, ExternalForce::ZERO,
spring, spring,
Collider::sphere(0.1), MassPropertiesBundle::new_computed(&Collider::sphere(0.1), 0.1),
ColliderDensity(0.1),
CollisionLayers::from_bits(0, 0),
)) ))
} }
.insert(SpatialBundle::from_transform( .insert(SpatialBundle::from_transform(
xform.with_translation(xform.translation + offset), xform.with_translation(xform.translation + offset),
)) ))
.id(); .id();
let axel_joint = RevoluteJoint::new(axel, wheel).with_aligned_axis(Vec3::NEG_X); bevy::log::info!("axle RB: {axle:?}");
let axel_joint = RevoluteJoint::new(axle, wheel).with_aligned_axis(Vec3::NEG_X);
commands.spawn(axel_joint); commands.spawn(axel_joint);
// suspension and steering: // suspension and steering:
if steering.is_some() { if steering.is_some() {
let joint = PrismaticJoint::new(axel, bike) let joint = PrismaticJoint::new(axle, bike)
.with_free_axis(suspension_axis) .with_free_axis(suspension_axis)
.with_local_anchor_1(Vec3::new(0.0, 0.0, 0.1)) .with_local_anchor_1(Vec3::new(0.0, 0.0, 0.1))
.with_local_anchor_2(offset) .with_local_anchor_2(offset)
.with_limits(limits[0], limits[1]); .with_limits(limits[0], limits[1]);
commands.spawn((joint, CyberFork)); commands.spawn((joint, CyberFork));
} else { } else {
let joint = PrismaticJoint::new(axel, bike) let joint = PrismaticJoint::new(axle, bike)
.with_free_axis(suspension_axis) .with_free_axis(suspension_axis)
.with_local_anchor_2(offset) .with_local_anchor_2(offset)
.with_limits(limits[0], limits[1]); .with_limits(limits[0], limits[1]);
@ -168,7 +164,7 @@ fn gen_tires(conf: &WheelConfig) -> (Mesh, Collider) {
for idx in indices.as_slice().chunks_exact(3) { for idx in indices.as_slice().chunks_exact(3) {
idxs.push([idx[0] as u32, idx[1] as u32, idx[2] as u32]); idxs.push([idx[0] as u32, idx[1] as u32, idx[2] as u32]);
} }
let wheel_collider = Collider::convex_decomposition_from_mesh(&mesh).unwrap(); let wheel_collider = Collider::trimesh_from_mesh(&mesh).unwrap();
(mesh, wheel_collider) (mesh, wheel_collider)
} }

View file

@ -44,12 +44,15 @@ fn setup_cybercams(mut commands: Commands) {
..Default::default() ..Default::default()
}; };
commands let id = commands
.spawn(Camera3dBundle { .spawn(Camera3dBundle {
projection: bevy::render::camera::Projection::Perspective(hero_projection), projection: bevy::render::camera::Projection::Perspective(hero_projection),
..Default::default() ..Default::default()
}) })
.insert(CyberCameras::Hero); .insert(CyberCameras::Hero)
.id();
commands.spawn(TargetCamera(id));
commands commands
.spawn(Camera3dBundle::default()) .spawn(Camera3dBundle::default())

View file

@ -2,6 +2,7 @@ use avian3d::debug_render::PhysicsGizmos;
use bevy::{ use bevy::{
color::Srgba, color::Srgba,
gizmos::AppGizmoBuilder, gizmos::AppGizmoBuilder,
math::Vec3,
prelude::{App, Color, GizmoConfig, Plugin}, prelude::{App, Color, GizmoConfig, Plugin},
}; };
@ -20,6 +21,8 @@ impl Plugin for CyberGlamorPlugin {
PhysicsGizmos { PhysicsGizmos {
contact_point_color: Some(Srgba::GREEN.into()), contact_point_color: Some(Srgba::GREEN.into()),
contact_normal_color: Some(Srgba::WHITE.into()), contact_normal_color: Some(Srgba::WHITE.into()),
hide_meshes: true,
axis_lengths: Some(Vec3::ZERO),
..Default::default() ..Default::default()
}, },
GizmoConfig::default(), GizmoConfig::default(),

View file

@ -1,3 +1,4 @@
use avian3d::prelude::PhysicsLayer;
use bevy::{ use bevy::{
prelude::{Query, Vec3, Window, With}, prelude::{Query, Vec3, Window, With},
window::PrimaryWindow, window::PrimaryWindow,
@ -12,6 +13,13 @@ pub mod lights;
pub mod planet; pub mod planet;
pub mod ui; pub mod ui;
#[derive(PhysicsLayer)]
pub enum ColliderGroups {
BikeBody,
Wheels,
Planet,
}
pub fn disable_mouse_trap(mut window: Query<&mut Window, With<PrimaryWindow>>) { pub fn disable_mouse_trap(mut window: Query<&mut Window, With<PrimaryWindow>>) {
let mut window = window.get_single_mut().unwrap(); let mut window = window.get_single_mut().unwrap();
window.cursor.grab_mode = bevy::window::CursorGrabMode::None; window.cursor.grab_mode = bevy::window::CursorGrabMode::None;

View file

@ -32,7 +32,7 @@ fn spawn_static_lights(
commands.insert_resource(AmbientLight { commands.insert_resource(AmbientLight {
color: Color::WHITE, color: Color::WHITE,
brightness: 0.2, brightness: 10_000.0,
}); });
let _cascade_shadow_config = CascadeShadowConfigBuilder { let _cascade_shadow_config = CascadeShadowConfigBuilder {

View file

@ -41,7 +41,7 @@ fn spawn_planet(
RigidBody::Static, RigidBody::Static,
pcollide, pcollide,
CyberPlanet, CyberPlanet,
CollisionLayers::new(u32::MAX, u32::MAX), CollisionLayers::new(LayerMask::ALL, LayerMask::ALL),
CollisionMargin(0.2), CollisionMargin(0.2),
)); ));
} }

View file

@ -3,8 +3,9 @@ use bevy::{
app::{Startup, Update}, app::{Startup, Update},
prelude::{ prelude::{
AlignSelf, App, AssetServer, Color, Commands, Component, Plugin, Query, Res, Style, Text, AlignSelf, App, AssetServer, Color, Commands, Component, Plugin, Query, Res, Style, Text,
TextBundle, TextSection, TextStyle, Transform, With, TextBundle, TextSection, TextStyle, With,
}, },
ui::TargetCamera,
}; };
use crate::bike::CyberBikeBody; use crate::bike::CyberBikeBody;
@ -34,16 +35,16 @@ fn setup_ui(mut commands: Commands, asset_server: Res<AssetServer>) {
}, },
..Default::default() ..Default::default()
}) })
.insert(UpText); .insert((UpText, TargetCamera));
} }
fn update_ui( fn update_ui(
state_query: Query<(&LinearVelocity, &Transform), With<CyberBikeBody>>, state_query: Query<&LinearVelocity, With<CyberBikeBody>>,
mut text_query: Query<&mut Text, With<UpText>>, mut text_query: Query<&mut Text, With<UpText>>,
) { ) {
let mut text = text_query.single_mut(); let mut text = text_query.single_mut();
let (velocity, xform) = state_query.single(); let velocity = state_query.single();
let speed = velocity.dot(*xform.forward()); let speed = velocity.0.length();
text.sections[0].value = format!("spd: {:.2}", speed); text.sections[0].value = format!("spd: {:.2}", speed);
} }