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::<CatControllerSettings>()
.add_plugins((PhysicsPlugins::default(), FrameTimeDiagnosticsPlugin))
.insert_resource(SubstepCount(24))
.insert_resource(SubstepCount(6))
.add_systems(
Update,
(
gravity,
#[cfg(feature = "inspector")]
set_gravity,
clear_forces,
calculate_lean,
apply_lean,
//#[cfg(feature = "inspector")]
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 avian3d::{
collision::Collisions,
dynamics::solver::xpbd::AngularConstraint,
prelude::{
ColliderMassProperties, ExternalForce, ExternalTorque, Gravity, LinearVelocity,
ColliderMassProperties, Collision, ExternalForce, ExternalTorque, Gravity, LinearVelocity,
PrismaticJoint, RigidBodyQuery,
},
};
#[cfg(feature = "inspector")]
use bevy::prelude::Entity;
use bevy::prelude::{Quat, Query, Res, ResMut, Time, Transform, Vec3, With, Without};
use bevy::prelude::{EventReader, Quat, Query, Res, ResMut, Time, Transform, Vec3, With, Without};
use super::{CatControllerSettings, CatControllerState, CyberLean, MovementSettings};
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.
pub(super) fn gravity(
pub(super) fn set_gravity(
xform: Query<&Transform, With<CyberBikeBody>>,
settings: Res<MovementSettings>,
@ -46,20 +45,25 @@ pub(super) fn gravity(
) {
let xform = xform.single();
*gravity = Gravity(xform.translation.normalize() * -settings.gravity);
// clear all external forces
}
pub(super) fn clear_forces(mut forces: Query<(&mut ExternalForce, &mut ExternalTorque)>) {
for (mut force, mut torque) in forces.iter_mut() {
force.clear();
torque.clear();
pub(super) fn clear_forces(
mut forces: Query<(Option<&mut ExternalForce>, Option<&mut ExternalTorque>)>,
) {
for (force, torque) in forces.iter_mut() {
if let Some(mut force) = force {
force.clear();
}
if let Some(mut torque) = torque {
torque.clear();
}
}
}
pub(super) fn suspension(
movment_settings: Res<MovementSettings>,
wheel_config: Res<WheelConfig>,
time: Res<Time>,
mass: Query<&ColliderMassProperties, With<CyberBikeBody>>,
mut axels: Query<(&mut ExternalForce, &CyberSpring, &Transform)>,
) {
@ -68,17 +72,19 @@ pub(super) fn suspension(
} else {
1.0
};
let dt = time.delta_seconds();
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() {
let spring = mag * spring.0;
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.
pub(super) fn cyber_lean(
pub(super) fn calculate_lean(
bike_state: Query<(&LinearVelocity, &Transform), With<CyberBikeBody>>,
wheels: Query<&Transform, With<CyberWheel>>,
input: Res<InputState>,
@ -104,7 +110,7 @@ pub(super) fn cyber_lean(
}
/// 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)>,
time: Res<Time>,
settings: Res<CatControllerSettings>,
@ -132,7 +138,7 @@ pub(super) fn falling_cat(
}
/// Apply forces to the cyberbike as a result of input.
pub(super) fn input_forces(
pub(super) fn apply_inputs(
settings: Res<MovementSettings>,
input: Res<InputState>,
time: Res<Time>,
@ -159,7 +165,8 @@ pub(super) fn input_forces(
let thrust = xform.forward() * input.throttle * settings.accel;
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
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);
}
#[cfg(feature = "inspector")]
pub(super) fn debug_bodies(bodies: Query<(Entity, RigidBodyQuery)>) {
for (entity, rbq) in bodies.iter().filter(|(_, r)| r.rb.is_dynamic()) {
let line = format!("{entity:?} at {:?}", rbq.current_position());
bevy::log::info!(line);
//#[cfg(feature = "inspector")]
mod inspector {
use bevy::prelude::Entity;
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);
}
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,
};
use super::{spawn_wheels, CyberBikeBody, Meshterial, WheelConfig, BIKE_BODY_COLLISION_GROUP};
use crate::{action::CatControllerState, planet::PLANET_RADIUS};
use super::{spawn_wheels, CyberBikeBody, Meshterial, WheelConfig};
use crate::{action::CatControllerState, planet::PLANET_RADIUS, ColliderGroups};
pub(super) fn spawn_cyberbike(
mut commands: Commands,
@ -32,8 +32,8 @@ pub(super) fn spawn_cyberbike(
..Default::default()
};
let (membership, filter) = BIKE_BODY_COLLISION_GROUP;
let bike_collision_group = CollisionLayers::new(membership, filter);
let bike_collision_group =
CollisionLayers::new(ColliderGroups::BikeBody, ColliderGroups::Planet);
let scene = asset_server.load("cb-no-y_up.glb#Scene0");
@ -50,7 +50,7 @@ pub(super) fn spawn_cyberbike(
SleepingDisabled,
CyberBikeBody,
CatControllerState::default(),
ColliderDensity(0.6),
ColliderDensity(0.06),
LinearDamping(0.1),
AngularDamping(2.0),
LinearVelocity::ZERO,
@ -66,5 +66,7 @@ pub(super) fn spawn_cyberbike(
})
.id();
bevy::log::info!("bike body: {bike:?}");
spawn_wheels(&mut commands, bike, &xform, &wheel_conf, &mut meshterials);
}

View file

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

View file

@ -1,10 +1,8 @@
use avian3d::prelude::*;
use bevy::prelude::{Torus as Tire, *};
use super::{
CyberFork, CyberSpring, CyberSteering, CyberWheel, Meshterial, WheelConfig,
BIKE_WHEEL_COLLISION_GROUP,
};
use super::{CyberFork, CyberSpring, CyberSteering, CyberWheel, Meshterial, WheelConfig};
use crate::ColliderGroups;
pub fn spawn_wheels(
commands: &mut Commands,
@ -13,11 +11,11 @@ pub fn spawn_wheels(
conf: &WheelConfig,
meshterials: &mut Meshterial,
) {
let (membership, filter) = BIKE_WHEEL_COLLISION_GROUP;
let wheels_collision_group = CollisionLayers::new(membership, filter);
let wheels_collision_group =
CollisionLayers::new(ColliderGroups::Wheels, ColliderGroups::Planet);
let wheel_y = conf.y;
let not_sleeping = SleepingDisabled;
let ccd = SweptCcd::NON_LINEAR.include_dynamic(false);
let ccd = SweptCcd::LINEAR.include_dynamic(false);
let limits = conf.limits;
let (meshes, materials) = meshterials;
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(),
RigidBody::Dynamic,
ColliderDensity(0.1),
CollisionMargin(0.1),
AngularVelocity::ZERO,
ExternalTorque::ZERO,
))
@ -91,43 +90,40 @@ pub fn spawn_wheels(
.id();
let spring = CyberSpring(suspension_axis);
let axel = if let Some(steering) = steering {
let axle = if let Some(steering) = steering {
commands.spawn((
RigidBody::Dynamic,
ExternalForce::ZERO,
steering,
spring,
Collider::sphere(0.1),
ColliderDensity(0.1),
CollisionLayers::from_bits(0, 0),
MassPropertiesBundle::new_computed(&Collider::sphere(0.1), 0.1),
))
} else {
commands.spawn((
RigidBody::Dynamic,
ExternalForce::ZERO,
spring,
Collider::sphere(0.1),
ColliderDensity(0.1),
CollisionLayers::from_bits(0, 0),
MassPropertiesBundle::new_computed(&Collider::sphere(0.1), 0.1),
))
}
.insert(SpatialBundle::from_transform(
xform.with_translation(xform.translation + offset),
))
.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);
// suspension and steering:
if steering.is_some() {
let joint = PrismaticJoint::new(axel, bike)
let joint = PrismaticJoint::new(axle, bike)
.with_free_axis(suspension_axis)
.with_local_anchor_1(Vec3::new(0.0, 0.0, 0.1))
.with_local_anchor_2(offset)
.with_limits(limits[0], limits[1]);
commands.spawn((joint, CyberFork));
} else {
let joint = PrismaticJoint::new(axel, bike)
let joint = PrismaticJoint::new(axle, bike)
.with_free_axis(suspension_axis)
.with_local_anchor_2(offset)
.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) {
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)
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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