161 lines
5.2 KiB
Rust
161 lines
5.2 KiB
Rust
use bevy::prelude::*;
|
|
use bevy_rapier3d::prelude::*;
|
|
|
|
use crate::planet::PLANET_RADIUS;
|
|
|
|
pub(crate) const SPAWN_ALTITUDE: f32 = PLANET_RADIUS * 1.01;
|
|
|
|
#[derive(Component)]
|
|
pub struct CyberBikeBody;
|
|
|
|
#[derive(Component)]
|
|
pub struct CyberBikeCollider;
|
|
|
|
#[derive(Component, Debug)]
|
|
pub struct CyberBikeModel;
|
|
|
|
#[derive(Component, Debug, Default, Clone, Copy)]
|
|
pub struct CyberBikeControl {
|
|
pub roll_sum: f32,
|
|
pub prev_roll_error: f32,
|
|
pub pitch_sum: f32,
|
|
pub prev_pitch_error: f32,
|
|
}
|
|
|
|
const BIKE_BODY_GROUP: InteractionGroups = InteractionGroups::new(0b01, 0b01);
|
|
const BIKE_WHEEL_GROUP: InteractionGroups = InteractionGroups::new(0b10, 0b10);
|
|
|
|
fn spawn_cyberbike(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|
let xform = Transform::from_translation(Vec3::X * SPAWN_ALTITUDE)
|
|
.with_rotation(Quat::from_axis_angle(Vec3::Z, -89.0f32.to_radians()));
|
|
|
|
let mut bbody = RigidBodyBundle::default();
|
|
|
|
bbody.damping.angular_damping = 0.5;
|
|
bbody.damping.linear_damping = 0.1;
|
|
bbody.activation = RigidBodyActivation::cannot_sleep().into();
|
|
|
|
bbody.ccd = RigidBodyCcd {
|
|
ccd_enabled: true,
|
|
ccd_thickness: 0.2,
|
|
ccd_max_dist: 2.7,
|
|
..Default::default()
|
|
}
|
|
.into();
|
|
|
|
let isometry = Isometry::from_parts(xform.translation.into(), xform.rotation.into());
|
|
bbody.position = isometry.into();
|
|
|
|
let shape = ColliderShape::capsule(
|
|
Vec3::new(0.0, 0.0, -2.7).into(),
|
|
Vec3::new(0.0, 0.0, 2.5).into(),
|
|
1.0,
|
|
);
|
|
let bcollide = ColliderBundle {
|
|
shape: shape.into(),
|
|
mass_properties: ColliderMassProps::Density(0.2).into(),
|
|
flags: ColliderFlags {
|
|
collision_groups: BIKE_BODY_GROUP,
|
|
..Default::default()
|
|
}
|
|
.into(),
|
|
material: ColliderMaterial {
|
|
friction: 0.0,
|
|
restitution: 0.0,
|
|
..Default::default()
|
|
}
|
|
.into(),
|
|
..Default::default()
|
|
};
|
|
|
|
let bike = commands
|
|
.spawn_bundle(bbody)
|
|
.insert_bundle((xform, GlobalTransform::default()))
|
|
.insert(RigidBodyPositionSync::Interpolated { prev_pos: None })
|
|
.with_children(|child_builder| {
|
|
child_builder
|
|
.spawn_bundle(bcollide)
|
|
.insert(ColliderDebugRender {
|
|
color: Color::GREEN,
|
|
})
|
|
.insert(CyberBikeCollider)
|
|
.insert(ColliderPositionSync::Discrete);
|
|
})
|
|
.with_children(|rider| {
|
|
rider.spawn_scene(asset_server.load("cyber-bike_no_y_up.glb#Scene0"));
|
|
})
|
|
.insert(CyberBikeModel)
|
|
.insert(CyberBikeBody)
|
|
.insert(CyberBikeControl::default())
|
|
.id();
|
|
|
|
// seriously the cyberbike is so fucking huge what the heck
|
|
let wheel_positions = vec![-5.1, 4.7, -5.1];
|
|
let wheel_y = -1.8f32;
|
|
|
|
for (i, &wheel_z) in wheel_positions.iter().enumerate() {
|
|
let (wheel_x, wheel_rad, stiffness) = match i {
|
|
0 => (-2.6, 1.0, 0.016),
|
|
2 => (2.6, 1.0, 0.016),
|
|
1 => (0.0, 1.2, 0.020),
|
|
_ => unreachable!(),
|
|
};
|
|
let offset = Vec3::new(wheel_x, wheel_y, wheel_z);
|
|
let trans = xform.translation + offset;
|
|
let wheel_pos_in_world = Isometry::from_parts(trans.into(), xform.rotation.into());
|
|
let _wheel_rb = commands
|
|
.spawn_bundle(RigidBodyBundle {
|
|
position: wheel_pos_in_world.into(),
|
|
activation: RigidBodyActivation::cannot_sleep().into(),
|
|
damping: RigidBodyDamping {
|
|
angular_damping: 0.8,
|
|
..Default::default()
|
|
}
|
|
.into(),
|
|
ccd: RigidBodyCcd {
|
|
ccd_enabled: true,
|
|
ccd_max_dist: wheel_rad,
|
|
ccd_thickness: 0.01,
|
|
..Default::default()
|
|
}
|
|
.into(),
|
|
..Default::default()
|
|
})
|
|
.insert_bundle(ColliderBundle {
|
|
material: ColliderMaterial::new(0.0, 0.0).into(),
|
|
shape: ColliderShape::ball(wheel_rad).into(),
|
|
mass_properties: ColliderMassProps::Density(0.001).into(),
|
|
flags: ColliderFlags {
|
|
collision_groups: BIKE_WHEEL_GROUP,
|
|
..Default::default()
|
|
}
|
|
.into(),
|
|
..Default::default()
|
|
})
|
|
.insert(ColliderPositionSync::Discrete)
|
|
.insert(ColliderDebugRender::from(Color::YELLOW))
|
|
.id();
|
|
|
|
let damping = 0.3;
|
|
|
|
let prismatic = PrismaticJoint::new(Vector::y_axis())
|
|
.local_anchor1(offset.into())
|
|
.motor_position(-0.4, stiffness, damping);
|
|
|
|
commands.spawn_bundle(((JointBuilderComponent::new(prismatic, bike, _wheel_rb)),));
|
|
}
|
|
}
|
|
|
|
pub struct CyberBikePlugin;
|
|
impl Plugin for CyberBikePlugin {
|
|
#[cfg(feature = "debug_render")]
|
|
fn build(&self, app: &mut App) {
|
|
app.add_plugin(RapierRenderPlugin)
|
|
.add_startup_system_to_stage(StartupStage::PostStartup, spawn_cyberbike);
|
|
}
|
|
|
|
#[cfg(not(feature = "debug_render"))]
|
|
fn build(&self, app: &mut App) {
|
|
app.add_startup_system_to_stage(StartupStage::PostStartup, spawn_cyberbike);
|
|
}
|
|
}
|