checkpoint
This commit is contained in:
parent
aef303ca71
commit
dd65741d7b
11 changed files with 115 additions and 61 deletions
|
@ -29,15 +29,18 @@ impl Plugin for CyberActionPlugin {
|
|||
.register_type::<CyberLean>()
|
||||
.register_type::<CatControllerSettings>()
|
||||
.add_plugins((PhysicsPlugins::default(), FrameTimeDiagnosticsPlugin))
|
||||
.insert_resource(SubstepCount(24))
|
||||
.insert_resource(SubstepCount(6))
|
||||
.add_systems(
|
||||
Update,
|
||||
(
|
||||
gravity,
|
||||
#[cfg(feature = "inspector")]
|
||||
set_gravity,
|
||||
clear_forces,
|
||||
calculate_lean,
|
||||
apply_lean,
|
||||
//#[cfg(feature = "inspector")]
|
||||
debug_bodies,
|
||||
(cyber_lean, suspension, falling_cat, input_forces).after(clear_forces),
|
||||
),
|
||||
)
|
||||
.chain(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
use std::f32::consts::{FRAC_PI_3, FRAC_PI_4};
|
||||
|
||||
use avian3d::{
|
||||
collision::Collisions,
|
||||
dynamics::solver::xpbd::AngularConstraint,
|
||||
prelude::{
|
||||
ColliderMassProperties, ExternalForce, ExternalTorque, Gravity, LinearVelocity,
|
||||
ColliderMassProperties, Collision, ExternalForce, ExternalTorque, Gravity, LinearVelocity,
|
||||
PrismaticJoint, RigidBodyQuery,
|
||||
},
|
||||
};
|
||||
#[cfg(feature = "inspector")]
|
||||
use bevy::prelude::Entity;
|
||||
use bevy::prelude::{Quat, Query, Res, ResMut, Time, Transform, Vec3, With, Without};
|
||||
use bevy::prelude::{EventReader, Quat, Query, Res, ResMut, Time, Transform, Vec3, With, Without};
|
||||
|
||||
use super::{CatControllerSettings, CatControllerState, CyberLean, MovementSettings};
|
||||
use crate::{
|
||||
|
@ -38,7 +37,7 @@ fn rotate_point(pt: &Vec3, rot: &Quat) -> Vec3 {
|
|||
}
|
||||
|
||||
/// The gravity vector points from the cyberbike to the center of the planet.
|
||||
pub(super) fn gravity(
|
||||
pub(super) fn set_gravity(
|
||||
xform: Query<&Transform, With<CyberBikeBody>>,
|
||||
|
||||
settings: Res<MovementSettings>,
|
||||
|
@ -46,20 +45,25 @@ pub(super) fn gravity(
|
|||
) {
|
||||
let xform = xform.single();
|
||||
*gravity = Gravity(xform.translation.normalize() * -settings.gravity);
|
||||
|
||||
// clear all external forces
|
||||
}
|
||||
|
||||
pub(super) fn clear_forces(mut forces: Query<(&mut ExternalForce, &mut ExternalTorque)>) {
|
||||
for (mut force, mut torque) in forces.iter_mut() {
|
||||
force.clear();
|
||||
torque.clear();
|
||||
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<MovementSettings>,
|
||||
wheel_config: Res<WheelConfig>,
|
||||
time: Res<Time>,
|
||||
mass: Query<&ColliderMassProperties, With<CyberBikeBody>>,
|
||||
mut axels: Query<(&mut ExternalForce, &CyberSpring, &Transform)>,
|
||||
) {
|
||||
|
@ -68,17 +72,19 @@ pub(super) fn suspension(
|
|||
} else {
|
||||
1.0
|
||||
};
|
||||
let dt = time.delta_seconds();
|
||||
let gravity = movment_settings.gravity;
|
||||
let mag = -wheel_config.stiffness * mass * gravity;
|
||||
let mag = -wheel_config.stiffness * mass * gravity * dt;
|
||||
for (mut force, spring, xform) in axels.iter_mut() {
|
||||
let spring = mag * spring.0;
|
||||
let spring = xform.translation + spring;
|
||||
let _ = force.apply_force(spring);
|
||||
bevy::log::info!("suspension force: {spring:?}");
|
||||
//let _ = force.apply_force(spring);
|
||||
}
|
||||
}
|
||||
|
||||
/// The desired lean angle, given steering input and speed.
|
||||
pub(super) fn cyber_lean(
|
||||
pub(super) fn calculate_lean(
|
||||
bike_state: Query<(&LinearVelocity, &Transform), With<CyberBikeBody>>,
|
||||
wheels: Query<&Transform, With<CyberWheel>>,
|
||||
input: Res<InputState>,
|
||||
|
@ -104,7 +110,7 @@ pub(super) fn cyber_lean(
|
|||
}
|
||||
|
||||
/// PID-based controller for stabilizing attitude; keeps the cyberbike upright.
|
||||
pub(super) fn falling_cat(
|
||||
pub(super) fn apply_lean(
|
||||
mut bike_query: Query<(&Transform, &mut ExternalTorque, &mut CatControllerState)>,
|
||||
time: Res<Time>,
|
||||
settings: Res<CatControllerSettings>,
|
||||
|
@ -132,7 +138,7 @@ pub(super) fn falling_cat(
|
|||
}
|
||||
|
||||
/// Apply forces to the cyberbike as a result of input.
|
||||
pub(super) fn input_forces(
|
||||
pub(super) fn apply_inputs(
|
||||
settings: Res<MovementSettings>,
|
||||
input: Res<InputState>,
|
||||
time: Res<Time>,
|
||||
|
@ -159,7 +165,8 @@ pub(super) fn input_forces(
|
|||
let thrust = xform.forward() * input.throttle * settings.accel;
|
||||
let point = xform.translation + *xform.back();
|
||||
|
||||
let _ = *forces.apply_force_at_point(dt * thrust, point, mass.center_of_mass.0);
|
||||
//let _ = *forces.apply_force_at_point(dt * thrust, point,
|
||||
// mass.center_of_mass.0);
|
||||
|
||||
// brake + thrust
|
||||
for mut motor in braking_query.iter_mut() {
|
||||
|
@ -188,10 +195,41 @@ pub(super) fn input_forces(
|
|||
fork.align_orientation(&mut axle, &mut bike, diff, &mut compliance, 1.0, dt);
|
||||
}
|
||||
|
||||
#[cfg(feature = "inspector")]
|
||||
pub(super) fn debug_bodies(bodies: Query<(Entity, RigidBodyQuery)>) {
|
||||
for (entity, rbq) in bodies.iter().filter(|(_, r)| r.rb.is_dynamic()) {
|
||||
let line = format!("{entity:?} at {:?}", rbq.current_position());
|
||||
bevy::log::info!(line);
|
||||
//#[cfg(feature = "inspector")]
|
||||
mod inspector {
|
||||
use bevy::prelude::Entity;
|
||||
|
||||
use super::*;
|
||||
pub(crate) fn debug_bodies(
|
||||
bodies: Query<(Entity, RigidBodyQuery)>,
|
||||
mut collisions: EventReader<Collision>,
|
||||
) {
|
||||
let bodies: Vec<_> = bodies.iter().collect();
|
||||
for i in 0..(bodies.len()) {
|
||||
let (ent, ref rb) = bodies[i];
|
||||
let cur_pos = rb.current_position();
|
||||
let mut max = 0.0f32;
|
||||
let mut min = f32::MAX;
|
||||
for j in 0..(bodies.len()) {
|
||||
if j == i {
|
||||
continue;
|
||||
}
|
||||
let (_, ref other) = bodies[j];
|
||||
let dist = (cur_pos - other.current_position()).length();
|
||||
max = max.max(dist);
|
||||
min = min.min(dist);
|
||||
}
|
||||
let line = format!("{ent:?} at {cur_pos:?} -- min: {min}, max: {max}");
|
||||
bevy::log::info!(line);
|
||||
}
|
||||
for Collision(contacts) in collisions.read() {
|
||||
bevy::log::info!(
|
||||
"Entities {:?} and {:?} are colliding",
|
||||
contacts.entity1,
|
||||
contacts.entity2,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
//#[cfg(feature = "inspector")]
|
||||
pub(super) use inspector::debug_bodies;
|
||||
|
|
|
@ -4,8 +4,8 @@ use bevy::{
|
|||
scene::SceneBundle,
|
||||
};
|
||||
|
||||
use super::{spawn_wheels, CyberBikeBody, Meshterial, WheelConfig, BIKE_BODY_COLLISION_GROUP};
|
||||
use crate::{action::CatControllerState, planet::PLANET_RADIUS};
|
||||
use super::{spawn_wheels, CyberBikeBody, Meshterial, WheelConfig};
|
||||
use crate::{action::CatControllerState, planet::PLANET_RADIUS, ColliderGroups};
|
||||
|
||||
pub(super) fn spawn_cyberbike(
|
||||
mut commands: Commands,
|
||||
|
@ -32,8 +32,8 @@ pub(super) fn spawn_cyberbike(
|
|||
..Default::default()
|
||||
};
|
||||
|
||||
let (membership, filter) = BIKE_BODY_COLLISION_GROUP;
|
||||
let bike_collision_group = CollisionLayers::new(membership, filter);
|
||||
let bike_collision_group =
|
||||
CollisionLayers::new(ColliderGroups::BikeBody, ColliderGroups::Planet);
|
||||
|
||||
let scene = asset_server.load("cb-no-y_up.glb#Scene0");
|
||||
|
||||
|
@ -50,7 +50,7 @@ pub(super) fn spawn_cyberbike(
|
|||
SleepingDisabled,
|
||||
CyberBikeBody,
|
||||
CatControllerState::default(),
|
||||
ColliderDensity(0.6),
|
||||
ColliderDensity(0.06),
|
||||
LinearDamping(0.1),
|
||||
AngularDamping(2.0),
|
||||
LinearVelocity::ZERO,
|
||||
|
@ -66,5 +66,7 @@ pub(super) fn spawn_cyberbike(
|
|||
})
|
||||
.id();
|
||||
|
||||
bevy::log::info!("bike body: {bike:?}");
|
||||
|
||||
spawn_wheels(&mut commands, bike, &xform, &wheel_conf, &mut meshterials);
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@ use bevy::{
|
|||
pub(crate) use self::components::*;
|
||||
use self::{body::spawn_cyberbike, wheels::spawn_wheels};
|
||||
|
||||
pub const BIKE_BODY_COLLISION_GROUP: (u32, u32) = (0b01, 0b01);
|
||||
pub const BIKE_WHEEL_COLLISION_GROUP: (u32, u32) = (0b10, 0b10);
|
||||
pub const BIKE_BODY_COLLISION_GROUP: (u32, u32) = (1, 1);
|
||||
pub const BIKE_WHEEL_COLLISION_GROUP: (u32, u32) = (2, 2);
|
||||
|
||||
type Meshterial<'a> = (
|
||||
ResMut<'a, Assets<Mesh>>,
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
use avian3d::prelude::*;
|
||||
use bevy::prelude::{Torus as Tire, *};
|
||||
|
||||
use super::{
|
||||
CyberFork, CyberSpring, CyberSteering, CyberWheel, Meshterial, WheelConfig,
|
||||
BIKE_WHEEL_COLLISION_GROUP,
|
||||
};
|
||||
use super::{CyberFork, CyberSpring, CyberSteering, CyberWheel, Meshterial, WheelConfig};
|
||||
use crate::ColliderGroups;
|
||||
|
||||
pub fn spawn_wheels(
|
||||
commands: &mut Commands,
|
||||
|
@ -13,11 +11,11 @@ pub fn spawn_wheels(
|
|||
conf: &WheelConfig,
|
||||
meshterials: &mut Meshterial,
|
||||
) {
|
||||
let (membership, filter) = BIKE_WHEEL_COLLISION_GROUP;
|
||||
let wheels_collision_group = CollisionLayers::new(membership, filter);
|
||||
let wheels_collision_group =
|
||||
CollisionLayers::new(ColliderGroups::Wheels, ColliderGroups::Planet);
|
||||
let wheel_y = conf.y;
|
||||
let not_sleeping = SleepingDisabled;
|
||||
let ccd = SweptCcd::NON_LINEAR.include_dynamic(false);
|
||||
let ccd = SweptCcd::LINEAR.include_dynamic(false);
|
||||
let limits = conf.limits;
|
||||
let (meshes, materials) = meshterials;
|
||||
let rake_vec: Vec3 = Vec3::new(0.0, 1.0, 0.57).normalize(); // about 30 degrees of rake
|
||||
|
@ -82,6 +80,7 @@ pub fn spawn_wheels(
|
|||
SpatialBundle::default(),
|
||||
RigidBody::Dynamic,
|
||||
ColliderDensity(0.1),
|
||||
CollisionMargin(0.1),
|
||||
AngularVelocity::ZERO,
|
||||
ExternalTorque::ZERO,
|
||||
))
|
||||
|
@ -91,43 +90,40 @@ pub fn spawn_wheels(
|
|||
.id();
|
||||
|
||||
let spring = CyberSpring(suspension_axis);
|
||||
let axel = if let Some(steering) = steering {
|
||||
let axle = if let Some(steering) = steering {
|
||||
commands.spawn((
|
||||
RigidBody::Dynamic,
|
||||
ExternalForce::ZERO,
|
||||
steering,
|
||||
spring,
|
||||
Collider::sphere(0.1),
|
||||
ColliderDensity(0.1),
|
||||
CollisionLayers::from_bits(0, 0),
|
||||
MassPropertiesBundle::new_computed(&Collider::sphere(0.1), 0.1),
|
||||
))
|
||||
} else {
|
||||
commands.spawn((
|
||||
RigidBody::Dynamic,
|
||||
ExternalForce::ZERO,
|
||||
spring,
|
||||
Collider::sphere(0.1),
|
||||
ColliderDensity(0.1),
|
||||
CollisionLayers::from_bits(0, 0),
|
||||
MassPropertiesBundle::new_computed(&Collider::sphere(0.1), 0.1),
|
||||
))
|
||||
}
|
||||
.insert(SpatialBundle::from_transform(
|
||||
xform.with_translation(xform.translation + offset),
|
||||
))
|
||||
.id();
|
||||
let axel_joint = RevoluteJoint::new(axel, wheel).with_aligned_axis(Vec3::NEG_X);
|
||||
bevy::log::info!("axle RB: {axle:?}");
|
||||
let axel_joint = RevoluteJoint::new(axle, wheel).with_aligned_axis(Vec3::NEG_X);
|
||||
commands.spawn(axel_joint);
|
||||
|
||||
// suspension and steering:
|
||||
if steering.is_some() {
|
||||
let joint = PrismaticJoint::new(axel, bike)
|
||||
let joint = PrismaticJoint::new(axle, bike)
|
||||
.with_free_axis(suspension_axis)
|
||||
.with_local_anchor_1(Vec3::new(0.0, 0.0, 0.1))
|
||||
.with_local_anchor_2(offset)
|
||||
.with_limits(limits[0], limits[1]);
|
||||
commands.spawn((joint, CyberFork));
|
||||
} else {
|
||||
let joint = PrismaticJoint::new(axel, bike)
|
||||
let joint = PrismaticJoint::new(axle, bike)
|
||||
.with_free_axis(suspension_axis)
|
||||
.with_local_anchor_2(offset)
|
||||
.with_limits(limits[0], limits[1]);
|
||||
|
@ -168,7 +164,7 @@ fn gen_tires(conf: &WheelConfig) -> (Mesh, Collider) {
|
|||
for idx in indices.as_slice().chunks_exact(3) {
|
||||
idxs.push([idx[0] as u32, idx[1] as u32, idx[2] as u32]);
|
||||
}
|
||||
let wheel_collider = Collider::convex_decomposition_from_mesh(&mesh).unwrap();
|
||||
let wheel_collider = Collider::trimesh_from_mesh(&mesh).unwrap();
|
||||
|
||||
(mesh, wheel_collider)
|
||||
}
|
||||
|
|
|
@ -44,12 +44,15 @@ fn setup_cybercams(mut commands: Commands) {
|
|||
..Default::default()
|
||||
};
|
||||
|
||||
commands
|
||||
let id = commands
|
||||
.spawn(Camera3dBundle {
|
||||
projection: bevy::render::camera::Projection::Perspective(hero_projection),
|
||||
..Default::default()
|
||||
})
|
||||
.insert(CyberCameras::Hero);
|
||||
.insert(CyberCameras::Hero)
|
||||
.id();
|
||||
|
||||
commands.spawn(TargetCamera(id));
|
||||
|
||||
commands
|
||||
.spawn(Camera3dBundle::default())
|
||||
|
|
|
@ -2,6 +2,7 @@ use avian3d::debug_render::PhysicsGizmos;
|
|||
use bevy::{
|
||||
color::Srgba,
|
||||
gizmos::AppGizmoBuilder,
|
||||
math::Vec3,
|
||||
prelude::{App, Color, GizmoConfig, Plugin},
|
||||
};
|
||||
|
||||
|
@ -20,6 +21,8 @@ impl Plugin for CyberGlamorPlugin {
|
|||
PhysicsGizmos {
|
||||
contact_point_color: Some(Srgba::GREEN.into()),
|
||||
contact_normal_color: Some(Srgba::WHITE.into()),
|
||||
hide_meshes: true,
|
||||
axis_lengths: Some(Vec3::ZERO),
|
||||
..Default::default()
|
||||
},
|
||||
GizmoConfig::default(),
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use avian3d::prelude::PhysicsLayer;
|
||||
use bevy::{
|
||||
prelude::{Query, Vec3, Window, With},
|
||||
window::PrimaryWindow,
|
||||
|
@ -12,6 +13,13 @@ pub mod lights;
|
|||
pub mod planet;
|
||||
pub mod ui;
|
||||
|
||||
#[derive(PhysicsLayer)]
|
||||
pub enum ColliderGroups {
|
||||
BikeBody,
|
||||
Wheels,
|
||||
Planet,
|
||||
}
|
||||
|
||||
pub fn disable_mouse_trap(mut window: Query<&mut Window, With<PrimaryWindow>>) {
|
||||
let mut window = window.get_single_mut().unwrap();
|
||||
window.cursor.grab_mode = bevy::window::CursorGrabMode::None;
|
||||
|
|
|
@ -32,7 +32,7 @@ fn spawn_static_lights(
|
|||
|
||||
commands.insert_resource(AmbientLight {
|
||||
color: Color::WHITE,
|
||||
brightness: 0.2,
|
||||
brightness: 10_000.0,
|
||||
});
|
||||
|
||||
let _cascade_shadow_config = CascadeShadowConfigBuilder {
|
||||
|
|
|
@ -41,7 +41,7 @@ fn spawn_planet(
|
|||
RigidBody::Static,
|
||||
pcollide,
|
||||
CyberPlanet,
|
||||
CollisionLayers::new(u32::MAX, u32::MAX),
|
||||
CollisionLayers::new(LayerMask::ALL, LayerMask::ALL),
|
||||
CollisionMargin(0.2),
|
||||
));
|
||||
}
|
||||
|
|
11
src/ui.rs
11
src/ui.rs
|
@ -3,8 +3,9 @@ use bevy::{
|
|||
app::{Startup, Update},
|
||||
prelude::{
|
||||
AlignSelf, App, AssetServer, Color, Commands, Component, Plugin, Query, Res, Style, Text,
|
||||
TextBundle, TextSection, TextStyle, Transform, With,
|
||||
TextBundle, TextSection, TextStyle, With,
|
||||
},
|
||||
ui::TargetCamera,
|
||||
};
|
||||
|
||||
use crate::bike::CyberBikeBody;
|
||||
|
@ -34,16 +35,16 @@ fn setup_ui(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||
},
|
||||
..Default::default()
|
||||
})
|
||||
.insert(UpText);
|
||||
.insert((UpText, TargetCamera));
|
||||
}
|
||||
|
||||
fn update_ui(
|
||||
state_query: Query<(&LinearVelocity, &Transform), With<CyberBikeBody>>,
|
||||
state_query: Query<&LinearVelocity, With<CyberBikeBody>>,
|
||||
mut text_query: Query<&mut Text, With<UpText>>,
|
||||
) {
|
||||
let mut text = text_query.single_mut();
|
||||
let (velocity, xform) = state_query.single();
|
||||
let speed = velocity.dot(*xform.forward());
|
||||
let velocity = state_query.single();
|
||||
let speed = velocity.0.length();
|
||||
text.sections[0].value = format!("spd: {:.2}", speed);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue