spawn npcs in order
This commit is contained in:
@@ -1117,6 +1117,7 @@
|
|||||||
"head" "field medic"
|
"head" "field medic"
|
||||||
"key" "fence_gate"
|
"key" "fence_gate"
|
||||||
"disable_ai" "true"
|
"disable_ai" "true"
|
||||||
|
"spawn_order" "0"
|
||||||
}
|
}
|
||||||
// entity 3
|
// entity 3
|
||||||
{
|
{
|
||||||
@@ -1130,6 +1131,7 @@
|
|||||||
"head" "field medic"
|
"head" "field medic"
|
||||||
"angles" "0 180 0"
|
"angles" "0 180 0"
|
||||||
"disable_ai" "true"
|
"disable_ai" "true"
|
||||||
|
"spawn_order" "1"
|
||||||
}
|
}
|
||||||
// entity 5
|
// entity 5
|
||||||
{
|
{
|
||||||
@@ -1386,6 +1388,7 @@
|
|||||||
"origin" "2568 4504 -232"
|
"origin" "2568 4504 -232"
|
||||||
"angles" "0 0 0"
|
"angles" "0 0 0"
|
||||||
"head" "super market shopper"
|
"head" "super market shopper"
|
||||||
|
"spawn_order" "2"
|
||||||
}
|
}
|
||||||
// entity 24
|
// entity 24
|
||||||
{
|
{
|
||||||
@@ -1394,6 +1397,7 @@
|
|||||||
"angles" "0 -90 0"
|
"angles" "0 -90 0"
|
||||||
"head" "green grocer"
|
"head" "green grocer"
|
||||||
"key" "fence_shaft"
|
"key" "fence_shaft"
|
||||||
|
"spawn_order" "3"
|
||||||
}
|
}
|
||||||
// entity 25
|
// entity 25
|
||||||
{
|
{
|
||||||
@@ -1600,8 +1604,8 @@
|
|||||||
// entity 45
|
// entity 45
|
||||||
{
|
{
|
||||||
"classname" "enemy_spawn"
|
"classname" "enemy_spawn"
|
||||||
"origin" "552 -680 -232"
|
"origin" "-184 -584 -232"
|
||||||
"angles" "0 90 0"
|
"angles" "0 0 0"
|
||||||
"head" "commando"
|
"head" "commando"
|
||||||
"key" ""
|
"key" ""
|
||||||
"disable_ai" "true"
|
"disable_ai" "true"
|
||||||
@@ -1609,8 +1613,8 @@
|
|||||||
// entity 46
|
// entity 46
|
||||||
{
|
{
|
||||||
"classname" "enemy_spawn"
|
"classname" "enemy_spawn"
|
||||||
"origin" "456 -680 -232"
|
"origin" "-184 -504 -232"
|
||||||
"angles" "0 90 0"
|
"angles" "0 0 0"
|
||||||
"head" "angry demonstrator"
|
"head" "angry demonstrator"
|
||||||
"key" ""
|
"key" ""
|
||||||
"disable_ai" "true"
|
"disable_ai" "true"
|
||||||
@@ -1618,8 +1622,8 @@
|
|||||||
// entity 47
|
// entity 47
|
||||||
{
|
{
|
||||||
"classname" "enemy_spawn"
|
"classname" "enemy_spawn"
|
||||||
"origin" "360 -680 -232"
|
"origin" "-184 -440 -232"
|
||||||
"angles" "0 90 0"
|
"angles" "0 0 0"
|
||||||
"head" "goblin"
|
"head" "goblin"
|
||||||
"key" ""
|
"key" ""
|
||||||
"disable_ai" "true"
|
"disable_ai" "true"
|
||||||
@@ -1627,8 +1631,8 @@
|
|||||||
// entity 48
|
// entity 48
|
||||||
{
|
{
|
||||||
"classname" "enemy_spawn"
|
"classname" "enemy_spawn"
|
||||||
"origin" "264 -680 -232"
|
"origin" "-184 -360 -232"
|
||||||
"angles" "0 90 0"
|
"angles" "0 0 0"
|
||||||
"head" "green grocer"
|
"head" "green grocer"
|
||||||
"key" ""
|
"key" ""
|
||||||
"disable_ai" "true"
|
"disable_ai" "true"
|
||||||
@@ -1636,8 +1640,8 @@
|
|||||||
// entity 49
|
// entity 49
|
||||||
{
|
{
|
||||||
"classname" "enemy_spawn"
|
"classname" "enemy_spawn"
|
||||||
"origin" "168 -680 -232"
|
"origin" "-184 -280 -232"
|
||||||
"angles" "0 90 0"
|
"angles" "0 0 0"
|
||||||
"head" "highland hammer thrower"
|
"head" "highland hammer thrower"
|
||||||
"key" ""
|
"key" ""
|
||||||
"disable_ai" "true"
|
"disable_ai" "true"
|
||||||
@@ -1645,8 +1649,8 @@
|
|||||||
// entity 50
|
// entity 50
|
||||||
{
|
{
|
||||||
"classname" "enemy_spawn"
|
"classname" "enemy_spawn"
|
||||||
"origin" "72 -680 -232"
|
"origin" "-184 -184 -232"
|
||||||
"angles" "0 90 0"
|
"angles" "0 0 0"
|
||||||
"head" "legionnaire"
|
"head" "legionnaire"
|
||||||
"key" ""
|
"key" ""
|
||||||
"disable_ai" "true"
|
"disable_ai" "true"
|
||||||
@@ -1654,8 +1658,8 @@
|
|||||||
// entity 51
|
// entity 51
|
||||||
{
|
{
|
||||||
"classname" "enemy_spawn"
|
"classname" "enemy_spawn"
|
||||||
"origin" "-24 -680 -232"
|
"origin" "-184 -104 -232"
|
||||||
"angles" "0 90 0"
|
"angles" "0 0 0"
|
||||||
"head" "mig pilot"
|
"head" "mig pilot"
|
||||||
"key" ""
|
"key" ""
|
||||||
"disable_ai" "true"
|
"disable_ai" "true"
|
||||||
@@ -1663,8 +1667,8 @@
|
|||||||
// entity 52
|
// entity 52
|
||||||
{
|
{
|
||||||
"classname" "enemy_spawn"
|
"classname" "enemy_spawn"
|
||||||
"origin" "-104 -680 -232"
|
"origin" "-184 -8 -232"
|
||||||
"angles" "0 90 0"
|
"angles" "0 0 0"
|
||||||
"head" "soldier ant"
|
"head" "soldier ant"
|
||||||
"key" ""
|
"key" ""
|
||||||
"disable_ai" "true"
|
"disable_ai" "true"
|
||||||
@@ -1673,7 +1677,7 @@
|
|||||||
{
|
{
|
||||||
"classname" "enemy_spawn"
|
"classname" "enemy_spawn"
|
||||||
"origin" "-184 -680 -232"
|
"origin" "-184 -680 -232"
|
||||||
"angles" "0 90 0"
|
"angles" "0 0 0"
|
||||||
"head" "super market shopper"
|
"head" "super market shopper"
|
||||||
"key" ""
|
"key" ""
|
||||||
"disable_ai" "true"
|
"disable_ai" "true"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use crate::{
|
|||||||
GameState,
|
GameState,
|
||||||
head::ActiveHead,
|
head::ActiveHead,
|
||||||
heads_database::HeadsDatabase,
|
heads_database::HeadsDatabase,
|
||||||
|
hitpoints::Hitpoints,
|
||||||
physics_layers::GameLayer,
|
physics_layers::GameLayer,
|
||||||
player::{Player, PlayerBodyMesh},
|
player::{Player, PlayerBodyMesh},
|
||||||
tb_entities::EnemySpawn,
|
tb_entities::EnemySpawn,
|
||||||
@@ -68,12 +69,12 @@ fn head_change(
|
|||||||
|
|
||||||
fn update_player_aim(
|
fn update_player_aim(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
potential_targets: Query<(Entity, &Transform), With<EnemySpawn>>,
|
potential_targets: Query<(Entity, &Transform), With<Hitpoints>>,
|
||||||
player_rot: Query<(&Transform, &GlobalTransform), With<PlayerBodyMesh>>,
|
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,
|
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;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -89,6 +90,10 @@ fn update_player_aim(
|
|||||||
let mut target_distance = f32::MAX;
|
let mut target_distance = f32::MAX;
|
||||||
|
|
||||||
for (e, t) in potential_targets.iter() {
|
for (e, t) in potential_targets.iter() {
|
||||||
|
if e == player {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let delta = player_pos - t.translation;
|
let delta = player_pos - t.translation;
|
||||||
|
|
||||||
let distance = delta.length();
|
let distance = delta.length();
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ pub struct AudioAssets {
|
|||||||
pub secret_head_collect: Handle<AudioSource>,
|
pub secret_head_collect: Handle<AudioSource>,
|
||||||
#[asset(path = "sfx/effects/head_drop.ogg")]
|
#[asset(path = "sfx/effects/head_drop.ogg")]
|
||||||
pub head_drop: Handle<AudioSource>,
|
pub head_drop: Handle<AudioSource>,
|
||||||
|
#[asset(path = "sfx/effects/beam_in_out.ogg")]
|
||||||
|
pub beaming: Handle<AudioSource>,
|
||||||
|
|
||||||
#[asset(path = "sfx/hit", collection(typed))]
|
#[asset(path = "sfx/hit", collection(typed))]
|
||||||
pub hit: Vec<Handle<AudioSource>>,
|
pub hit: Vec<Handle<AudioSource>>,
|
||||||
|
|||||||
46
src/npc.rs
46
src/npc.rs
@@ -2,12 +2,14 @@ use crate::{
|
|||||||
GameState,
|
GameState,
|
||||||
ai::Ai,
|
ai::Ai,
|
||||||
character::AnimatedCharacter,
|
character::AnimatedCharacter,
|
||||||
|
global_observer,
|
||||||
head::ActiveHead,
|
head::ActiveHead,
|
||||||
head_drop::HeadDrops,
|
head_drop::HeadDrops,
|
||||||
heads::{ActiveHeads, HEAD_COUNT, HeadState},
|
heads::{ActiveHeads, HEAD_COUNT, HeadState},
|
||||||
heads_database::HeadsDatabase,
|
heads_database::HeadsDatabase,
|
||||||
hitpoints::{Hitpoints, Kill},
|
hitpoints::{Hitpoints, Kill},
|
||||||
keys::KeySpawn,
|
keys::KeySpawn,
|
||||||
|
sounds::PlaySound,
|
||||||
tb_entities::EnemySpawn,
|
tb_entities::EnemySpawn,
|
||||||
};
|
};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
@@ -17,11 +19,34 @@ use std::collections::HashMap;
|
|||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
pub struct Npc;
|
pub struct Npc;
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
#[derive(Resource, Reflect, Default)]
|
||||||
app.add_systems(OnEnter(GameState::Playing), init);
|
#[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
|
//TODO: move into HeadsDatabase
|
||||||
let mut names: HashMap<String, usize> = HashMap::default();
|
let mut names: HashMap<String, usize> = HashMap::default();
|
||||||
for i in 0..HEAD_COUNT {
|
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() {
|
for (e, spawn) in query.iter() {
|
||||||
|
if let Some(order) = spawn.spawn_order {
|
||||||
|
if order > spawning.spawn_index {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let id = names[&spawn.head];
|
let id = names[&spawn.head];
|
||||||
commands
|
commands
|
||||||
.entity(e)
|
.entity(e)
|
||||||
@@ -47,6 +78,8 @@ fn init(mut commands: Commands, query: Query<(Entity, &EnemySpawn)>, heads_db: R
|
|||||||
.insert_if(Ai, || !spawn.disable_ai)
|
.insert_if(Ai, || !spawn.disable_ai)
|
||||||
.with_child((Name::from("body-rig"), AnimatedCharacter::new(id)))
|
.with_child((Name::from("body-rig"), AnimatedCharacter::new(id)))
|
||||||
.observe(on_kill);
|
.observe(on_kill);
|
||||||
|
|
||||||
|
commands.trigger(PlaySound::Beaming);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +92,14 @@ fn on_kill(
|
|||||||
return;
|
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(HeadDrops::new(transform.translation, head.0));
|
||||||
|
commands.trigger(OnCheckSpawns);
|
||||||
|
|
||||||
commands.entity(trigger.target()).despawn();
|
commands.entity(trigger.target()).despawn();
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ pub enum PlaySound {
|
|||||||
Reloaded,
|
Reloaded,
|
||||||
CashHeal,
|
CashHeal,
|
||||||
Crossbow,
|
Crossbow,
|
||||||
|
Beaming,
|
||||||
Backpack { open: bool },
|
Backpack { open: bool },
|
||||||
Head(String),
|
Head(String),
|
||||||
}
|
}
|
||||||
@@ -60,6 +61,7 @@ fn on_spawn_sounds(
|
|||||||
PlaySound::HeadCollect => assets.head_collect.clone(),
|
PlaySound::HeadCollect => assets.head_collect.clone(),
|
||||||
PlaySound::SecretHeadCollect => assets.secret_head_collect.clone(),
|
PlaySound::SecretHeadCollect => assets.secret_head_collect.clone(),
|
||||||
PlaySound::MissileExplosion => assets.missile_explosion.clone(),
|
PlaySound::MissileExplosion => assets.missile_explosion.clone(),
|
||||||
|
PlaySound::Beaming => assets.beaming.clone(),
|
||||||
PlaySound::Backpack { open } => {
|
PlaySound::Backpack { open } => {
|
||||||
if *open {
|
if *open {
|
||||||
assets.backpack_open.clone()
|
assets.backpack_open.clone()
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ pub struct EnemySpawn {
|
|||||||
pub head: String,
|
pub head: String,
|
||||||
pub key: String,
|
pub key: String,
|
||||||
pub disable_ai: bool,
|
pub disable_ai: bool,
|
||||||
|
pub spawn_order: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EnemySpawn {
|
impl EnemySpawn {
|
||||||
|
|||||||
@@ -53,6 +53,7 @@
|
|||||||
"true" : "true"
|
"true" : "true"
|
||||||
"false" : "false"
|
"false" : "false"
|
||||||
]
|
]
|
||||||
|
spawn_order(integer) : "spawn_order" : : ""
|
||||||
]
|
]
|
||||||
|
|
||||||
@SolidClass base(__transform, __target) = movable
|
@SolidClass base(__transform, __target) = movable
|
||||||
|
|||||||
Reference in New Issue
Block a user