diff --git a/src/bike.rs b/src/bike.rs index 38d1ca0..ab39015 100644 --- a/src/bike.rs +++ b/src/bike.rs @@ -5,36 +5,54 @@ use bevy::prelude::*; use crate::physics::CatControllerState; +pub const REST_DISTANCE: f32 = 0.8; + #[derive(Component)] pub struct CyberBikeBody; #[derive(Component)] -pub struct CyberWheel; +pub enum CyberWheel { + Front, + Rear, +} // marker for front suspension joint #[derive(Component)] pub struct Steering; -#[derive(Component)] -pub struct FrontHub; // marker for rear suspension joint #[derive(Component)] pub struct Rearing; -#[derive(Component)] -pub struct RearHub; + +#[derive(Debug, Resource, Reflect)] +pub struct SuspensionConfig { + pub rest_dist: f32, + pub konstant: f32, + pub damping: f32, +} + +impl Default for SuspensionConfig { + fn default() -> Self { + Self { + rest_dist: REST_DISTANCE, + konstant: 150.0, + damping: 50.0, + } + } +} fn spawn_bike( mut commands: Commands, mut meshes: ResMut<Assets<Mesh>>, mut materials: ResMut<Assets<StandardMaterial>>, ) { - let pos = Vec3::new(0.0, 4.0, 0.0); - let xform = Transform::from_translation(pos).with_rotation(Quat::from_rotation_z(0.0)); + let pos = Vec3::new(0.0, 24.0, 0.0); + let xform = Transform::from_translation(pos); //.with_rotation(Quat::from_rotation_z(0.0)); let body_collider = Collider::capsule_endpoints(0.5, Vec3::new(0.0, 0.0, -0.65), Vec3::new(0.0, 0.0, 0.8)); - let bike = commands + let _bike = commands .spawn((xform, Visibility::default())) .insert(( Name::new("body"), @@ -45,8 +63,6 @@ fn spawn_bike( CyberBikeBody, CatControllerState::default(), ColliderDensity(20.0), - LinearDamping(0.1), - AngularDamping(2.0), LinearVelocity::ZERO, AngularVelocity::ZERO, ExternalForce::ZERO.with_persistence(false), @@ -54,62 +70,89 @@ fn spawn_bike( )) .with_children(|builder| { let color = Color::srgb(0.7, 0.05, 0.7); - let mut rotation = Transform::default(); // Transform::from_rotation(Quat::from_rotation_y(FRAC_PI_2)); - rotation.rotate_x(FRAC_PI_2); + let mut xform = Transform::default(); + xform.rotate_x(FRAC_PI_2); let pbr_bundle = ( Mesh3d(meshes.add(Capsule3d::new(0.5, 1.45))), - rotation, + xform, MeshMaterial3d(materials.add(color)), ); builder.spawn(pbr_bundle); - }) - .id(); + spawn_wheels(builder, meshes, materials, xform, builder.parent_entity()); + }); - spawn_wheels(commands, meshes, materials, xform, bike); + //spawn_wheels(commands, meshes, materials, xform, bike); +} + +fn spawn_caster( + commands: &mut ChildBuilder, + collider: Collider, + xform: Transform, + direction: Dir3, + parent: Entity, + is_front: bool, +) { + let caster = ShapeCaster::new(collider, xform.translation, Quat::IDENTITY, direction) + .with_query_filter(SpatialQueryFilter::from_excluded_entities([parent])); + + let mut entity = commands.spawn((caster, Transform::default())); + if is_front { + entity.insert((Steering, Name::new("front wheel"))); + } else { + entity.insert((Rearing, Name::new("rear wheel"))); + } } fn spawn_wheels( - mut commands: Commands, + commands: &mut ChildBuilder, mut meshes: ResMut<Assets<Mesh>>, mut materials: ResMut<Assets<StandardMaterial>>, xform: Transform, body: Entity, ) { - let front_rake = Vec3::new(0.0, -1.0, -0.57).normalize(); // about 30 degrees - let front_pos = xform.translation + front_rake; - let (mesh, collider) = gen_tire(); - let front_hub = wheels_helper( - &mut commands, + let front_rake = Vec3::new(0.0, -1.0, -0.57).normalize(); // about 30 degrees + let front_attach = xform.translation + xform.forward() * 0.7; + let front_wheel_pos = front_attach + (front_rake * REST_DISTANCE); + + spawn_caster( + commands, + collider.clone(), + Transform::from_translation(front_attach), + Dir3::new_unchecked(front_rake), + body, + true, + ); + wheel_mesh( + commands, &mut meshes, &mut materials, - front_pos, + front_wheel_pos, mesh.clone(), - collider.clone(), + CyberWheel::Front, ); - commands.entity(front_hub).insert(FrontHub); - commands.spawn(( - Steering, - FixedJoint::new(front_hub, body).with_local_anchor_2(*xform.forward() + front_rake), - )); let rear_rake = Vec3::new(0.0, -1.0, 0.57).normalize(); - let rear_pos = xform.translation + rear_rake; + let rear_attach = xform.translation + xform.back() * 0.7; + let rear_wheel_pos = rear_attach + (rear_rake * REST_DISTANCE); - let rear_hub = wheels_helper( - &mut commands, + spawn_caster( + commands, + collider, + Transform::from_translation(rear_attach), + Dir3::new_unchecked(rear_rake), + body, + false, + ); + wheel_mesh( + commands, &mut meshes, &mut materials, - rear_pos, + rear_wheel_pos, mesh, - collider, + CyberWheel::Rear, ); - commands.entity(rear_hub).insert(RearHub); - commands.spawn(( - Rearing, - FixedJoint::new(rear_hub, body).with_local_anchor_2(*xform.back() + rear_rake), - )); } //-************************************************************************ @@ -117,37 +160,20 @@ fn spawn_wheels( //-************************************************************************ fn gen_tire() -> (Mesh, Collider) { - let mut tire_mesh: Mesh = Torus::new(0.25, 0.40).into(); - let tire_verts = tire_mesh - .attribute(Mesh::ATTRIBUTE_POSITION) - .unwrap() - .as_float3() - .unwrap() - .iter() - .map(|v| { - // - let v = Vec3::from_array(*v); - let m = Mat3::from_rotation_z(90.0f32.to_radians()); - let p = m.mul_vec3(v); - p.to_array() - }) - .collect::<Vec<[f32; 3]>>(); - tire_mesh.remove_attribute(Mesh::ATTRIBUTE_POSITION); - tire_mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, tire_verts); - - let collider = Collider::convex_hull_from_mesh(&tire_mesh).unwrap(); + let tire_mesh: Mesh = Sphere::new(0.4).into(); + let collider = Collider::sphere(0.4); (tire_mesh, collider) } -fn wheels_helper( - commands: &mut Commands, +fn wheel_mesh( + commands: &mut ChildBuilder, meshes: &mut ResMut<Assets<Mesh>>, materials: &mut ResMut<Assets<StandardMaterial>>, position: Vec3, tire_mesh: Mesh, - collider: Collider, -) -> Entity { + wheel: CyberWheel, +) { let wheel_material = &StandardMaterial { base_color: Color::srgb(0.01, 0.01, 0.01), alpha_mode: AlphaMode::Opaque, @@ -156,47 +182,21 @@ fn wheels_helper( }; let xform = Transform::from_translation(position); - let hub_mesh: Mesh = Sphere::new(0.1).into(); - let hub = commands - .spawn(( - Name::new("hub"), - RigidBody::Dynamic, - MassPropertiesBundle::from_shape(&Collider::sphere(0.1), 200.0), - Mesh3d(meshes.add(hub_mesh)), - MeshMaterial3d(materials.add(wheel_material.clone())), - xform, - )) - .id(); - - let tire = commands - .spawn(( - Name::new("tire"), - Mesh3d(meshes.add(tire_mesh)), - MeshMaterial3d(materials.add(wheel_material.clone())), - xform, - CyberWheel, - RigidBody::Dynamic, - collider, - Friction::new(0.9).with_dynamic_coefficient(0.6), - Restitution::new(0.1), - ColliderDensity(30.0), - CollisionLayers::from_bits(2, 2), - ExternalTorque::ZERO.with_persistence(false), - CollisionMargin(0.05), - SweptCcd::NON_LINEAR, - )) - .id(); - - // connect hubs and tires to make wheels - commands.spawn(RevoluteJoint::new(hub, tire).with_aligned_axis(Vec3::X)); - hub + commands.spawn(( + Name::new("tire"), + Mesh3d(meshes.add(tire_mesh)), + MeshMaterial3d(materials.add(wheel_material.clone())), + xform, + wheel, + )); } pub struct CyberBikePlugin; impl Plugin for CyberBikePlugin { fn build(&self, app: &mut App) { + app.init_resource::<SuspensionConfig>(); app.add_systems(Startup, spawn_bike); } } diff --git a/src/camera.rs b/src/camera.rs index ca4c8cd..75a51c9 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -16,7 +16,7 @@ impl Default for DebugCamOffset { fn default() -> Self { DebugCamOffset { rot: 60.0, - dist: 10.0, + dist: 30.0, alt: 4.0, } }