From c358108c561025345327a20bbbd0533dc54e3ca4 Mon Sep 17 00:00:00 2001 From: extrawurst Date: Thu, 13 Mar 2025 11:05:56 +0100 Subject: [PATCH] enemy can drop key --- assets/maps/map1.map | 1 + src/gates.rs | 7 +--- src/keys.rs | 80 +++++++++++++++++++++++++++++++++++++++ src/main.rs | 7 +++- src/npc.rs | 19 ++++++---- src/tb_entities.rs | 1 + trenchbroom/hedz/hedz.fgd | 5 +++ 7 files changed, 104 insertions(+), 16 deletions(-) create mode 100644 src/keys.rs diff --git a/assets/maps/map1.map b/assets/maps/map1.map index bccdbb2..d13cf08 100644 --- a/assets/maps/map1.map +++ b/assets/maps/map1.map @@ -629,6 +629,7 @@ "origin" "648 -680 -248" "angles" "0 -90 0" "head" "field medic" +"has_key" "true" } // entity 3 { diff --git a/src/gates.rs b/src/gates.rs index 76953ae..7b94a42 100644 --- a/src/gates.rs +++ b/src/gates.rs @@ -1,4 +1,4 @@ -use crate::{movables::TriggerMovableEvent, npc::KeyCollected}; +use crate::{keys::KeyCollected, movables::TriggerMovableEvent}; use bevy::{prelude::*, utils::hashbrown::HashSet}; #[derive(Resource)] @@ -26,11 +26,6 @@ fn on_key( AudioPlayer::new(asset_server.load("sfx/effects/gate.ogg")), PlaybackSettings::DESPAWN, )); - //TODO: put into actual key collect once we have that - commands.spawn(( - AudioPlayer::new(asset_server.load("sfx/effects/key_collect.ogg")), - PlaybackSettings::DESPAWN, - )); let entities: HashSet<_> = vec!["fence_01", "fence_02"] .into_iter() diff --git a/src/keys.rs b/src/keys.rs new file mode 100644 index 0000000..1b43f2e --- /dev/null +++ b/src/keys.rs @@ -0,0 +1,80 @@ +use crate::player::Player; +use avian3d::prelude::*; +use bevy::prelude::*; +use std::f32::consts::PI; + +#[derive(Event, Reflect)] +pub struct KeySpawn(pub Vec3); + +#[derive(Component, Reflect)] +#[reflect(Component)] +struct Key; + +#[derive(Event, Reflect)] +pub struct KeyCollected; + +pub fn plugin(app: &mut App) { + app.add_systems(Update, collect_key); + app.add_observer(on_spawn); +} + +fn on_spawn( + trigger: Trigger, + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, +) { + let KeySpawn(position) = trigger.event(); + + let mesh = meshes.add(Cylinder::default()); + + //TODO: randomize + let spawn_dir = Quat::from_rotation_y(PI / 2.) * Vec3::new(0.5, 0.6, 0.).normalize(); + + commands + .spawn(( + Name::new("key"), + Key, + 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(( + Transform::from_scale(Vec3::new(2.2, 0.4, 2.2)) + .with_rotation(Quat::from_rotation_x(PI / 2.)), + Mesh3d(mesh), + MeshMaterial3d(materials.add(Color::srgb(0., 0., 0.9))), + )); +} + +fn collect_key( + mut commands: Commands, + mut collision_event_reader: EventReader, + query_player: Query<&Player>, + query_collectable: Query<&Key>, + asset_server: Res, +) { + for CollisionStarted(e1, e2) in collision_event_reader.read() { + let collectable = if query_player.contains(*e1) && query_collectable.contains(*e2) { + Some(*e2) + } else if query_player.contains(*e2) && query_collectable.contains(*e1) { + Some(*e1) + } else { + None + }; + + if let Some(collectable) = collectable { + commands.spawn(( + AudioPlayer::new(asset_server.load("sfx/effects/key_collect.ogg")), + PlaybackSettings::DESPAWN, + )); + + commands.trigger(KeyCollected); + commands.entity(collectable).despawn_recursive(); + } + } +} diff --git a/src/main.rs b/src/main.rs index d30d527..fccda75 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ mod camera; mod cash; mod gates; mod heads_ui; +mod keys; mod movables; mod npc; mod platforms; @@ -61,12 +62,14 @@ fn main() { // }); app.add_plugins(PhysicsPlugins::default()); - // app.add_plugins(PhysicsDebugPlugin::default()); app.add_plugins(( TnuaControllerPlugin::new(FixedUpdate), TnuaAvian3dPlugin::new(FixedUpdate), )); + // app.add_plugins(PhysicsDebugPlugin::default()); + // app.add_plugins(bevy_inspector_egui::quick::WorldInspectorPlugin::default()); + app.add_systems(Update, Dolly::::update_active); app.add_plugins(alien::plugin); @@ -80,12 +83,12 @@ fn main() { app.add_plugins(aim::plugin); app.add_plugins(shooting::plugin); app.add_plugins(npc::plugin); + app.add_plugins(keys::plugin); app.insert_resource(AmbientLight { color: Color::WHITE, brightness: 400., }); - app.add_plugins(bevy_inspector_egui::quick::WorldInspectorPlugin::default()); app.add_plugins(TrenchBroomPlugin(TrenchBroomConfig::new("hedz"))); diff --git a/src/npc.rs b/src/npc.rs index 3df77e7..32dc978 100644 --- a/src/npc.rs +++ b/src/npc.rs @@ -1,4 +1,4 @@ -use crate::tb_entities::EnemySpawn; +use crate::{keys::KeySpawn, tb_entities::EnemySpawn}; use bevy::prelude::*; #[derive(Event, Reflect)] @@ -6,10 +6,6 @@ pub struct Hit { pub damage: u32, } -// TODO: add actual keys -#[derive(Event, Reflect)] -pub struct KeyCollected; - #[derive(Component, Reflect)] struct Hp(i32); @@ -23,10 +19,14 @@ fn init(mut commands: Commands, query: Query, Without< } } -fn on_hit(trigger: Trigger, mut commands: Commands, mut query: Query<&mut Hp>) { +fn on_hit( + trigger: Trigger, + mut commands: Commands, + mut query: Query<(&mut Hp, &Transform, &EnemySpawn)>, +) { let Hit { damage } = trigger.event(); - let Ok(mut hp) = query.get_mut(trigger.entity()) else { + let Ok((mut hp, transform, enemy)) = query.get_mut(trigger.entity()) else { return; }; @@ -36,6 +36,9 @@ fn on_hit(trigger: Trigger, mut commands: Commands, mut query: Query<&mut H if hp.0 <= 0 { commands.entity(trigger.entity()).despawn_recursive(); - commands.trigger(KeyCollected); + + if enemy.has_key { + commands.trigger(KeySpawn(transform.translation)); + } } } diff --git a/src/tb_entities.rs b/src/tb_entities.rs index 20a1957..61ecdf4 100644 --- a/src/tb_entities.rs +++ b/src/tb_entities.rs @@ -85,6 +85,7 @@ pub struct MoveTarget { #[model({ "path": "models/alien_naked.glb" })] pub struct EnemySpawn { pub head: String, + pub has_key: bool, } impl EnemySpawn { diff --git a/trenchbroom/hedz/hedz.fgd b/trenchbroom/hedz/hedz.fgd index 98f82c4..7dd3700 100644 --- a/trenchbroom/hedz/hedz.fgd +++ b/trenchbroom/hedz/hedz.fgd @@ -67,6 +67,11 @@ @PointClass base(transform) model({ "path": "models/alien_naked.glb" }) = enemy_spawn [ head(string) : "head" : "" : "" + has_key(choices) : "has_key" : "false" : "" = + [ + "true" : "true" + "false" : "false" + ] ] @SolidClass base(transform, target) = movable