diff --git a/crates/bevy_xpbd_3d/examples/cast_ray_predicate.rs b/crates/bevy_xpbd_3d/examples/cast_ray_predicate.rs new file mode 100644 index 00000000..95e61466 --- /dev/null +++ b/crates/bevy_xpbd_3d/examples/cast_ray_predicate.rs @@ -0,0 +1,200 @@ +#![allow(clippy::unnecessary_cast)] + +use bevy::{pbr::NotShadowReceiver, prelude::*}; +use bevy_xpbd_3d::{math::*, prelude::*}; +use examples_common_3d::XpbdExamplePlugin; + +fn main() { + App::new() + .add_plugins((DefaultPlugins, XpbdExamplePlugin)) + .insert_resource(ClearColor(Color::rgb(0.05, 0.05, 0.1))) + .insert_resource(Msaa::Sample4) + .add_systems(Startup, setup) + .add_systems(Update, (movement, reset_colors, raycast).chain()) + .run(); +} + +/// The acceleration used for movement. +#[derive(Component)] +struct MovementAcceleration(Scalar); + +#[derive(Component)] +struct RayIndicator; + +/// If to be ignored by raycast +#[derive(Component)] +struct OutOfGlass(bool); + +const CUBE_COLOR: Color = Color::rgba(0.2, 0.7, 0.9, 1.0); +const CUBE_COLOR_GLASS: Color = Color::rgba(0.2, 0.7, 0.9, 0.5); + +fn setup( + mut commands: Commands, + mut materials: ResMut>, + mut meshes: ResMut>, +) { + let cube_mesh = meshes.add(Mesh::from(shape::Cube { size: 1.0 })); + + // Ground + commands.spawn(( + PbrBundle { + mesh: cube_mesh.clone(), + material: materials.add(Color::rgb(0.7, 0.7, 0.8).into()), + transform: Transform::from_xyz(0.0, -2.0, 0.0).with_scale(Vec3::new(100.0, 1.0, 100.0)), + ..default() + }, + RigidBody::Static, + Collider::cuboid(1.0, 1.0, 1.0), + )); + + let cube_size = 2.0; + + // Spawn cube stacks + for x in -1..2 { + for y in -1..2 { + for z in -1..2 { + let position = Vec3::new(x as f32, y as f32 + 5.0, z as f32) * (cube_size + 0.05); + let material: StandardMaterial = if x == -1 { + CUBE_COLOR_GLASS.into() + } else { + CUBE_COLOR.into() + }; + commands.spawn(( + PbrBundle { + mesh: cube_mesh.clone(), + material: materials.add(material.clone()), + transform: Transform::from_translation(position) + .with_scale(Vec3::splat(cube_size as f32)), + ..default() + }, + RigidBody::Dynamic, + Collider::cuboid(1.0, 1.0, 1.0), + MovementAcceleration(10.0), + OutOfGlass(x == -1), + )); + } + } + } + + // raycast indicator + commands.spawn(( + PbrBundle { + mesh: cube_mesh.clone(), + material: materials.add(Color::rgb(1.0, 0.0, 0.0).into()), + transform: Transform::from_xyz(-500.0, 2.0, 0.0) + .with_scale(Vec3::new(1000.0, 0.1, 0.1)), + ..default() + }, + RayIndicator, + NotShadowReceiver, + )); + + // Directional light + commands.spawn(DirectionalLightBundle { + directional_light: DirectionalLight { + illuminance: 20_000.0, + shadows_enabled: true, + ..default() + }, + transform: Transform::default().looking_at(Vec3::new(-1.0, -2.5, -1.5), Vec3::Y), + ..default() + }); + + // Camera + commands.spawn(Camera3dBundle { + transform: Transform::from_translation(Vec3::new(0.0, 12.0, 40.0)) + .looking_at(Vec3::Y * 5.0, Vec3::Y), + ..default() + }); +} + +fn movement( + time: Res