use colliders for wheels, fields for thrust and steering

This commit is contained in:
Joe Ardent 2024-06-18 19:10:23 -07:00
parent 94717dd60c
commit 0fae893508
3 changed files with 33 additions and 82 deletions

View file

@ -2,17 +2,13 @@ use std::f32::consts::{FRAC_PI_3, FRAC_PI_4};
use bevy::{ use bevy::{
prelude::{ prelude::{
info, Commands, Entity, Gizmos, Local, Quat, Query, Res, ResMut, Time, Transform, Vec3, info, Gizmos, Local, Quat, Query, Res, ResMut, Time, Transform, Vec3, With, Without,
With, Without,
}, },
render::color::Color, render::color::Color,
}; };
use bevy_rapier3d::{ use bevy_rapier3d::prelude::{
dynamics::MassProperties, ExternalForce, QueryFilter, RapierConfiguration, RapierContext, ReadMassProperties,
prelude::{ TimestepMode, Velocity,
CollisionGroups, ExternalForce, Group, MultibodyJoint, QueryFilter, RapierConfiguration,
RapierContext, ReadMassProperties, TimestepMode, Velocity,
},
}; };
#[cfg(feature = "inspector")] #[cfg(feature = "inspector")]
@ -21,7 +17,7 @@ use super::{
CatControllerSettings, CatControllerState, CyberLean, MovementSettings, PreviousVelocity, CatControllerSettings, CatControllerState, CyberLean, MovementSettings, PreviousVelocity,
}; };
use crate::{ use crate::{
bike::{CyberBikeBody, CyberSteering, CyberWheel, WheelConfig, BIKE_WHEEL_COLLISION_GROUP}, bike::{CyberBikeBody, CyberSteering, CyberWheel, WheelConfig},
input::InputState, input::InputState,
}; };
@ -138,93 +134,42 @@ pub(super) fn wheel_forces(
( (
&Transform, &Transform,
&Velocity, &Velocity,
&mut PreviousVelocity,
&mut ExternalForce, &mut ExternalForce,
Option<&CyberSteering>, Option<&CyberSteering>,
), ),
(With<CyberWheel>, Without<CyberBikeBody>), With<CyberWheel>,
>,
mut body_query: Query<
(
&Transform,
&Velocity,
&mut PreviousVelocity,
&ReadMassProperties,
),
(With<CyberBikeBody>, Without<CyberWheel>),
>, >,
wheel_config: Res<WheelConfig>, wheel_config: Res<WheelConfig>,
rapier_config: Res<RapierConfiguration>,
context: Res<RapierContext>, context: Res<RapierContext>,
settings: Res<MovementSettings>, settings: Res<MovementSettings>,
input: Res<InputState>, input: Res<InputState>,
mut gizmos: Gizmos, mut gizmos: Gizmos,
) { ) {
let (body_xform, body_vel, mut body_pvel, body_mass) = body_query.single_mut();
let gvec = rapier_config.gravity;
// body kinematics
let body_lin_accel = body_vel.linvel - body_pvel.0.linvel;
let body_ang_accel = body_vel.angvel - body_pvel.0.angvel;
let mut body_forward = body_vel
.linvel
.try_normalize()
.unwrap_or_else(|| body_xform.forward().normalize());
// we're just projecting onto the ground, so nuke the Y.
body_forward.y = 0.0;
let body_half_mass = body_mass.mass * 0.5;
let half_weight = settings.gravity * body_half_mass;
// wheel stuff // wheel stuff
let radius = wheel_config.radius; let radius = wheel_config.radius;
let squish_radius = 1.5 * radius;
// inputs // inputs
let steering = input.yaw; let steering = input.yaw;
let throttle = input.throttle * settings.accel; let throttle = input.throttle * settings.accel;
for (xform, vel, mut pvel, mut external_force, steering) in wheels_query.iter_mut() { for (xform, velocity, mut external_force, steering) in wheels_query.iter_mut() {
if let Some((_, projected)) = if let Some((_, projected)) =
context.project_point(xform.translation, false, QueryFilter::only_fixed()) context.project_point(xform.translation, false, QueryFilter::only_fixed())
{ {
//info!("projected point: {:?}", projected);
//dbg!("{:?}", projected);
let normal = (projected.point - xform.translation); let normal = (projected.point - xform.translation);
let len = normal.length(); let len = normal.length();
let normal = normal.normalize(); if len < radius {
if len < squish_radius { let mut force = Vec3::ZERO;
let squish = if len > radius { // do thrust's share
1.0 - ((len - radius) / (squish_radius - radius)).powi(2) let thrust = normal.cross(xform.left().into()) * throttle;
} else { force += thrust;
1.0
};
info!("squish: {squish}");
let grav_norm = gvec.normalize().dot(normal);
// we're in contact, first gravity
let normal = if projected.is_inside { Vec3::Y } else { normal };
let mut force = -1.1 * grav_norm * half_weight * normal;
// do linear acceleration's share // do steering's share
// f = ma
let lin_accel_norm = normal.dot(body_lin_accel.normalize());
force += body_mass.mass * lin_accel_norm * body_lin_accel;
// do angular accelerations's share? // do the friction's share
// do friction's share (depends on previous three)
// do thrust's share (depends on friction):
//
// let ef = ExternalForce::at_point(force, point,
// center_of_mass);
// do steering's share (also depends on friction)
// apply the squish factor
force *= squish;
// show the force // show the force
#[cfg(feature = "inspector")]
gizmos.arrow(xform.translation, force, Color::RED); gizmos.arrow(xform.translation, force, Color::RED);
// ok apply the force // ok apply the force
@ -233,8 +178,6 @@ pub(super) fn wheel_forces(
} }
} }
} }
body_pvel.0 = *body_vel;
} }
/// General velocity-based drag-force calculation; does not take orientation /// General velocity-based drag-force calculation; does not take orientation

View file

@ -1,13 +1,14 @@
use bevy::prelude::*; use bevy::prelude::*;
use bevy_rapier3d::{ use bevy_rapier3d::{
dynamics::{FixedJointBuilder, Velocity}, dynamics::{Ccd, FixedJointBuilder, Velocity},
geometry::{Collider, CollisionGroups, Friction},
prelude::{ prelude::{
ColliderMassProperties, ExternalForce, MultibodyJoint, PrismaticJointBuilder, RigidBody, ColliderMassProperties, ExternalForce, MultibodyJoint, PrismaticJointBuilder, RigidBody,
Sleeping, TransformInterpolation, Sleeping, TransformInterpolation,
}, },
}; };
use super::{CyberSteering, CyberWheel, Meshterial, WheelConfig}; use super::{CyberSteering, CyberWheel, Meshterial, WheelConfig, BIKE_WHEEL_COLLISION_GROUP};
use crate::action::PreviousVelocity; use crate::action::PreviousVelocity;
pub(crate) fn spawn_wheels( pub(crate) fn spawn_wheels(
@ -21,10 +22,14 @@ pub(crate) fn spawn_wheels(
let not_sleeping = Sleeping::disabled(); let not_sleeping = Sleeping::disabled();
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
let mut wheel_poses = Vec::with_capacity(2); let mut wheel_poses = Vec::with_capacity(2);
let (membership, filter) = BIKE_WHEEL_COLLISION_GROUP;
let wheels_collision_group = CollisionGroups::new(membership, filter);
// front // front
{ {
let wheel_x = 0.0; let wheel_x = 0.0;
@ -106,6 +111,13 @@ pub(crate) fn spawn_wheels(
SpatialBundle::default(), SpatialBundle::default(),
TransformInterpolation::default(), TransformInterpolation::default(),
RigidBody::Dynamic, RigidBody::Dynamic,
Ccd { enabled: true },
Friction {
coefficient: 0.0,
combine_rule: bevy_rapier3d::dynamics::CoefficientCombineRule::Min,
},
wheels_collision_group,
Collider::ball(conf.radius),
)); ));
} }
} }

View file

@ -18,11 +18,7 @@ fn spawn_planet(
let (mesh, shape) = gen_planet(2999.9); let (mesh, shape) = gen_planet(2999.9);
let pbody = ( let pbody = (RigidBody::Fixed, Transform::from_xyz(0.0, 0.1, 0.0));
RigidBody::Fixed,
Ccd { enabled: true },
Transform::from_xyz(0.0, 0.1, 0.0),
);
let pcollide = ( let pcollide = (
shape, shape,
@ -32,8 +28,8 @@ fn spawn_planet(
}, },
Restitution::new(0.8), Restitution::new(0.8),
Transform::from_xyz(0.0, 1.0, 0.0), Transform::from_xyz(0.0, 1.0, 0.0),
// same as the bike body CollisionGroups::default(), // all colliders
CollisionGroups::new(Group::GROUP_1, Group::GROUP_1), Ccd { enabled: true },
); );
commands commands