checkpoint, frictionless wheels

This commit is contained in:
Joe Ardent 2024-06-15 14:18:17 -07:00
parent 3b307f4389
commit 59f0ed89e9
10 changed files with 141 additions and 161 deletions

View file

@ -4,6 +4,7 @@ use bevy::{
prelude::{Component, ReflectResource, Resource, Vec3}, prelude::{Component, ReflectResource, Resource, Vec3},
reflect::Reflect, reflect::Reflect,
}; };
use bevy_rapier3d::dynamics::Velocity;
#[derive(Debug, Resource)] #[derive(Debug, Resource)]
pub(crate) struct ActionDebugInstant(pub Instant); pub(crate) struct ActionDebugInstant(pub Instant);
@ -26,20 +27,8 @@ impl ActionDebugInstant {
} }
} }
#[derive(Debug, Component)] #[derive(Debug, Component, Default)]
pub(super) struct Tunneling { pub struct PreviousVelocity(pub Velocity);
pub frames: usize,
pub dir: Vec3,
}
impl Default for Tunneling {
fn default() -> Self {
Tunneling {
frames: 15,
dir: Vec3::Y,
}
}
}
#[derive(Debug, Resource, Reflect)] #[derive(Debug, Resource, Reflect)]
#[reflect(Resource)] #[reflect(Resource)]

View file

@ -29,18 +29,17 @@ impl Plugin for CyberActionPlugin {
.register_type::<CyberLean>() .register_type::<CyberLean>()
.register_type::<CatControllerSettings>() .register_type::<CatControllerSettings>()
.add_plugins(RapierPhysicsPlugin::<NoUserData>::default()) .add_plugins(RapierPhysicsPlugin::<NoUserData>::default())
.add_systems(Startup, timestep_setup) .add_systems(Startup, physics_init)
.add_plugins(FrameTimeDiagnosticsPlugin::default()) .add_plugins(FrameTimeDiagnosticsPlugin)
.add_systems( .add_systems(
Update, Update,
( (
gravity, reset_body_force,
reset_wheel_forces,
cyber_lean, cyber_lean,
falling_cat, falling_cat,
input_forces, input_forces,
drag, drag,
//tunnel_out,
//surface_fix,
) )
.chain(), .chain(),
); );

View file

@ -3,67 +3,60 @@ use std::f32::consts::{FRAC_PI_3, FRAC_PI_4};
use bevy::prelude::{ use bevy::prelude::{
Commands, Entity, Local, Quat, Query, Res, ResMut, Time, Transform, Vec3, With, Without, Commands, Entity, Local, Quat, Query, Res, ResMut, Time, Transform, Vec3, With, Without,
}; };
use bevy_rapier3d::prelude::{ use bevy_rapier3d::{
dynamics::MassProperties,
prelude::{
CollisionGroups, ExternalForce, Group, MultibodyJoint, QueryFilter, RapierConfiguration, CollisionGroups, ExternalForce, Group, MultibodyJoint, QueryFilter, RapierConfiguration,
RapierContext, ReadMassProperties, TimestepMode, Velocity, RapierContext, ReadMassProperties, TimestepMode, Velocity,
},
}; };
#[cfg(feature = "inspector")] #[cfg(feature = "inspector")]
use super::ActionDebugInstant; use super::ActionDebugInstant;
use super::{CatControllerSettings, CatControllerState, CyberLean, MovementSettings, Tunneling}; use super::{
CatControllerSettings, CatControllerState, CyberLean, MovementSettings, PreviousVelocity,
};
use crate::{ use crate::{
bike::{CyberBikeBody, CyberSteering, CyberWheel, WheelConfig, BIKE_WHEEL_COLLISION_GROUP}, bike::{CyberBikeBody, CyberSteering, CyberWheel, WheelConfig, BIKE_WHEEL_COLLISION_GROUP},
input::InputState, input::InputState,
}; };
fn yaw_to_angle(yaw: f32) -> f32 { pub(super) fn physics_init(
let v = yaw.powi(5) * FRAC_PI_4; mut config: ResMut<RapierConfiguration>,
if v.is_normal() {
v
} else {
0.0
}
}
fn rotate_point(pt: &Vec3, rot: &Quat) -> Vec3 {
// thanks to https://danceswithcode.net/engineeringnotes/quaternions/quaternions.html
let [x, y, z] = pt.normalize().to_array();
let qpt = Quat::from_xyzw(x, y, z, 0.0);
// p' = rot^-1 * qpt * rot
let rot_qpt = rot.inverse() * qpt * *rot;
// why does this need to be inverted???
-Vec3::from_array([rot_qpt.x, rot_qpt.y, rot_qpt.z])
}
pub(super) fn timestep_setup(mut config: ResMut<RapierConfiguration>) {
let ts = TimestepMode::Fixed {
dt: 1.0 / 60.0,
substeps: 2,
};
config.timestep_mode = ts;
}
/// The gravity vector points from the cyberbike to the center of the planet.
pub(super) fn gravity(
mut query: Query<(&Transform, &mut ExternalForce), With<CyberBikeBody>>,
settings: Res<MovementSettings>, settings: Res<MovementSettings>,
mut rapier_config: ResMut<RapierConfiguration>, ) {
config.timestep_mode = TimestepMode::Variable {
max_dt: 1.0 / 60.0,
time_scale: 1.0,
substeps: 3,
};
config.gravity = Vec3::NEG_Y * settings.gravity;
}
pub(super) fn reset_body_force(
mut query: Query<&mut ExternalForce, With<CyberBikeBody>>,
#[cfg(feature = "inspector")] mut debug_instant: ResMut<ActionDebugInstant>, #[cfg(feature = "inspector")] mut debug_instant: ResMut<ActionDebugInstant>,
) { ) {
let (xform, mut forces) = query.single_mut(); let mut body_force = query.single_mut();
#[cfg(feature = "inspector")] #[cfg(feature = "inspector")]
{ {
if debug_instant.elapsed().as_millis() > 6000 { if debug_instant.elapsed().as_millis() > 1000 {
dbg!(&forces); //dbg!(&body_force);
debug_instant.reset(); debug_instant.reset();
} }
} }
rapier_config.gravity = Vec3::Y * -settings.gravity; body_force.force = Vec3::ZERO;
forces.force = Vec3::ZERO; body_force.torque = Vec3::ZERO;
forces.torque = Vec3::ZERO; }
pub(super) fn reset_wheel_forces(mut query: Query<&mut ExternalForce, With<CyberWheel>>) {
for mut force in query.iter_mut() {
force.force = Vec3::ZERO;
force.torque = Vec3::ZERO;
}
} }
/// The desired lean angle, given steering input and speed. /// The desired lean angle, given steering input and speed.
@ -117,8 +110,8 @@ pub(super) fn falling_cat(
if *count < 30 { if *count < 30 {
if *count == 0 { if *count == 0 {
dbg!(&xform.translation); //dbg!(&xform.translation);
dbg!(&vel.linvel); //dbg!(&vel.linvel);
} }
*count += 1; *count += 1;
} else { } else {
@ -141,10 +134,7 @@ pub(super) fn input_forces(
settings: Res<MovementSettings>, settings: Res<MovementSettings>,
input: Res<InputState>, input: Res<InputState>,
mut braking_query: Query<&mut MultibodyJoint, (Without<CyberSteering>, With<CyberWheel>)>, mut braking_query: Query<&mut MultibodyJoint, (Without<CyberSteering>, With<CyberWheel>)>,
mut body_query: Query< mut body_query: Query<(&Transform, &mut ExternalForce), With<CyberBikeBody>>,
(&Transform, &mut ExternalForce),
(With<CyberBikeBody>, Without<CyberSteering>),
>,
mut steering_query: Query<&mut MultibodyJoint, With<CyberSteering>>, mut steering_query: Query<&mut MultibodyJoint, With<CyberSteering>>,
) { ) {
let (xform, mut forces) = body_query.single_mut(); let (xform, mut forces) = body_query.single_mut();
@ -156,21 +146,21 @@ pub(super) fn input_forces(
*forces += force; *forces += force;
// brake + thrust // brake + thrust
for mut motor in braking_query.iter_mut() { // for mut motor in braking_query.iter_mut() {
let factor = if input.brake { // let factor = if input.brake {
500.00 // 500.00
} else { // } else {
input.throttle * settings.accel // input.throttle * settings.accel
}; // };
let speed = if input.brake { 0.0 } else { -70.0 }; // let speed = if input.brake { 0.0 } else { -70.0 };
motor.data = (*motor // motor.data = (*motor
.data // .data
.as_revolute_mut() // .as_revolute_mut()
.unwrap() // .unwrap()
.set_motor_max_force(factor) // .set_motor_max_force(factor)
.set_motor_velocity(speed, factor)) // .set_motor_velocity(speed, factor))
.into(); // .into();
} // }
// steering // steering
let angle = yaw_to_angle(input.yaw); let angle = yaw_to_angle(input.yaw);
@ -183,13 +173,32 @@ pub(super) fn input_forces(
.into(); .into();
} }
pub(super) fn wheel_forces(
mut wheels_query: Query<(&Transform, &Velocity, &mut PreviousVelocity), With<CyberWheel>>,
mut body_query: Query<
(
&Transform,
&Velocity,
&mut PreviousVelocity,
&ReadMassProperties,
),
With<CyberBikeBody>,
>,
config: Res<WheelConfig>,
context: Res<RapierContext>,
) {
let (body_xform, body_vel, mut body_pvel, body_mass) = body_query.single_mut();
for (xform, vel, mut pvel) in wheels_query.iter_mut() {
//
}
body_pvel.0 = *body_vel;
}
/// Don't let the wheels get stuck underneat the planet /// Don't let the wheels get stuck underneat the planet
pub(super) fn surface_fix( pub(super) fn surface_fix(
mut commands: Commands, mut wheel_query: Query<(Entity, &Transform, &mut CollisionGroups), With<CyberWheel>>,
mut wheel_query: Query<
(Entity, &Transform, &mut CollisionGroups),
(With<CyberWheel>, Without<Tunneling>),
>,
span_query: Query<&Transform, With<CyberWheel>>, span_query: Query<&Transform, With<CyberWheel>>,
config: Res<WheelConfig>, config: Res<WheelConfig>,
context: Res<RapierContext>, context: Res<RapierContext>,
@ -212,43 +221,10 @@ pub(super) fn surface_fix(
) { ) {
//cgroups.memberships = Group::NONE; //cgroups.memberships = Group::NONE;
//cgroups.filters = Group::NONE; //cgroups.filters = Group::NONE;
commands.entity(entity).insert(Tunneling {
frames: 2,
dir: hit.1.normal,
});
} }
} }
} }
pub(super) fn tunnel_out(
mut commands: Commands,
mut wheel_query: Query<
(
Entity,
&mut Tunneling,
&mut ExternalForce,
&mut CollisionGroups,
),
With<CyberWheel>,
>,
mprops: Query<&ReadMassProperties, With<CyberBikeBody>>,
settings: Res<MovementSettings>,
) {
let mprops = mprops.single();
for (entity, mut tunneling, mut force, mut cgroups) in wheel_query.iter_mut() {
if tunneling.frames == 0 {
commands.entity(entity).remove::<Tunneling>();
force.force = Vec3::ZERO;
(cgroups.memberships, cgroups.filters) = BIKE_WHEEL_COLLISION_GROUP;
continue;
}
tunneling.frames -= 1;
force.force = tunneling.dir * settings.gravity * 1.1 * mprops.get().mass;
#[cfg(feature = "inspector")]
dbg!(&tunneling);
}
}
/// General velocity-based drag-force calculation; does not take orientation /// General velocity-based drag-force calculation; does not take orientation
/// into account. /// into account.
pub(super) fn drag(mut query: Query<(&Velocity, &mut ExternalForce), With<CyberBikeBody>>) { pub(super) fn drag(mut query: Query<(&Velocity, &mut ExternalForce), With<CyberBikeBody>>) {
@ -259,3 +235,24 @@ pub(super) fn drag(mut query: Query<(&Velocity, &mut ExternalForce), With<CyberB
forces.force -= vel * (v2 * 0.02); forces.force -= vel * (v2 * 0.02);
} }
} }
// helpers
fn yaw_to_angle(yaw: f32) -> f32 {
let v = yaw.powi(5) * FRAC_PI_4;
if v.is_normal() {
v
} else {
0.0
}
}
fn rotate_point(pt: &Vec3, rot: &Quat) -> Vec3 {
// thanks to https://danceswithcode.net/engineeringnotes/quaternions/quaternions.html
let [x, y, z] = pt.normalize().to_array();
let qpt = Quat::from_xyzw(x, y, z, 0.0);
// p' = rot^-1 * qpt * rot
let rot_qpt = rot.inverse() * qpt * *rot;
// why does this need to be inverted???
-Vec3::from_array([rot_qpt.x, rot_qpt.y, rot_qpt.z])
}

View file

@ -22,7 +22,6 @@ pub struct WheelConfig {
pub stiffness: f32, pub stiffness: f32,
pub damping: f32, pub damping: f32,
pub radius: f32, pub radius: f32,
pub thickness: f32,
pub friction: f32, pub friction: f32,
pub restitution: f32, pub restitution: f32,
pub density: f32, pub density: f32,
@ -37,9 +36,8 @@ impl Default for WheelConfig {
limits: [-0.5, 0.1], limits: [-0.5, 0.1],
stiffness: 30.0, stiffness: 30.0,
damping: 8.0, damping: 8.0,
radius: 0.35, radius: 0.3,
thickness: 0.11, friction: 0.0,
friction: 1.2,
restitution: 0.95, restitution: 0.95,
density: 0.05, density: 0.05,
} }

View file

@ -1,5 +1,6 @@
mod body; mod body;
mod components; mod components;
//mod controller;
mod wheels; mod wheels;
use bevy::prelude::{App, Assets, Mesh, Plugin, PostStartup, ResMut, StandardMaterial}; use bevy::prelude::{App, Assets, Mesh, Plugin, PostStartup, ResMut, StandardMaterial};
@ -9,7 +10,7 @@ pub(crate) use self::components::*;
use self::{body::spawn_cyberbike, wheels::spawn_wheels}; use self::{body::spawn_cyberbike, wheels::spawn_wheels};
pub const BIKE_BODY_COLLISION_GROUP: (Group, Group) = (Group::GROUP_1, Group::GROUP_1); pub const BIKE_BODY_COLLISION_GROUP: (Group, Group) = (Group::GROUP_1, Group::GROUP_1);
pub const BIKE_WHEEL_COLLISION_GROUP: (Group, Group) = (Group::GROUP_10, Group::GROUP_10); pub const BIKE_WHEEL_COLLISION_GROUP: (Group, Group) = (Group::GROUP_2, Group::GROUP_2);
type Meshterial<'a> = ( type Meshterial<'a> = (
ResMut<'a, Assets<Mesh>>, ResMut<'a, Assets<Mesh>>,

View file

@ -1,13 +1,17 @@
use bevy::prelude::{shape::Torus as Tire, *}; use bevy::prelude::*;
use bevy_rapier3d::prelude::{ use bevy_rapier3d::{
dynamics::{FixedJointBuilder, Velocity},
prelude::{
Ccd, CoefficientCombineRule, Collider, ColliderMassProperties, CollisionGroups, Damping, Ccd, CoefficientCombineRule, Collider, ColliderMassProperties, CollisionGroups, Damping,
ExternalForce, Friction, MultibodyJoint, PrismaticJointBuilder, Restitution, ExternalForce, Friction, MultibodyJoint, PrismaticJointBuilder, Restitution,
RevoluteJointBuilder, RigidBody, Sleeping, TransformInterpolation, RevoluteJointBuilder, RigidBody, Sleeping, TransformInterpolation,
},
}; };
use super::{CyberSteering, CyberWheel, Meshterial, WheelConfig, BIKE_WHEEL_COLLISION_GROUP}; use super::{CyberSteering, CyberWheel, Meshterial, WheelConfig, BIKE_WHEEL_COLLISION_GROUP};
use crate::action::PreviousVelocity;
pub fn spawn_wheels( pub(crate) fn spawn_wheels(
commands: &mut Commands, commands: &mut Commands,
bike: Entity, bike: Entity,
conf: &WheelConfig, conf: &WheelConfig,
@ -25,7 +29,7 @@ pub fn spawn_wheels(
let friction = Friction { let friction = Friction {
coefficient: conf.friction, coefficient: conf.friction,
combine_rule: CoefficientCombineRule::Average, combine_rule: CoefficientCombineRule::Min,
}; };
let mut wheel_poses = Vec::with_capacity(2); let mut wheel_poses = Vec::with_capacity(2);
@ -50,14 +54,9 @@ pub fn spawn_wheels(
let (mesh, collider) = gen_tires(conf); let (mesh, collider) = gen_tires(conf);
let material = StandardMaterial { let material = StandardMaterial {
base_color: Color::Rgba { base_color: Color::YELLOW,
red: 0.99,
green: 0.99,
blue: 0.05,
alpha: 1.0,
},
alpha_mode: AlphaMode::Opaque, alpha_mode: AlphaMode::Opaque,
perceptual_roughness: 0.5, perceptual_roughness: 0.1,
..Default::default() ..Default::default()
}; };
@ -102,10 +101,10 @@ pub fn spawn_wheels(
fork_rb_entity fork_rb_entity
}; };
let axel_builder = RevoluteJointBuilder::new(Vec3::X); let axel_builder = FixedJointBuilder::new(); //RevoluteJointBuilder::new(Vec3::X);
let axel_joint = MultibodyJoint::new(axel_parent_entity, axel_builder); let axel_joint = MultibodyJoint::new(axel_parent_entity, axel_builder);
let wheel_damping = Damping { let wheel_damping = Damping {
linear_damping: 0.8, //linear_damping: 0.8,
..Default::default() ..Default::default()
}; };
@ -119,8 +118,9 @@ pub fn spawn_wheels(
wheels_collision_group, wheels_collision_group,
friction, friction,
CyberWheel, CyberWheel,
Velocity::default(),
PreviousVelocity::default(),
ExternalForce::default(), ExternalForce::default(),
Restitution::new(conf.restitution),
SpatialBundle::default(), SpatialBundle::default(),
TransformInterpolation::default(), TransformInterpolation::default(),
RigidBody::Dynamic, RigidBody::Dynamic,
@ -132,7 +132,7 @@ pub fn spawn_wheels(
fn gen_tires(conf: &WheelConfig) -> (Mesh, Collider) { fn gen_tires(conf: &WheelConfig) -> (Mesh, Collider) {
let wheel_rad = conf.radius; let wheel_rad = conf.radius;
let tire = Sphere::new(wheel_rad); let tire = Sphere::new(wheel_rad);
let mut mesh = Mesh::from(tire); let mesh = Mesh::from(tire);
let wheel_collider = Collider::ball(wheel_rad); let wheel_collider = Collider::ball(wheel_rad);
(mesh, wheel_collider) (mesh, wheel_collider)

View file

@ -10,7 +10,7 @@ fn spawn_static_lights(
mut materials: ResMut<Assets<StandardMaterial>>, mut materials: ResMut<Assets<StandardMaterial>>,
) { ) {
let pink_light = PointLight { let pink_light = PointLight {
//intensity: 1_00.0, intensity: 10_00.0,
range: LIGHT_RANGE, range: LIGHT_RANGE,
color: Color::WHITE, color: Color::WHITE,
radius: 10.0, radius: 10.0,

View file

@ -1,5 +1,5 @@
use bevy::prelude::*; use bevy::prelude::*;
//#[cfg(feature = "inspector")] #[cfg(feature = "inspector")]
use cyber_rider::glamor::CyberGlamorPlugin; use cyber_rider::glamor::CyberGlamorPlugin;
use cyber_rider::{ use cyber_rider::{
action::CyberActionPlugin, bike::CyberBikePlugin, camera::CyberCamPlugin, disable_mouse_trap, action::CyberActionPlugin, bike::CyberBikePlugin, camera::CyberCamPlugin, disable_mouse_trap,
@ -33,7 +33,7 @@ fn main() {
.add_systems(Startup, disable_mouse_trap) .add_systems(Startup, disable_mouse_trap)
.add_systems(Update, bevy::window::close_on_esc); .add_systems(Update, bevy::window::close_on_esc);
//#[cfg(feature = "inspector")] #[cfg(feature = "inspector")]
app.add_plugins(CyberGlamorPlugin); app.add_plugins(CyberGlamorPlugin);
app.run(); app.run();

View file

@ -1,12 +1,6 @@
use bevy::{ use bevy::{prelude::*, render::color::Color};
prelude::{shape::Icosphere, *},
render::{color::Color, mesh::Indices, render_asset::RenderAssetUsages},
};
use bevy_rapier3d::prelude::*; use bevy_rapier3d::prelude::*;
use hexasphere::shapes::IcoSphere; // use noise::{HybridMulti, NoiseFn, SuperSimplex};
use noise::{HybridMulti, NoiseFn, SuperSimplex};
use rand::{Rng, SeedableRng};
use wgpu::PrimitiveTopology;
pub const PLANET_RADIUS: f32 = 2_000.0; pub const PLANET_RADIUS: f32 = 2_000.0;
pub const PLANET_HUE: f32 = 31.0; pub const PLANET_HUE: f32 = 31.0;
@ -22,7 +16,7 @@ fn spawn_planet(
) { ) {
//let color = Color::rgb(0.74, 0.5334, 0.176); //let color = Color::rgb(0.74, 0.5334, 0.176);
let (mesh, shape) = gen_planet(999.9); let (mesh, shape) = gen_planet(2999.9);
let pbody = ( let pbody = (
RigidBody::Fixed, RigidBody::Fixed,
@ -37,7 +31,9 @@ fn spawn_planet(
..Default::default() ..Default::default()
}, },
Restitution::new(0.8), Restitution::new(0.8),
Transform::from_xyz(0.0, 0.1, 0.0), Transform::from_xyz(0.0, 1.0, 0.0),
// same as the bike body
CollisionGroups::new(Group::GROUP_1, Group::GROUP_1),
); );
commands commands
@ -67,9 +63,9 @@ impl Plugin for CyberPlanetPlugin {
//--------------------------------------------------------------------- //---------------------------------------------------------------------
fn gen_planet(span: f32) -> (Mesh, Collider) { fn gen_planet(span: f32) -> (Mesh, Collider) {
let mesh = Cuboid::new(span, 0.1, span); let mut mesh = Cuboid::new(span, 1.0, span);
let collider = Collider::cuboid(span / 2.0, 0.05, span / 2.0); let collider = Collider::cuboid(span / 2.0, 0.5, span / 2.0);
(mesh.mesh(), collider) (mesh.mesh(), collider)
} }

View file

@ -5,8 +5,8 @@ use bevy::{
TextBundle, TextSection, TextStyle, Transform, With, TextBundle, TextSection, TextStyle, Transform, With,
}, },
}; };
#[cfg(feature = "inspector")] //#[cfg(feature = "inspector")]
use bevy_inspector_egui::quick::WorldInspectorPlugin; //use bevy_inspector_egui::quick::WorldInspectorPlugin;
use bevy_rapier3d::prelude::Velocity; use bevy_rapier3d::prelude::Velocity;
use crate::bike::CyberBikeBody; use crate::bike::CyberBikeBody;
@ -54,7 +54,7 @@ pub struct CyberUIPlugin;
impl Plugin for CyberUIPlugin { impl Plugin for CyberUIPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
#[cfg(feature = "inspector")] #[cfg(feature = "inspector")]
//app.add_plugins(WorldInspectorPlugin); //app.add_plugins(WorldInspectorPlugin::new());
// //
app.add_systems(Startup, setup_ui) app.add_systems(Startup, setup_ui)