diff --git a/src/bike.rs b/src/bike.rs index 7748563..9a6cd6a 100644 --- a/src/bike.rs +++ b/src/bike.rs @@ -26,9 +26,16 @@ pub enum CyberWheel { #[reflect(Component)] pub struct WheelState { pub displacement: Scalar, + pub force_normal: Scalar, pub sliding: bool, - pub grounded: bool, - pub ppos: Vec3, + pub contact_point: Option<Vec3>, + pub contact_normal: Option<Vec3>, +} + +impl WheelState { + pub fn reset(&mut self) { + *self = Self::default(); + } } #[derive(Component, Clone, Copy, Debug, Reflect)] diff --git a/src/physics.rs b/src/physics.rs index b580317..1b961b9 100644 --- a/src/physics.rs +++ b/src/physics.rs @@ -163,26 +163,15 @@ mod systems { } pub(super) fn suspension( - mut bike_body_query: Query< - (&Transform, &mut ExternalForce, RigidBodyQuery), - With<CyberBikeBody>, - >, + mut bike_body_query: Query<(&Transform, &mut ExternalForce), With<CyberBikeBody>>, mut wheel_mesh_query: Query< (&mut Transform, &mut WheelState, &WheelConfig, &CyberWheel), Without<CyberBikeBody>, >, caster_query: Query<(&RayCaster, &RayHits, &CyberWheel)>, time: Res<Time>, - input: Res<InputState>, mut gizmos: Gizmos, ) { - let max_thrust = 100.0; - let max_yaw = 50.0; - let mut thrust = input.throttle * max_thrust; - if input.brake { - thrust *= -1.0; - } - let yaw = input.yaw * max_yaw; let dt = time.delta().as_secs_f32(); let mut front_caster = &RayCaster::default(); @@ -204,10 +193,7 @@ mod systems { } } - let Ok((bike_xform, mut bike_forces, rbq)) = bike_body_query.get_single_mut() else { - bevy::log::warn!("Couldn't get body query"); - return; - }; + let (bike_xform, mut bike_forces) = bike_body_query.single_mut(); for (mut xform, mut state, config, wheel) in wheel_mesh_query.iter_mut() { let (caster, hits) = match wheel { @@ -217,48 +203,83 @@ mod systems { if let Some(hit) = hits.iter().next() { let dist = hit.distance; - let cdir = caster.direction.as_vec3(); - xform.translation = config.attach + (cdir * (dist - WHEEL_RADIUS)); + let hit_point = caster.global_origin() + caster.global_direction() * dist; let displacement = config.rest_dist - dist; let damper_vel = (state.displacement - displacement) / dt; - state.displacement = displacement; let mag = config.konstant * displacement - config.damping * damper_vel; - let mag = mag.max(0.0); - let fdir = hit.normal; - let force = fdir * mag; + state.force_normal = mag; + state.contact_normal = Some(hit.normal); + state.contact_point = Some(hit_point); + state.displacement = displacement; - let hit_point = caster.global_origin() + caster.global_direction() * dist; + let cdir = caster.direction.as_vec3(); + xform.translation = config.attach + (cdir * (dist - WHEEL_RADIUS)); + + let force = hit.normal * mag; gizmos.arrow( hit_point, hit_point + force, Color::linear_rgb(1., 0.5, 0.2), ); - - let _vel = rbq.velocity_at_point(hit_point); - //bevy::log::info!("{_vel:?}"); - bike_forces.apply_force_at_point( force, caster.global_origin(), bike_xform.translation, ); + } else { + xform.translation = config.attach + (caster.direction.as_vec3() * config.rest_dist); + state.reset(); + } + } + } - let normal = hit.normal; + pub(super) fn steering( + mut bike_query: Query< + (&Transform, &mut ExternalForce, RigidBodyQueryReadOnly), + With<CyberBikeBody>, + >, + mut wheels: Query<(&mut WheelState, &WheelConfig, &CyberWheel)>, + time: Res<Time>, + input: Res<InputState>, + mut gizmos: Gizmos, + ) { + let Ok((bike_xform, mut bike_force, bike_body)) = bike_query.get_single_mut() else { + bevy::log::warn!("No entity for bike_query."); + return; + }; + + let max_thrust = 100.0; + let max_yaw = 50.0; + let thrust = input.throttle * max_thrust; + let yaw = input.yaw * max_yaw; + let dt = time.delta().as_secs_f32(); + + for (mut state, config, wheel) in wheels.iter_mut() { + if let Some(contact_point) = state.contact_point { + let vel = bike_body.velocity_at_point(contact_point); + bevy::log::info_once!("vel: {vel:?}"); + let friction = config.friction; + bevy::log::info_once!(friction); + // just to shut the linter up about state not needing to be mut + state.sliding = true; + + let normal = state.contact_normal.unwrap(); let steering = match wheel { CyberWheel::Front => normal.cross(*bike_xform.back()) * yaw, CyberWheel::Rear => Vec3::ZERO, - //_ => normal.cross(*bike_xform.forward()) * yaw, // Vec3::ZERO, }; let thrust = normal.cross(*bike_xform.right()) * thrust; let total = (thrust + steering) * dt; - bike_forces.apply_force_at_point(total, hit_point, bike_xform.translation); - gizmos.arrow(hit_point, hit_point + total, Color::linear_rgb(1., 1., 0.2)); - } else { - xform.translation = config.attach + (caster.direction.as_vec3() * config.rest_dist); + bike_force.apply_force_at_point(total, contact_point, bike_xform.translation); + gizmos.arrow( + contact_point, + contact_point + total, + Color::linear_rgb(1., 1., 0.2), + ); } } } @@ -301,7 +322,7 @@ mod systems { } } -use systems::{apply_lean, calculate_lean, suspension, tweak}; +use systems::{apply_lean, calculate_lean, steering, suspension, tweak}; pub struct CyberPhysicsPlugin; @@ -319,7 +340,7 @@ impl Plugin for CyberPhysicsPlugin { }) .add_systems( FixedUpdate, - (calculate_lean, apply_lean, suspension).chain(), + (calculate_lean, apply_lean, suspension, steering).chain(), ) .add_systems(Update, tweak); }