use bevy::prelude::*; use bevy_rapier3d::prelude::*; use crate::planet::PLANET_RADIUS; pub(crate) const SPAWN_ALTITUDE: f32 = PLANET_RADIUS * 1.015 + 90.0; #[derive(Component)] pub struct CyberBikeBody; #[derive(Component)] pub struct CyberBikeCollider; #[derive(Component, Debug)] pub struct CyberBikeModel; fn spawn_cyberbike(mut commands: Commands, asset_server: Res) { let xform = Transform::from_translation(Vec3::Y * SPAWN_ALTITUDE) .with_rotation(Quat::from_axis_angle(Vec3::X, -80.0f32.to_radians())); let mut bbody = RigidBodyBundle::default(); bbody.damping.angular_damping = 0.8; 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.04).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) .id(); // seriously the cyberbike is so fucking huge what the heck let wheel_positions = vec![-5.5, 4.7]; let wheel_rad = 0.7; let wheel_y = -2.0; for wheel_z in wheel_positions { let offset = Vec3::new(0.0, 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(), ccd: RigidBodyCcd { ccd_enabled: true, ccd_max_dist: wheel_rad, ccd_thickness: 0.1, ..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.01).into(), ..Default::default() }) .insert(ColliderPositionSync::Discrete) .insert(ColliderDebugRender::from(Color::YELLOW)) .id(); let (stiffness, damping) = (0.1, 0.4); let prismatic = PrismaticJoint::new(Vector::y_axis()) .local_anchor1(offset.into()) .motor_position(-0.1, 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); } }