use std::f32::consts::{FRAC_PI_3, FRAC_PI_4}; use avian3d::{ collision::Collisions, dynamics::solver::xpbd::AngularConstraint, prelude::{ ColliderMassProperties, Collision, ExternalForce, ExternalTorque, Gravity, LinearVelocity, PrismaticJoint, RigidBodyQuery, }, }; use bevy::prelude::{EventReader, Quat, Query, Res, ResMut, Time, Transform, Vec3, With, Without}; use super::{CatControllerSettings, CatControllerState, CyberLean, MovementSettings}; use crate::{ bike::{CyberBikeBody, CyberFork, CyberSpring, CyberSteering, CyberWheel, WheelConfig}, input::InputState, }; 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]) } /// The gravity vector points from the cyberbike to the center of the planet. pub(super) fn set_gravity( xform: Query<&Transform, With>, settings: Res, mut gravity: ResMut, ) { let xform = xform.single(); *gravity = Gravity(xform.translation.normalize() * -settings.gravity); } pub(super) fn clear_forces( mut forces: Query<(Option<&mut ExternalForce>, Option<&mut ExternalTorque>)>, ) { for (force, torque) in forces.iter_mut() { if let Some(mut force) = force { force.clear(); } if let Some(mut torque) = torque { torque.clear(); } } } pub(super) fn suspension( movment_settings: Res, wheel_config: Res, time: Res