use bevy::{color::palettes::css::{BLUE, GREEN}, render::mesh::{SphereKind, SphereMeshBuilder}}; use bevy_rapier3d::rapier::prelude::CollisionEventFlags; use games::*; fn main() { App::new() .add_plugins(BaseGamePlugin) .add_systems(Startup, ( setup_physics_scene, position_camera.after(setup_camera) ).chain()) .add_systems(Update, (control_ball, read_events)) .run(); } fn setup_physics_scene( mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut> ) { // Create the ground. // Make this a physical looking object commands .spawn(( Collider::cuboid(100.0, 0.1, 100.0), Transform::from_xyz(0.0, -2.0, 0.0), Mesh3d(meshes.add(Plane3d::new(Vec3::Y, Vec2::splat(50.0)))), MeshMaterial3d(materials.add(StandardMaterial { base_color: RED.into(), ..Default::default() })), )); commands.spawn(( SpotLight { color: WHITE.into(), intensity: 10_000_000.0, shadows_enabled: true, ..default() }, Transform::from_xyz(0.0, 10.0, 10.0).looking_at(Vec3::ZERO, Vec3::Y), )); // Create the bouncing ball. commands .spawn(( RigidBody::Dynamic, GravityScale(1.0), Collider::ball(0.5), ColliderMassProperties::Mass(2.0), Restitution::coefficient(0.7), ExternalImpulse::default(), Transform::from_xyz(0.0, 4.0, 0.0), Marker, ActiveEvents::all(), Mesh3d(meshes.add(SphereMeshBuilder::new( 0.5, SphereKind::Uv { sectors: 10, stacks: 10, }, ))), MeshMaterial3d(materials.add(StandardMaterial { base_color: BLUE.into(), ..Default::default() })), )); // Create a box that the ball can pass into/through // TODO: Transparent box to visualize area commands .spawn(( Sensor, Marker, Collider::cuboid(1.0, 1.0, 1.0), Transform::from_xyz(0.0, 0.0, 0.0), Mesh3d(meshes.add(Cuboid::new(2.0, 2.0, 2.0))), MeshMaterial3d(materials.add(StandardMaterial { base_color: GREEN.with_alpha(0.5).into(), alpha_mode: AlphaMode::Blend, ..Default::default() })), )); } /// Position the world camera to get a better view fn position_camera( mut query: Query<(Entity, &mut Transform), (With, With)>, mut commands: Commands, ) { query.iter_mut().for_each(|(e, mut t)| { *t = Transform::from_xyz(10.0, 10.0, 10.0) .looking_at(Vec3::ZERO, Vec3::Y); }) } fn control_ball( keys: Res>, mut ball: Single<&mut ExternalImpulse>, ) { if keys.pressed(KeyCode::ArrowUp) { ball.torque_impulse = Vec3::new(0.0, 0.0, 0.1); } if keys.pressed(KeyCode::ArrowDown) { ball.torque_impulse = Vec3::new(0.0, 0.0, -0.1); } if keys.pressed(KeyCode::ArrowLeft) { ball.torque_impulse = Vec3::new(0.1, 0.0, 0.0); } if keys.pressed(KeyCode::ArrowRight) { ball.torque_impulse = Vec3::new(-0.1, 0.0, 0.0); } } #[derive(Debug)] enum WithinBounds { Enter(Entity, Entity), Exit(Entity, Entity), } #[derive(Component, Debug)] struct Marker; fn read_events( mut events: EventReader, mut commands: Commands, ) { events.read().filter_map(|collision_event| { match collision_event { CollisionEvent::Started(a, b, flags) => { (*flags == CollisionEventFlags::SENSOR).then_some(WithinBounds::Enter(*a, *b)) }, CollisionEvent::Stopped(a, b, flags) => { (*flags == CollisionEventFlags::SENSOR).then_some(WithinBounds::Exit(*a, *b)) } } }).for_each(|within_bounds| { info!("Event: {:?}", within_bounds); }) }