cyber_rider/src/bike/wheels.rs
2024-07-15 22:47:36 -07:00

174 lines
5.3 KiB
Rust

use avian3d::prelude::*;
use bevy::prelude::{Torus as Tire, *};
use super::{
CyberFork, CyberSpring, CyberSteering, CyberWheel, Meshterial, WheelConfig,
BIKE_WHEEL_COLLISION_GROUP,
};
pub fn spawn_wheels(
commands: &mut Commands,
bike: Entity,
xform: &Transform,
conf: &WheelConfig,
meshterials: &mut Meshterial,
) {
let (membership, filter) = BIKE_WHEEL_COLLISION_GROUP;
let wheels_collision_group = CollisionLayers::new(membership, filter);
let wheel_y = conf.y;
let not_sleeping = SleepingDisabled;
let ccd = SweptCcd::NON_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
let friction = Friction {
dynamic_coefficient: conf.friction,
static_coefficient: conf.friction,
combine_rule: CoefficientCombine::Average,
};
let mut wheel_poses = Vec::with_capacity(2);
// front
{
let wheel_x = 0.0;
let wheel_z = -conf.front_forward;
let offset = Vec3::new(wheel_x, wheel_y, wheel_z);
wheel_poses.push((offset, Some(CyberSteering)));
}
// rear
{
let wheel_x = 0.0;
let wheel_z = conf.rear_back;
let offset = Vec3::new(wheel_x, wheel_y, wheel_z);
wheel_poses.push((offset, None));
}
for (offset, steering) in wheel_poses {
let (mesh, collider) = gen_tires(conf);
let material = StandardMaterial {
base_color: Color::linear_rgba(0.01, 0.01, 0.01, 1.0),
alpha_mode: AlphaMode::Opaque,
perceptual_roughness: 0.5,
..Default::default()
};
let pbr_bundle = PbrBundle {
material: materials.add(material),
mesh: meshes.add(mesh),
..Default::default()
};
let suspension_axis = if steering.is_some() {
rake_vec
} else {
Vec3::Y
};
let wheel = commands
.spawn(pbr_bundle)
.insert((
collider,
ccd,
not_sleeping,
wheels_collision_group,
friction,
CyberWheel,
ExternalForce::default(),
Restitution::new(conf.restitution),
SpatialBundle::default(),
RigidBody::Dynamic,
ColliderDensity(0.1),
AngularVelocity::ZERO,
ExternalTorque::ZERO,
))
.insert(SpatialBundle::from_transform(
xform.with_translation(xform.translation + offset),
))
.id();
let spring = CyberSpring(suspension_axis);
let axel = 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),
))
} else {
commands.spawn((
RigidBody::Dynamic,
ExternalForce::ZERO,
spring,
Collider::sphere(0.1),
ColliderDensity(0.1),
CollisionLayers::from_bits(0, 0),
))
}
.insert(SpatialBundle::from_transform(
xform.with_translation(xform.translation + offset),
))
.id();
let axel_joint = RevoluteJoint::new(axel, wheel).with_aligned_axis(Vec3::NEG_X);
commands.spawn(axel_joint);
// suspension and steering:
if steering.is_some() {
let joint = PrismaticJoint::new(axel, 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)
.with_free_axis(suspension_axis)
.with_local_anchor_2(offset)
.with_limits(limits[0], limits[1]);
commands.spawn(joint);
};
}
}
// do mesh shit
fn gen_tires(conf: &WheelConfig) -> (Mesh, Collider) {
let wheel_rad = conf.radius;
let tire_thickness = conf.thickness;
let tire = Tire {
minor_radius: tire_thickness,
major_radius: wheel_rad,
};
let mut mesh = Mesh::from(tire);
let tire_verts = 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]>>();
mesh.remove_attribute(Mesh::ATTRIBUTE_POSITION);
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, tire_verts);
let mut idxs = Vec::new();
let indices = mesh.indices().unwrap().iter().collect::<Vec<_>>();
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();
(mesh, wheel_collider)
}