Compare commits

..

No commits in common. "eaba0edcd2aa1533b18ce0caaa529f1a6f21c0db" and "cc519efdb61456b1a17a9d1b3ce6cce10006d826" have entirely different histories.

2 changed files with 57 additions and 97 deletions

View file

@ -6,13 +6,13 @@ use bevy::prelude::*;
use crate::physics::CatControllerState; use crate::physics::CatControllerState;
pub const SPRING_CONSTANT: Scalar = 60.0; pub const SPRING_CONSTANT: Scalar = 50.0;
pub const DAMPING_CONSTANT: Scalar = 10.0; pub const DAMPING_CONSTANT: Scalar = 10.0;
pub const WHEEL_RADIUS: Scalar = 0.4; pub const WHEEL_RADIUS: Scalar = 0.4;
pub const REST_DISTANCE: Scalar = 1.5 + WHEEL_RADIUS; pub const REST_DISTANCE: Scalar = 1.0 + WHEEL_RADIUS;
pub const FRICTION_COEFF: Scalar = 0.9; pub const FRICTION_COEFF: Scalar = 0.8;
pub const FRONT_ATTACH: Vec3 = Vec3::new(0.0, 0.0, -0.5); 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.5); pub const REAR_ATTACH: Vec3 = Vec3::new(0.0, 0.0, 0.7);
#[derive(Component)] #[derive(Component)]
pub struct CyberBikeBody; pub struct CyberBikeBody;
@ -92,7 +92,7 @@ fn spawn_bike(
SleepingDisabled, SleepingDisabled,
CyberBikeBody, CyberBikeBody,
CatControllerState::default(), CatControllerState::default(),
ColliderDensity(1.2), ColliderDensity(0.6),
AngularDamping(0.2), AngularDamping(0.2),
LinearDamping(0.1), LinearDamping(0.1),
ExternalForce::ZERO.with_persistence(false), ExternalForce::ZERO.with_persistence(false),
@ -120,7 +120,7 @@ fn spawn_wheels(
) { ) {
let mesh: Mesh = Sphere::new(WHEEL_RADIUS).into(); let mesh: Mesh = Sphere::new(WHEEL_RADIUS).into();
let front_rake = Vec3::new(0.0, -1.0, -0.9).normalize(); // about 30 degrees let front_rake = Vec3::new(0.0, -1.0, -0.57).normalize(); // about 30 degrees
let front_wheel_pos = FRONT_ATTACH + (front_rake * REST_DISTANCE); let front_wheel_pos = FRONT_ATTACH + (front_rake * REST_DISTANCE);
wheel_caster( wheel_caster(
@ -148,7 +148,7 @@ fn spawn_wheels(
CyberWheel::Front, CyberWheel::Front,
); );
let rear_rake = Vec3::new(0.0, -1.0, 0.9).normalize(); let rear_rake = Vec3::new(0.0, -1.0, 0.57).normalize();
let rear_wheel_pos = REAR_ATTACH + (rear_rake * REST_DISTANCE); let rear_wheel_pos = REAR_ATTACH + (rear_rake * REST_DISTANCE);
wheel_caster( wheel_caster(

View file

@ -1,8 +1,6 @@
use avian3d::{math::Scalar, prelude::*}; use avian3d::prelude::*;
use bevy::prelude::*; use bevy::prelude::*;
const DRAG_COEFF: Scalar = 0.1;
#[derive(Resource, Default, Debug, Reflect)] #[derive(Resource, Default, Debug, Reflect)]
#[reflect(Resource)] #[reflect(Resource)]
struct CyberLean { struct CyberLean {
@ -20,9 +18,9 @@ pub struct CatControllerSettings {
impl Default for CatControllerSettings { impl Default for CatControllerSettings {
fn default() -> Self { fn default() -> Self {
Self { Self {
kp: 16.0, kp: 30.0,
kd: 2.0, kd: 7.0,
ki: 0.9, ki: 1.0,
} }
} }
} }
@ -31,6 +29,7 @@ impl Default for CatControllerSettings {
pub struct CatControllerState { pub struct CatControllerState {
pub roll_integral: f32, pub roll_integral: f32,
pub roll_prev: f32, pub roll_prev: f32,
decay_factor: f32,
roll_limit: f32, roll_limit: f32,
} }
@ -39,6 +38,7 @@ impl Default for CatControllerState {
Self { Self {
roll_integral: Default::default(), roll_integral: Default::default(),
roll_prev: Default::default(), roll_prev: Default::default(),
decay_factor: 0.99,
roll_limit: 1.5, roll_limit: 1.5,
} }
} }
@ -60,7 +60,7 @@ mod systems {
use avian3d::prelude::*; use avian3d::prelude::*;
use bevy::prelude::*; use bevy::prelude::*;
use super::{CatControllerSettings, CatControllerState, CyberLean, DRAG_COEFF}; use super::{CatControllerSettings, CatControllerState, CyberLean};
use crate::{ use crate::{
bike::{CyberBikeBody, CyberWheel, WheelConfig, WheelState, WHEEL_RADIUS}, bike::{CyberBikeBody, CyberWheel, WheelConfig, WheelState, WHEEL_RADIUS},
input::InputState, input::InputState,
@ -105,21 +105,13 @@ mod systems {
} }
pub(super) fn apply_lean( pub(super) fn apply_lean(
mut bike_query: Query<(&Transform, &mut ExternalForce, &mut CatControllerState)>, mut bike_query: Query<(&Transform, &mut ExternalTorque, &mut CatControllerState)>,
wheels: Query<&WheelState>,
time: Res<Time>, time: Res<Time>,
settings: Res<CatControllerSettings>, settings: Res<CatControllerSettings>,
lean: Res<CyberLean>, lean: Res<CyberLean>,
mut gizmos: Gizmos, mut gizmos: Gizmos,
) { ) {
let (xform, mut force, mut control_vars) = bike_query.single_mut(); let (xform, mut torque, mut control_vars) = bike_query.single_mut();
let mut factor = 1.0;
for wheel in wheels.iter() {
if wheel.contact_point.is_none() {
factor -= 0.25;
}
}
let world_up = Vec3::Y; //xform.translation.normalize(); let world_up = Vec3::Y; //xform.translation.normalize();
let rot = Quat::from_axis_angle(*xform.back(), lean.lean); let rot = Quat::from_axis_angle(*xform.back(), lean.lean);
@ -135,7 +127,7 @@ mod systems {
// show which is forward // show which is forward
gizmos.arrow( gizmos.arrow(
*xform.forward() + xform.translation, *xform.forward() + xform.translation,
2.5 * *xform.forward() + xform.translation, 1.5 * *xform.forward() + xform.translation,
bevy::color::palettes::basic::PURPLE, bevy::color::palettes::basic::PURPLE,
); );
@ -150,15 +142,11 @@ mod systems {
let mag = let mag =
(settings.kp * roll_error) + (settings.ki * integral) + (settings.kd * derivative); (settings.kp * roll_error) + (settings.ki * integral) + (settings.kd * derivative);
if mag.is_finite() { if mag.is_finite() {
let lean_force = factor * mag * *xform.left(); let tork = mag * *xform.back();
force.apply_force_at_point( torque.apply_torque(tork);
lean_force,
xform.translation + *xform.up(),
xform.translation,
);
gizmos.arrow( gizmos.arrow(
xform.translation + *xform.up(), xform.translation + Vec3::Y,
xform.translation + *xform.up() + lean_force, xform.translation + mag * *xform.right() + Vec3::Y,
Color::WHITE, Color::WHITE,
); );
} }
@ -251,12 +239,7 @@ mod systems {
pub(super) fn steering( pub(super) fn steering(
mut bike_query: Query< mut bike_query: Query<
( (&Transform, &mut ExternalForce, RigidBodyQueryReadOnly),
&Transform,
&LinearVelocity,
&mut ExternalForce,
RigidBodyQueryReadOnly,
),
With<CyberBikeBody>, With<CyberBikeBody>,
>, >,
mut wheels: Query<(&mut WheelState, &WheelConfig, &CyberWheel)>, mut wheels: Query<(&mut WheelState, &WheelConfig, &CyberWheel)>,
@ -264,16 +247,16 @@ mod systems {
input: Res<InputState>, input: Res<InputState>,
mut gizmos: Gizmos, mut gizmos: Gizmos,
) { ) {
let Ok((bike_xform, bike_vel, mut bike_force, bike_body)) = bike_query.get_single_mut() let Ok((bike_xform, mut bike_force, bike_body)) = bike_query.get_single_mut() else {
else {
bevy::log::warn!("No entity for bike_query."); bevy::log::warn!("No entity for bike_query.");
return; return;
}; };
let bike_vel = bike_vel.0;
let dt = time.delta().as_secs_f32(); let dt = time.delta().as_secs_f32();
let max_thrust = 2000.0; let max_thrust = 1000.0;
let yaw_angle = -yaw_to_angle(input.yaw); let thrust_force = input.throttle * max_thrust * dt;
let max_yaw = 500.0;
let yaw_force = input.yaw * max_yaw * dt;
for (mut state, config, wheel) in wheels.iter_mut() { for (mut state, config, wheel) in wheels.iter_mut() {
if let Some(contact_point) = state.contact_point { if let Some(contact_point) = state.contact_point {
@ -281,34 +264,45 @@ mod systems {
let normal = state.contact_normal.unwrap().normalize(); let normal = state.contact_normal.unwrap().normalize();
let max_force_mag = state.force_normal * config.friction; let max_force_mag = state.force_normal * config.friction;
let rot = Quat::from_axis_angle(normal, yaw_angle); let yaw_dir = match wheel {
let forward = normal.cross(*bike_xform.right()); CyberWheel::Front => normal.cross(*bike_xform.back()).normalize_or_zero(),
let thrust_mag = input.throttle * max_thrust * dt; CyberWheel::Rear => Vec3::ZERO,
let (thrust_dir, thrust_force) = match wheel {
CyberWheel::Rear => (forward, thrust_mag * 0.1),
CyberWheel::Front => (rot * forward, thrust_mag),
}; };
let thrust = thrust_force * thrust_dir; let thrust_dir = normal.cross(*bike_xform.right());
let friction_dir = match wheel {
CyberWheel::Front => normal.cross(thrust_dir),
CyberWheel::Rear => normal.cross(*bike_xform.forward()),
};
let vel = bike_body.velocity_at_point(contact_point - bike_xform.translation); let vel = bike_body.velocity_at_point(contact_point - bike_xform.translation);
let yaw = yaw_force * yaw_dir;
let thrust = thrust_force * thrust_dir;
let yust = yaw + thrust;
bevy::log::debug!("yust: {yust:?}");
bevy::log::debug!("{:?}", bike_xform.left());
let left = bike_xform.forward().cross(normal);
let friction_dir = match wheel {
CyberWheel::Front => {
if yaw_force + thrust_force > 0.1 {
normal.cross(yust.normalize()).normalize()
} else {
left
}
}
CyberWheel::Rear => left,
};
let friction_factor = -0.025 * vel.dot(friction_dir); let friction_factor = -0.025 * vel.dot(friction_dir);
let friction = (friction_factor / dt) * friction_dir; let friction = (friction_factor / dt) * friction_dir;
let diff = bike_vel - vel; let mut force = yust + friction;
bevy::log::debug!("{wheel:?}: vel diff: {diff:?} ({})", diff.length(),);
let mut force = thrust + friction;
force *= dt * 50.0; force *= dt * 50.0;
let force_mag = force.length(); let force_mag = force.length();
if force_mag > max_force_mag { if force_mag > max_force_mag {
state.sliding = true; state.sliding = true;
force = force.normalize_or_zero() * max_force_mag; force = force.normalize_or_zero() * max_force_mag;
//bevy::log::info!("clamping {wheel:?} to {max_force_mag}: {friction_factor}");
} else { } else {
state.sliding = false; state.sliding = false;
} }
@ -319,44 +313,10 @@ mod systems {
contact_point + friction, contact_point + friction,
Color::linear_rgb(1., 1., 0.2), Color::linear_rgb(1., 1., 0.2),
); );
gizmos.arrow(
contact_point,
contact_point + thrust,
Color::linear_rgb(1., 0., 0.2),
);
} }
} }
} }
pub(super) fn drag(
mut bike_query: Query<
(&Transform, &LinearVelocity, &mut ExternalForce),
With<CyberBikeBody>,
>,
mut gizmos: Gizmos,
time: Res<Time>,
) {
let (xform, vel, mut force) = bike_query.single_mut();
let dt = time.delta_secs();
let speed = vel.length();
let dspeed = speed.powf(1.2) * 0.1;
let dir = vel.normalize_or_zero();
let drag = -dspeed * dt * DRAG_COEFF * dir;
if speed > 1.0 {
force.apply_force_at_point(drag, xform.translation, xform.translation);
}
bevy::log::debug!("speed: {}, drag force: {}", speed, drag.length());
gizmos.arrow(
xform.translation,
xform.translation + drag * 10.,
Color::linear_rgb(1.0, 0.0, 0.0),
);
}
pub(super) fn tweak( pub(super) fn tweak(
mut config: Query<&mut WheelConfig>, mut config: Query<&mut WheelConfig>,
mut keys: ResMut<ButtonInput<KeyCode>>, mut keys: ResMut<ButtonInput<KeyCode>>,
@ -395,7 +355,7 @@ mod systems {
} }
} }
use systems::{apply_lean, calculate_lean, drag, steering, suspension, tweak}; use systems::{apply_lean, calculate_lean, steering, suspension, tweak};
pub struct CyberPhysicsPlugin; pub struct CyberPhysicsPlugin;
@ -413,7 +373,7 @@ impl Plugin for CyberPhysicsPlugin {
}) })
.add_systems( .add_systems(
FixedUpdate, FixedUpdate,
(calculate_lean, apply_lean, suspension, steering, drag).chain(), (calculate_lean, apply_lean, suspension, steering).chain(),
) )
.add_systems(Update, tweak); .add_systems(Update, tweak);
} }