166 lines
5 KiB
Rust
166 lines
5 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,
|
|
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,
|
|
))
|
|
.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),
|
|
))
|
|
} else {
|
|
commands.spawn((
|
|
RigidBody::Dynamic,
|
|
ExternalForce::ZERO,
|
|
spring,
|
|
Collider::sphere(0.1),
|
|
ColliderDensity(0.1),
|
|
))
|
|
}
|
|
.insert(SpatialBundle::default())
|
|
.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)
|
|
}
|