bouncy suspension, no friction
This commit is contained in:
parent
b8a54626a7
commit
c924428a9e
2 changed files with 128 additions and 12 deletions
23
src/bike.rs
23
src/bike.rs
|
@ -5,12 +5,15 @@ use bevy::prelude::*;
|
|||
|
||||
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)]
|
||||
pub struct CyberBikeBody;
|
||||
|
||||
#[derive(Component)]
|
||||
#[derive(Component, Clone, Copy, Debug)]
|
||||
pub enum CyberWheel {
|
||||
Front,
|
||||
Rear,
|
||||
|
@ -25,18 +28,23 @@ pub struct Steering;
|
|||
pub struct Rearing;
|
||||
|
||||
#[derive(Debug, Resource, Reflect)]
|
||||
#[reflect(Resource)]
|
||||
pub struct SuspensionConfig {
|
||||
pub rest_dist: f32,
|
||||
pub konstant: f32,
|
||||
pub damping: f32,
|
||||
pub front_attach: Vec3,
|
||||
pub rear_attach: Vec3,
|
||||
}
|
||||
|
||||
impl Default for SuspensionConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
rest_dist: REST_DISTANCE,
|
||||
konstant: 150.0,
|
||||
konstant: 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 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 body_collider =
|
||||
|
@ -86,8 +94,6 @@ fn spawn_bike(
|
|||
builder.parent_entity(),
|
||||
);
|
||||
});
|
||||
|
||||
//spawn_wheels(commands, meshes, materials, xform, bike);
|
||||
}
|
||||
|
||||
fn spawn_caster(
|
||||
|
@ -98,10 +104,10 @@ fn spawn_caster(
|
|||
parent: Entity,
|
||||
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]));
|
||||
|
||||
let mut entity = commands.spawn((caster, Transform::default()));
|
||||
let mut entity = commands.spawn((caster, xform));
|
||||
if is_front {
|
||||
entity.insert((Steering, Name::new("front wheel")));
|
||||
} else {
|
||||
|
@ -194,6 +200,7 @@ fn wheel_mesh(
|
|||
Mesh3d(meshes.add(tire_mesh)),
|
||||
MeshMaterial3d(materials.add(wheel_material.clone())),
|
||||
xform,
|
||||
LinearVelocity::ZERO,
|
||||
wheel,
|
||||
));
|
||||
}
|
||||
|
|
117
src/physics.rs
117
src/physics.rs
|
@ -62,10 +62,13 @@ mod systems {
|
|||
use std::f32::consts::{FRAC_PI_3, FRAC_PI_4};
|
||||
|
||||
use avian3d::prelude::*;
|
||||
use bevy::prelude::*;
|
||||
use bevy::{math::VectorSpace, prelude::*};
|
||||
|
||||
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 {
|
||||
let v = yaw.powi(5) * FRAC_PI_3;
|
||||
|
@ -166,9 +169,115 @@ mod systems {
|
|||
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;
|
||||
|
||||
|
@ -184,6 +293,6 @@ impl Plugin for CyberPhysicsPlugin {
|
|||
.add_systems(Startup, |mut gravity: ResMut<Gravity>| {
|
||||
gravity.0 *= 0.01;
|
||||
})
|
||||
.add_systems(Update, (apply_lean, calculate_lean));
|
||||
.add_systems(Update, (apply_lean, calculate_lean, suspension));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue