use crate::{ GameState, billboards::Billboard, 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))); app.add_observer(on_spawn); } fn on_spawn(trigger: Trigger, mut commands: Commands, asset_server: 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(); let mesh = asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/key.glb")); 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, Restitution::new(0.6), )) .with_child((Billboard, SquishAnimation(2.6), SceneRoot(mesh))); } 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_recursive(); } }