spawn npcs in order

This commit is contained in:
2025-06-21 12:06:56 +02:00
parent 28ad53fd68
commit 241b96fcc7
8 changed files with 78 additions and 23 deletions

View File

@@ -1117,6 +1117,7 @@
"head" "field medic"
"key" "fence_gate"
"disable_ai" "true"
"spawn_order" "0"
}
// entity 3
{
@@ -1130,6 +1131,7 @@
"head" "field medic"
"angles" "0 180 0"
"disable_ai" "true"
"spawn_order" "1"
}
// entity 5
{
@@ -1386,6 +1388,7 @@
"origin" "2568 4504 -232"
"angles" "0 0 0"
"head" "super market shopper"
"spawn_order" "2"
}
// entity 24
{
@@ -1394,6 +1397,7 @@
"angles" "0 -90 0"
"head" "green grocer"
"key" "fence_shaft"
"spawn_order" "3"
}
// entity 25
{
@@ -1600,8 +1604,8 @@
// entity 45
{
"classname" "enemy_spawn"
"origin" "552 -680 -232"
"angles" "0 90 0"
"origin" "-184 -584 -232"
"angles" "0 0 0"
"head" "commando"
"key" ""
"disable_ai" "true"
@@ -1609,8 +1613,8 @@
// entity 46
{
"classname" "enemy_spawn"
"origin" "456 -680 -232"
"angles" "0 90 0"
"origin" "-184 -504 -232"
"angles" "0 0 0"
"head" "angry demonstrator"
"key" ""
"disable_ai" "true"
@@ -1618,8 +1622,8 @@
// entity 47
{
"classname" "enemy_spawn"
"origin" "360 -680 -232"
"angles" "0 90 0"
"origin" "-184 -440 -232"
"angles" "0 0 0"
"head" "goblin"
"key" ""
"disable_ai" "true"
@@ -1627,8 +1631,8 @@
// entity 48
{
"classname" "enemy_spawn"
"origin" "264 -680 -232"
"angles" "0 90 0"
"origin" "-184 -360 -232"
"angles" "0 0 0"
"head" "green grocer"
"key" ""
"disable_ai" "true"
@@ -1636,8 +1640,8 @@
// entity 49
{
"classname" "enemy_spawn"
"origin" "168 -680 -232"
"angles" "0 90 0"
"origin" "-184 -280 -232"
"angles" "0 0 0"
"head" "highland hammer thrower"
"key" ""
"disable_ai" "true"
@@ -1645,8 +1649,8 @@
// entity 50
{
"classname" "enemy_spawn"
"origin" "72 -680 -232"
"angles" "0 90 0"
"origin" "-184 -184 -232"
"angles" "0 0 0"
"head" "legionnaire"
"key" ""
"disable_ai" "true"
@@ -1654,8 +1658,8 @@
// entity 51
{
"classname" "enemy_spawn"
"origin" "-24 -680 -232"
"angles" "0 90 0"
"origin" "-184 -104 -232"
"angles" "0 0 0"
"head" "mig pilot"
"key" ""
"disable_ai" "true"
@@ -1663,8 +1667,8 @@
// entity 52
{
"classname" "enemy_spawn"
"origin" "-104 -680 -232"
"angles" "0 90 0"
"origin" "-184 -8 -232"
"angles" "0 0 0"
"head" "soldier ant"
"key" ""
"disable_ai" "true"
@@ -1673,7 +1677,7 @@
{
"classname" "enemy_spawn"
"origin" "-184 -680 -232"
"angles" "0 90 0"
"angles" "0 0 0"
"head" "super market shopper"
"key" ""
"disable_ai" "true"

View File

@@ -5,6 +5,7 @@ use crate::{
GameState,
head::ActiveHead,
heads_database::HeadsDatabase,
hitpoints::Hitpoints,
physics_layers::GameLayer,
player::{Player, PlayerBodyMesh},
tb_entities::EnemySpawn,
@@ -68,12 +69,12 @@ fn head_change(
fn update_player_aim(
mut commands: Commands,
potential_targets: Query<(Entity, &Transform), With<EnemySpawn>>,
potential_targets: Query<(Entity, &Transform), With<Hitpoints>>,
player_rot: Query<(&Transform, &GlobalTransform), With<PlayerBodyMesh>>,
mut player_aim: Query<(&AimState, &mut AimTarget), With<Player>>,
mut player_aim: Query<(Entity, &AimState, &mut AimTarget), With<Player>>,
spatial_query: SpatialQuery,
) {
let Some((state, mut aim_target)) = player_aim.iter_mut().next() else {
let Some((player, state, mut aim_target)) = player_aim.iter_mut().next() else {
return;
};
@@ -89,6 +90,10 @@ fn update_player_aim(
let mut target_distance = f32::MAX;
for (e, t) in potential_targets.iter() {
if e == player {
continue;
}
let delta = player_pos - t.translation;
let distance = delta.length();

View File

@@ -54,6 +54,8 @@ pub struct AudioAssets {
pub secret_head_collect: Handle<AudioSource>,
#[asset(path = "sfx/effects/head_drop.ogg")]
pub head_drop: Handle<AudioSource>,
#[asset(path = "sfx/effects/beam_in_out.ogg")]
pub beaming: Handle<AudioSource>,
#[asset(path = "sfx/hit", collection(typed))]
pub hit: Vec<Handle<AudioSource>>,

View File

@@ -2,12 +2,14 @@ use crate::{
GameState,
ai::Ai,
character::AnimatedCharacter,
global_observer,
head::ActiveHead,
head_drop::HeadDrops,
heads::{ActiveHeads, HEAD_COUNT, HeadState},
heads_database::HeadsDatabase,
hitpoints::{Hitpoints, Kill},
keys::KeySpawn,
sounds::PlaySound,
tb_entities::EnemySpawn,
};
use bevy::prelude::*;
@@ -17,11 +19,34 @@ use std::collections::HashMap;
#[reflect(Component)]
pub struct Npc;
pub fn plugin(app: &mut App) {
app.add_systems(OnEnter(GameState::Playing), init);
#[derive(Resource, Reflect, Default)]
#[reflect(Resource)]
struct NpcSpawning {
spawn_index: u32,
}
fn init(mut commands: Commands, query: Query<(Entity, &EnemySpawn)>, heads_db: Res<HeadsDatabase>) {
#[derive(Event)]
struct OnCheckSpawns;
pub fn plugin(app: &mut App) {
app.init_resource::<NpcSpawning>();
app.add_systems(OnEnter(GameState::Playing), setup);
global_observer!(app, on_spawn_check);
}
fn setup(mut commands: Commands) {
commands.init_resource::<NpcSpawning>();
commands.trigger(OnCheckSpawns);
}
fn on_spawn_check(
_trigger: Trigger<OnCheckSpawns>,
mut commands: Commands,
query: Query<(Entity, &EnemySpawn), Without<Npc>>,
heads_db: Res<HeadsDatabase>,
spawning: Res<NpcSpawning>,
) {
//TODO: move into HeadsDatabase
let mut names: HashMap<String, usize> = HashMap::default();
for i in 0..HEAD_COUNT {
@@ -29,6 +54,12 @@ fn init(mut commands: Commands, query: Query<(Entity, &EnemySpawn)>, heads_db: R
}
for (e, spawn) in query.iter() {
if let Some(order) = spawn.spawn_order {
if order > spawning.spawn_index {
continue;
}
}
let id = names[&spawn.head];
commands
.entity(e)
@@ -47,6 +78,8 @@ fn init(mut commands: Commands, query: Query<(Entity, &EnemySpawn)>, heads_db: R
.insert_if(Ai, || !spawn.disable_ai)
.with_child((Name::from("body-rig"), AnimatedCharacter::new(id)))
.observe(on_kill);
commands.trigger(PlaySound::Beaming);
}
}
@@ -59,7 +92,14 @@ fn on_kill(
return;
};
if let Some(order) = enemy.spawn_order {
commands.insert_resource(NpcSpawning {
spawn_index: order + 1,
});
}
commands.trigger(HeadDrops::new(transform.translation, head.0));
commands.trigger(OnCheckSpawns);
commands.entity(trigger.target()).despawn();

View File

@@ -19,6 +19,7 @@ pub enum PlaySound {
Reloaded,
CashHeal,
Crossbow,
Beaming,
Backpack { open: bool },
Head(String),
}
@@ -60,6 +61,7 @@ fn on_spawn_sounds(
PlaySound::HeadCollect => assets.head_collect.clone(),
PlaySound::SecretHeadCollect => assets.secret_head_collect.clone(),
PlaySound::MissileExplosion => assets.missile_explosion.clone(),
PlaySound::Beaming => assets.beaming.clone(),
PlaySound::Backpack { open } => {
if *open {
assets.backpack_open.clone()

View File

@@ -120,6 +120,7 @@ pub struct EnemySpawn {
pub head: String,
pub key: String,
pub disable_ai: bool,
pub spawn_order: Option<u32>,
}
impl EnemySpawn {

View File

@@ -53,6 +53,7 @@
"true" : "true"
"false" : "false"
]
spawn_order(integer) : "spawn_order" : : ""
]
@SolidClass base(__transform, __target) = movable