use crate::{ GameState, billboards::Billboard, global_observer, loading_assets::GameAssets, physics_layers::GameLayer, player::Player, sounds::PlaySound, squish_animation::SquishAnimation, }; use avian3d::prelude::*; use bevy::prelude::*; use std::f32::consts::PI; #[derive(Event, Reflect)] pub struct KeySpawn(pub Vec3, pub String); #[derive(Component, Reflect)] #[reflect(Component)] struct Key(pub String); #[derive(Event, Reflect)] pub struct KeyCollected(pub String); pub fn plugin(app: &mut App) { app.add_systems(Update, collect_key.run_if(in_state(GameState::Playing))); global_observer!(app, on_spawn_key); } fn on_spawn_key(trigger: Trigger, mut commands: Commands, assets: Res) { let KeySpawn(position, id) = trigger.event(); let angle = rand::random::() * PI * 2.; let spawn_dir = Quat::from_rotation_y(angle) * Vec3::new(0.5, 0.6, 0.).normalize(); commands.spawn(( Name::new("key"), Key(id.clone()), Transform::from_translation(*position), Visibility::default(), Collider::sphere(1.5), ExternalImpulse::new(spawn_dir * 180.).with_persistence(false), LockedAxes::ROTATION_LOCKED, RigidBody::Dynamic, CollisionLayers::new(LayerMask(GameLayer::Collectibles.to_bits()), LayerMask::ALL), CollisionEventsEnabled, Restitution::new(0.6), Children::spawn(Spawn(( Billboard, SquishAnimation(2.6), SceneRoot(assets.mesh_key.clone()), ))), )); } fn collect_key( mut commands: Commands, mut collision_event_reader: EventReader, query_player: Query<&Player>, query_collectable: Query<&Key>, ) { for CollisionStarted(e1, e2) in collision_event_reader.read() { let collectable = if query_player.contains(*e1) && query_collectable.contains(*e2) { *e2 } else if query_player.contains(*e2) && query_collectable.contains(*e1) { *e1 } else { continue; }; let key = query_collectable.get(collectable).unwrap(); commands.trigger(PlaySound::KeyCollect); commands.trigger(KeyCollected(key.0.clone())); commands.entity(collectable).despawn(); } }