enemy can drop key

This commit is contained in:
2025-03-13 11:05:56 +01:00
parent 8946289ac2
commit c358108c56
7 changed files with 104 additions and 16 deletions

View File

@@ -629,6 +629,7 @@
"origin" "648 -680 -248" "origin" "648 -680 -248"
"angles" "0 -90 0" "angles" "0 -90 0"
"head" "field medic" "head" "field medic"
"has_key" "true"
} }
// entity 3 // entity 3
{ {

View File

@@ -1,4 +1,4 @@
use crate::{movables::TriggerMovableEvent, npc::KeyCollected}; use crate::{keys::KeyCollected, movables::TriggerMovableEvent};
use bevy::{prelude::*, utils::hashbrown::HashSet}; use bevy::{prelude::*, utils::hashbrown::HashSet};
#[derive(Resource)] #[derive(Resource)]
@@ -26,11 +26,6 @@ fn on_key(
AudioPlayer::new(asset_server.load("sfx/effects/gate.ogg")), AudioPlayer::new(asset_server.load("sfx/effects/gate.ogg")),
PlaybackSettings::DESPAWN, 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"] let entities: HashSet<_> = vec!["fence_01", "fence_02"]
.into_iter() .into_iter()

80
src/keys.rs Normal file
View File

@@ -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<KeySpawn>,
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
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<CollisionStarted>,
query_player: Query<&Player>,
query_collectable: Query<&Key>,
asset_server: Res<AssetServer>,
) {
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();
}
}
}

View File

@@ -5,6 +5,7 @@ mod camera;
mod cash; mod cash;
mod gates; mod gates;
mod heads_ui; mod heads_ui;
mod keys;
mod movables; mod movables;
mod npc; mod npc;
mod platforms; mod platforms;
@@ -61,12 +62,14 @@ fn main() {
// }); // });
app.add_plugins(PhysicsPlugins::default()); app.add_plugins(PhysicsPlugins::default());
// app.add_plugins(PhysicsDebugPlugin::default());
app.add_plugins(( app.add_plugins((
TnuaControllerPlugin::new(FixedUpdate), TnuaControllerPlugin::new(FixedUpdate),
TnuaAvian3dPlugin::new(FixedUpdate), TnuaAvian3dPlugin::new(FixedUpdate),
)); ));
// app.add_plugins(PhysicsDebugPlugin::default());
// app.add_plugins(bevy_inspector_egui::quick::WorldInspectorPlugin::default());
app.add_systems(Update, Dolly::<MainCamera>::update_active); app.add_systems(Update, Dolly::<MainCamera>::update_active);
app.add_plugins(alien::plugin); app.add_plugins(alien::plugin);
@@ -80,12 +83,12 @@ fn main() {
app.add_plugins(aim::plugin); app.add_plugins(aim::plugin);
app.add_plugins(shooting::plugin); app.add_plugins(shooting::plugin);
app.add_plugins(npc::plugin); app.add_plugins(npc::plugin);
app.add_plugins(keys::plugin);
app.insert_resource(AmbientLight { app.insert_resource(AmbientLight {
color: Color::WHITE, color: Color::WHITE,
brightness: 400., brightness: 400.,
}); });
app.add_plugins(bevy_inspector_egui::quick::WorldInspectorPlugin::default());
app.add_plugins(TrenchBroomPlugin(TrenchBroomConfig::new("hedz"))); app.add_plugins(TrenchBroomPlugin(TrenchBroomConfig::new("hedz")));

View File

@@ -1,4 +1,4 @@
use crate::tb_entities::EnemySpawn; use crate::{keys::KeySpawn, tb_entities::EnemySpawn};
use bevy::prelude::*; use bevy::prelude::*;
#[derive(Event, Reflect)] #[derive(Event, Reflect)]
@@ -6,10 +6,6 @@ pub struct Hit {
pub damage: u32, pub damage: u32,
} }
// TODO: add actual keys
#[derive(Event, Reflect)]
pub struct KeyCollected;
#[derive(Component, Reflect)] #[derive(Component, Reflect)]
struct Hp(i32); struct Hp(i32);
@@ -23,10 +19,14 @@ fn init(mut commands: Commands, query: Query<Entity, (With<EnemySpawn>, Without<
} }
} }
fn on_hit(trigger: Trigger<Hit>, mut commands: Commands, mut query: Query<&mut Hp>) { fn on_hit(
trigger: Trigger<Hit>,
mut commands: Commands,
mut query: Query<(&mut Hp, &Transform, &EnemySpawn)>,
) {
let Hit { damage } = trigger.event(); 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; return;
}; };
@@ -36,6 +36,9 @@ fn on_hit(trigger: Trigger<Hit>, mut commands: Commands, mut query: Query<&mut H
if hp.0 <= 0 { if hp.0 <= 0 {
commands.entity(trigger.entity()).despawn_recursive(); commands.entity(trigger.entity()).despawn_recursive();
commands.trigger(KeyCollected);
if enemy.has_key {
commands.trigger(KeySpawn(transform.translation));
}
} }
} }

View File

@@ -85,6 +85,7 @@ pub struct MoveTarget {
#[model({ "path": "models/alien_naked.glb" })] #[model({ "path": "models/alien_naked.glb" })]
pub struct EnemySpawn { pub struct EnemySpawn {
pub head: String, pub head: String,
pub has_key: bool,
} }
impl EnemySpawn { impl EnemySpawn {

View File

@@ -67,6 +67,11 @@
@PointClass base(transform) model({ "path": "models/alien_naked.glb" }) = enemy_spawn @PointClass base(transform) model({ "path": "models/alien_naked.glb" }) = enemy_spawn
[ [
head(string) : "head" : "" : "" head(string) : "head" : "" : ""
has_key(choices) : "has_key" : "false" : "" =
[
"true" : "true"
"false" : "false"
]
] ]
@SolidClass base(transform, target) = movable @SolidClass base(transform, target) = movable