bouncy suspension, no friction

This commit is contained in:
Joe Ardent 2025-02-18 22:24:44 -08:00
parent b8a54626a7
commit c924428a9e
2 changed files with 128 additions and 12 deletions

View file

@ -5,12 +5,15 @@ use bevy::prelude::*;
use crate::physics::CatControllerState; use crate::physics::CatControllerState;
pub const REST_DISTANCE: f32 = 0.8; pub const REST_DISTANCE: f32 = 1.0;
pub const WHEEL_RADIUS: f32 = 0.4;
pub const FRONT_ATTACH: Vec3 = Vec3::new(0.0, 0.0, -0.7);
pub const REAR_ATTACH: Vec3 = Vec3::new(0.0, 0.0, 0.7);
#[derive(Component)] #[derive(Component)]
pub struct CyberBikeBody; pub struct CyberBikeBody;
#[derive(Component)] #[derive(Component, Clone, Copy, Debug)]
pub enum CyberWheel { pub enum CyberWheel {
Front, Front,
Rear, Rear,
@ -25,18 +28,23 @@ pub struct Steering;
pub struct Rearing; pub struct Rearing;
#[derive(Debug, Resource, Reflect)] #[derive(Debug, Resource, Reflect)]
#[reflect(Resource)]
pub struct SuspensionConfig { pub struct SuspensionConfig {
pub rest_dist: f32, pub rest_dist: f32,
pub konstant: f32, pub konstant: f32,
pub damping: f32, pub damping: f32,
pub front_attach: Vec3,
pub rear_attach: Vec3,
} }
impl Default for SuspensionConfig { impl Default for SuspensionConfig {
fn default() -> Self { fn default() -> Self {
Self { Self {
rest_dist: REST_DISTANCE, rest_dist: REST_DISTANCE,
konstant: 150.0, konstant: 50.0,
damping: 50.0, damping: 50.0,
front_attach: FRONT_ATTACH,
rear_attach: REAR_ATTACH,
} }
} }
} }
@ -46,7 +54,7 @@ fn spawn_bike(
mut meshes: ResMut<Assets<Mesh>>, mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>, mut materials: ResMut<Assets<StandardMaterial>>,
) { ) {
let pos = Vec3::new(0.0, 24.0, 0.0); let pos = Vec3::new(0.0, 4.0, 0.0);
let xform = Transform::from_translation(pos); //.with_rotation(Quat::from_rotation_z(0.0)); let xform = Transform::from_translation(pos); //.with_rotation(Quat::from_rotation_z(0.0));
let body_collider = let body_collider =
@ -86,8 +94,6 @@ fn spawn_bike(
builder.parent_entity(), builder.parent_entity(),
); );
}); });
//spawn_wheels(commands, meshes, materials, xform, bike);
} }
fn spawn_caster( fn spawn_caster(
@ -98,10 +104,10 @@ fn spawn_caster(
parent: Entity, parent: Entity,
is_front: bool, is_front: bool,
) { ) {
let caster = ShapeCaster::new(collider, xform.translation, Quat::IDENTITY, direction) let caster = ShapeCaster::new(collider, Vec3::ZERO, Quat::IDENTITY, direction)
.with_query_filter(SpatialQueryFilter::from_excluded_entities([parent])); .with_query_filter(SpatialQueryFilter::from_excluded_entities([parent]));
let mut entity = commands.spawn((caster, Transform::default())); let mut entity = commands.spawn((caster, xform));
if is_front { if is_front {
entity.insert((Steering, Name::new("front wheel"))); entity.insert((Steering, Name::new("front wheel")));
} else { } else {
@ -194,6 +200,7 @@ fn wheel_mesh(
Mesh3d(meshes.add(tire_mesh)), Mesh3d(meshes.add(tire_mesh)),
MeshMaterial3d(materials.add(wheel_material.clone())), MeshMaterial3d(materials.add(wheel_material.clone())),
xform, xform,
LinearVelocity::ZERO,
wheel, wheel,
)); ));
} }

View file

@ -62,10 +62,13 @@ mod systems {
use std::f32::consts::{FRAC_PI_3, FRAC_PI_4}; use std::f32::consts::{FRAC_PI_3, FRAC_PI_4};
use avian3d::prelude::*; use avian3d::prelude::*;
use bevy::prelude::*; use bevy::{math::VectorSpace, prelude::*};
use super::{CatControllerSettings, CatControllerState, CyberLean}; use super::{CatControllerSettings, CatControllerState, CyberLean};
use crate::{bike::CyberBikeBody, input::InputState}; use crate::{
bike::{CyberBikeBody, CyberWheel, Rearing, Steering, SuspensionConfig},
input::InputState,
};
fn _yaw_to_angle(yaw: f32) -> f32 { fn _yaw_to_angle(yaw: f32) -> f32 {
let v = yaw.powi(5) * FRAC_PI_3; let v = yaw.powi(5) * FRAC_PI_3;
@ -166,9 +169,115 @@ mod systems {
0.0 0.0
} }
} }
pub(super) fn suspension(
mut bike_body_query: Query<(&Transform, &mut ExternalForce), With<CyberBikeBody>>,
mut wheel_mesh_query: Query<
(&mut Transform, &LinearVelocity, &CyberWheel),
Without<CyberBikeBody>,
>,
front_wheel_query: Query<(&ShapeCaster, &ShapeHits), (With<Steering>, Without<Rearing>)>,
rear_wheel_query: Query<(&ShapeCaster, &ShapeHits), (With<Rearing>, Without<Steering>)>,
config: Res<SuspensionConfig>,
) {
let mut front_wheel_xform = None;
let mut rear_wheel_xform = None;
let mut front_wheel_vel = Vec3::ZERO;
let mut rear_wheel_vel = Vec3::ZERO;
for (xform, vel, wheel) in wheel_mesh_query.iter_mut() {
match wheel {
CyberWheel::Front => {
front_wheel_xform = Some(xform);
front_wheel_vel = **vel;
}
CyberWheel::Rear => {
rear_wheel_xform = Some(xform);
rear_wheel_vel = **vel;
}
}
}
let (bike_xform, mut bike_forces) = bike_body_query.single_mut();
for (caster, hits) in front_wheel_query.iter() {
for hit in hits.iter() {
if let Some(ref mut xform) = front_wheel_xform {
let force = suspension_force(
caster,
hit,
&config,
front_wheel_vel,
xform,
bike_xform.rotation,
true,
);
bike_forces.apply_force_at_point(
force,
caster.global_origin(),
bike_xform.translation,
);
}
}
}
for (caster, hits) in rear_wheel_query.iter() {
for hit in hits.iter() {
if let Some(ref mut xform) = rear_wheel_xform {
let force = suspension_force(
caster,
hit,
&config,
rear_wheel_vel,
xform,
bike_xform.rotation,
false,
);
bike_forces.apply_force_at_point(
force,
caster.global_origin(),
bike_xform.translation,
);
}
}
}
}
fn suspension_force(
caster: &ShapeCaster,
hit: &ShapeHitData,
config: &SuspensionConfig,
wheel_vel: Vec3,
wheel_xform: &mut Transform,
rotation: Quat,
is_front: bool,
) -> Vec3 {
let mut loc = Vec3::ZERO;
let mut up_force = Vec3::ZERO;
let attach = if is_front {
config.front_attach
} else {
config.rear_attach
};
let dist = hit.distance;
let cdir = caster.direction.as_vec3();
let dir = rotation.mul_vec3(cdir);
if dist < config.rest_dist {
loc = attach + (cdir * dist);
let displacement = config.rest_dist - dist;
let damper_vel = dir.dot(wheel_vel);
let mag = config.konstant * displacement - config.damping * damper_vel;
up_force = -dir * mag;
} else {
loc = attach + (cdir * config.rest_dist);
}
wheel_xform.translation = loc;
up_force
}
} }
use systems::{apply_lean, calculate_lean}; use systems::{apply_lean, calculate_lean, suspension};
pub struct CyberPhysicsPlugin; pub struct CyberPhysicsPlugin;
@ -184,6 +293,6 @@ impl Plugin for CyberPhysicsPlugin {
.add_systems(Startup, |mut gravity: ResMut<Gravity>| { .add_systems(Startup, |mut gravity: ResMut<Gravity>| {
gravity.0 *= 0.01; gravity.0 *= 0.01;
}) })
.add_systems(Update, (apply_lean, calculate_lean)); .add_systems(Update, (apply_lean, calculate_lean, suspension));
} }
} }