diff --git a/src/action.rs b/src/action.rs index 23fd85f..a37bf6e 100644 --- a/src/action.rs +++ b/src/action.rs @@ -2,7 +2,7 @@ use bevy::prelude::*; use bevy_rapier3d::{na::Vector3, prelude::*}; use crate::{ - colliders::{CyberBikeBody, CyberBikeCollider}, + bike::{CyberBikeBody, CyberBikeCollider}, input::InputState, }; diff --git a/src/bike.rs b/src/bike.rs new file mode 100644 index 0000000..97f0b1c --- /dev/null +++ b/src/bike.rs @@ -0,0 +1,159 @@ +use bevy::prelude::*; +use bevy_rapier3d::prelude::*; + +use crate::planet::PLANET_RADIUS; + +pub(crate) const SPAWN_ALTITUDE: f32 = PLANET_RADIUS * 1.015; + +#[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::X * SPAWN_ALTITUDE) + .looking_at(Vec3::new(PLANET_RADIUS, 1000.0, 0.0), Vec3::X); + + 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(); + + add_wheels(bike, &xform, &mut commands); +} + +fn add_wheels(bike: Entity, xform: &Transform, mut commands: &mut Commands) { + let wheel_collider = ColliderBundle { + material: ColliderMaterial::new(0.0, 0.0).into(), + shape: ColliderShape::ball(0.25).into(), + mass_properties: ColliderMassProps::Density(0.1).into(), + ..Default::default() + }; + + let shock = PrismaticJoint::new(Vector::y_axis()) + .local_anchor1(Vec3::new(-3.0, -3.0, -3.0).into()) + .motor_position(-1.0, 0.02, 0.5); + + let ccd = RigidBodyCcd { + ccd_enabled: true, + ccd_thickness: 0.1, + ccd_max_dist: 0.25, + ..Default::default() + }; + + let mut fw_pos = Isometry::default(); + fw_pos.translation = + (xform.translation + (xform.down() * 4.5 + (xform.forward() * 2.5))).into(); + + let front_wheel_body = RigidBodyBundle { + //activation: RigidBodyActivation::cannot_sleep().into(), + //ccd: ccd.into(), + position: fw_pos.into(), + ..Default::default() + }; + + let front_wheel = commands + .spawn_bundle(front_wheel_body) + .insert_bundle(wheel_collider) + .insert(ColliderPositionSync::Discrete) + .insert(ColliderDebugRender::from(Color::YELLOW)) + .id(); + + //commands.spawn_bundle((JointBuilderComponent::new(shock, bike, + // front_wheel),)); + + // let bw_pos = Isometry::new( + // (xform.translation + xform.down() + xform.back() * 2.0).into(), + // Vec3::ZERO.into(), + // ); + + // let back_wheel_body = RigidBodyBundle { + // activation: RigidBodyActivation::cannot_sleep().into(), + // ccd: ccd.into(), + // position: bw_pos.into(), + // ..Default::default() + // }; + + // let wheel_collider = ColliderBundle { + // material: ColliderMaterial::new(0.0, 0.0).into(), + // // default shape is a 1-meter ball + // ..Default::default() + // }; + + // let back_wheel = commands + // .spawn_bundle(back_wheel_body) + // .insert_bundle(wheel_collider) + // .insert(ColliderPositionSync::Discrete) + // .insert(ColliderDebugRender::from(Color::RED)) + // .id(); + + //commands.spawn_bundle((JointBuilderComponent::new(shock, bike, + // back_wheel),)); +} + +pub struct CyberCollidersPlugin; +impl Plugin for CyberCollidersPlugin { + #[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); + } +} diff --git a/src/camera.rs b/src/camera.rs index d03a231..86c1c3c 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -3,7 +3,7 @@ use bevy::{ render::camera::{ActiveCameras, Camera, CameraPlugin}, }; -use crate::{input::InputState, static_geometry::CyberBikeModel}; +use crate::{bike::CyberBikeModel, input::InputState}; // 85 degrees in radians const MAX_PITCH: f32 = 1.48353; diff --git a/src/colliders.rs b/src/colliders.rs deleted file mode 100644 index 242ce55..0000000 --- a/src/colliders.rs +++ /dev/null @@ -1,213 +0,0 @@ -use bevy::{ - prelude::*, - render::mesh::{Indices, VertexAttributeValues}, -}; -use bevy_rapier3d::prelude::*; - -use crate::static_geometry::{CyberBikeModel, CyberPlanet, PLANET_RADIUS, SPAWN_ALTITUDE}; - -#[derive(Component)] -pub struct CyberBikeBody; - -#[derive(Component)] -pub struct CyberBikeCollider; - -fn setup_colliders( - mut commands: Commands, - meshes: Res>, - planet_query: Query<(Entity, &Handle), With>, - bike_query: Query<(Entity, &Transform), With>, -) { - let (planet, mesh_handle) = planet_query.single(); - - let mesh = meshes.get(mesh_handle).unwrap(); - - let mut shape = ColliderShape::ball(PLANET_RADIUS); - - let vertices = mesh.attribute(Mesh::ATTRIBUTE_POSITION).unwrap(); - if let VertexAttributeValues::Float32x3(verts) = vertices { - if let Some(Indices::U32(indices)) = mesh.indices() { - let mut idxs = Vec::new(); - for idx in indices.chunks_exact(3) { - idxs.push([idx[0], idx[1], idx[2]]); - } - let vertices = verts - .iter() - .map(|p| Point::from_slice(p)) - .collect::>>(); - - shape = ColliderShape::trimesh(vertices, idxs); - } - } - - let pbody = RigidBodyBundle { - body_type: RigidBodyType::Static.into(), - ccd: RigidBodyCcd { - ccd_enabled: true, - ccd_thickness: 2.0, - ccd_max_dist: SPAWN_ALTITUDE, - ..Default::default() - } - .into(), - ..Default::default() - }; - let pcollide = ColliderBundle { - shape: shape.into(), - material: ColliderMaterial { - friction: 0.05, - restitution: 0.00, - ..Default::default() - } - .into(), - ..Default::default() - }; - - commands - .entity(planet) - .insert_bundle(pbody) - .insert_bundle(pcollide); - - // bike - let (bike, xform) = bike_query.single(); - setup_bike_collider(bike, xform, &mut commands); -} - -fn setup_bike_collider(bike: Entity, xform: &Transform, commands: &mut Commands) { - 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.7, - ccd_max_dist: 1.5, - ..Default::default() - } - .into(); - - let isometry = Isometry::from_parts(xform.translation.into(), xform.rotation.into()); - bbody.position = isometry.into(); - - // collider - 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() - }; - commands - .entity(bike) - .insert_bundle(bbody) - .insert(CyberBikeBody) - .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); - }); - - /* { - let wheel_collider = ColliderBundle { - material: ColliderMaterial::new(0.0, 0.0).into(), - shape: ColliderShape::ball(0.25).into(), - mass_properties: ColliderMassProps::Density(0.1).into(), - ..Default::default() - }; - - let shock = PrismaticJoint::new(Vector::y_axis()) - .local_anchor1(Vec3::new(-3.0, -3.0, -3.0).into()) - .motor_position(-1.0, 0.02, 0.5); - - let ccd = RigidBodyCcd { - ccd_enabled: true, - ccd_thickness: 0.1, - ccd_max_dist: 0.25, - ..Default::default() - }; - - let mut fw_pos = Isometry::default(); - fw_pos.translation = - (xform.translation + (xform.down() * 4.5 + (xform.forward() * 2.5))).into(); - - let front_wheel_body = RigidBodyBundle { - //activation: RigidBodyActivation::cannot_sleep().into(), - //ccd: ccd.into(), - position: fw_pos.into(), - ..Default::default() - }; - - let front_wheel = commands - .spawn_bundle(front_wheel_body) - .insert_bundle(wheel_collider) - .insert(ColliderPositionSync::Discrete) - .insert(ColliderDebugRender::from(Color::YELLOW)) - .id(); - - //commands.spawn_bundle((JointBuilderComponent::new(shock, bike, front_wheel),)); - - // let bw_pos = Isometry::new( - // (xform.translation + xform.down() + xform.back() * 2.0).into(), - // Vec3::ZERO.into(), - // ); - - // let back_wheel_body = RigidBodyBundle { - // activation: RigidBodyActivation::cannot_sleep().into(), - // ccd: ccd.into(), - // position: bw_pos.into(), - // ..Default::default() - // }; - - // let wheel_collider = ColliderBundle { - // material: ColliderMaterial::new(0.0, 0.0).into(), - // // default shape is a 1-meter ball - // ..Default::default() - // }; - - // let back_wheel = commands - // .spawn_bundle(back_wheel_body) - // .insert_bundle(wheel_collider) - // .insert(ColliderPositionSync::Discrete) - // .insert(ColliderDebugRender::from(Color::RED)) - // .id(); - - //commands.spawn_bundle((JointBuilderComponent::new(shock, bike, - // back_wheel),)); - - }; */ -} - -pub struct CyberCollidersPlugin; -impl Plugin for CyberCollidersPlugin { - #[cfg(feature = "debug_render")] - fn build(&self, app: &mut App) { - app.add_plugin(RapierRenderPlugin) - .add_startup_system_to_stage( - StartupStage::PostStartup, - setup_colliders.label("colliders"), - ); - } - - #[cfg(not(feature = "debug_render"))] - fn build(&self, app: &mut App) { - app.add_startup_system_to_stage( - StartupStage::PostStartup, - setup_colliders.label("colliders"), - ); - } -} diff --git a/src/glamor.rs b/src/glamor.rs index 60d3412..fccc493 100644 --- a/src/glamor.rs +++ b/src/glamor.rs @@ -10,7 +10,7 @@ use bevy::{ use bevy_polyline::{Polyline, PolylineBundle, PolylineMaterial, PolylinePlugin}; use rand::{thread_rng, Rng}; -use crate::{lights::AnimateCyberLightWireframe, static_geometry::CyberPlanet}; +use crate::{lights::AnimateCyberLightWireframe, planet::CyberPlanet}; pub const BISEXY_COLOR: Color = Color::hsla(292.0, 0.9, 0.60, 1.1); diff --git a/src/lib.rs b/src/lib.rs index 2b4190f..76e95ea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,12 +4,12 @@ use bevy::{ }; pub mod action; +pub mod bike; pub mod camera; -pub mod colliders; pub mod glamor; pub mod input; pub mod lights; -pub mod static_geometry; +pub mod planet; pub mod ui; #[derive(Clone, Debug, Hash, PartialEq, Eq, SystemLabel, StageLabel)] diff --git a/src/lights.rs b/src/lights.rs index ad42c09..5f41872 100644 --- a/src/lights.rs +++ b/src/lights.rs @@ -3,7 +3,7 @@ use std::f32::consts::TAU; use bevy::prelude::*; use rand::prelude::*; -use crate::static_geometry::PLANET_RADIUS; +use crate::planet::PLANET_RADIUS; pub const LIGHT_RANGE: f32 = 90.0; diff --git a/src/main.rs b/src/main.rs index 0ebacf9..aa114a3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,9 +2,9 @@ use bevy::prelude::*; use cyber_rider::{ action::{CyberActionPlugin, MovementSettings}, camera::CyberCamPlugin, - colliders::CyberCollidersPlugin, + bike::CyberCollidersPlugin, disable_mouse_trap, - static_geometry::CyberGeomPlugin, + planet::CyberGeomPlugin, glamor::CyberGlamorPlugin, input::CyberInputPlugin, lights::CyberSpaceLightsPlugin, diff --git a/src/static_geometry.rs b/src/planet.rs similarity index 74% rename from src/static_geometry.rs rename to src/planet.rs index a481b89..6afa681 100644 --- a/src/static_geometry.rs +++ b/src/planet.rs @@ -2,6 +2,7 @@ use bevy::{ prelude::{shape::Icosphere, *}, render::mesh::Indices, }; +use bevy_rapier3d::prelude::*; use hexasphere::shapes::IcoSphere; use noise::{HybridMulti, NoiseFn, SuperSimplex}; use wgpu::PrimitiveTopology; @@ -9,10 +10,6 @@ use wgpu::PrimitiveTopology; use crate::Label; pub const PLANET_RADIUS: f32 = 5000.0; -pub(crate) const SPAWN_ALTITUDE: f32 = PLANET_RADIUS * 1.015; - -#[derive(Component, Debug)] -pub struct CyberBikeModel; #[derive(Component)] pub struct CyberPlanet; @@ -23,16 +20,32 @@ fn spawn_planet( mut materials: ResMut>, ) { let color = Color::rgb(0.2, 0.1, 0.2); - let isphere = shape::Icosphere { + let isphere = Icosphere { radius: PLANET_RADIUS, subdivisions: 79, }; - let pmesh = gen_planet(isphere); + let (mesh, shape) = gen_planet(isphere); + + let pbody = RigidBodyBundle { + body_type: RigidBodyType::Static.into(), + ..Default::default() + }; + + let pcollide = ColliderBundle { + shape: shape.into(), + material: ColliderMaterial { + friction: 0.05, + restitution: 0.00, + ..Default::default() + } + .into(), + ..Default::default() + }; commands .spawn_bundle(PbrBundle { - mesh: meshes.add(pmesh), + mesh: meshes.add(mesh), material: materials.add(StandardMaterial { base_color: color, metallic: 0.1, @@ -43,30 +56,15 @@ fn spawn_planet( ..Default::default() }) + .insert_bundle(pbody) + .insert_bundle(pcollide) .insert(CyberPlanet); } -fn spawn_cyberbike(mut commands: Commands, asset_server: Res) { - commands - .spawn_bundle(( - Transform { - translation: Vec3::new(SPAWN_ALTITUDE, 0.0, 0.0), - ..Default::default() - } - .looking_at(Vec3::new(PLANET_RADIUS, 1000.0, 0.0), Vec3::X), - GlobalTransform::identity(), - )) - .with_children(|rider| { - rider.spawn_scene(asset_server.load("cyber-bike_no_y_up.glb#Scene0")); - }) - .insert(CyberBikeModel); -} - pub struct CyberGeomPlugin; impl Plugin for CyberGeomPlugin { fn build(&self, app: &mut App) { - app.add_startup_system(spawn_planet.label(Label::Geometry)) - .add_startup_system(spawn_cyberbike.label(Label::Geometry)); + app.add_startup_system(spawn_planet.label(Label::Geometry)); } } @@ -74,7 +72,7 @@ impl Plugin for CyberGeomPlugin { // utils //--------------------------------------------------------------------- -fn gen_planet(sphere: Icosphere) -> Mesh { +fn gen_planet(sphere: Icosphere) -> (Mesh, ColliderShape) { // straight-up stolen from Bevy's impl of Mesh from Icosphere, so I can do the // displacement before normals are calculated. let generated = IcoSphere::new(sphere.subdivisions, |point| { @@ -112,11 +110,18 @@ fn gen_planet(sphere: Icosphere) -> Mesh { generated.get_indices(i, &mut indices); } + let mut idxs = Vec::new(); + for idx in indices.chunks_exact(3) { + idxs.push([idx[0], idx[1], idx[2]]); + } + + let shape = ColliderShape::trimesh(points.iter().map(|p| Point::from_slice(p)).collect(), idxs); + let indices = Indices::U32(indices); let mut mesh = Mesh::new(PrimitiveTopology::TriangleList); mesh.set_indices(Some(indices)); mesh.set_attribute(Mesh::ATTRIBUTE_POSITION, points); mesh.set_attribute(Mesh::ATTRIBUTE_UV_0, uvs); - mesh + (mesh, shape) } diff --git a/src/ui.rs b/src/ui.rs index f2f3de1..6292c9f 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,7 +1,7 @@ use bevy::prelude::*; use bevy_rapier3d::prelude::*; -use crate::colliders::CyberBikeBody; +use crate::bike::CyberBikeBody; #[derive(Component)] struct UpText;