single global observers root node (#25)

plus auto name observer macro `global_observer`
This commit is contained in:
extrawurst
2025-04-07 18:22:29 +02:00
committed by GitHub
parent 92da1587ba
commit ddc57ec1e8
17 changed files with 94 additions and 37 deletions

View File

@@ -1,7 +1,7 @@
use super::{Projectile, TriggerGun}; use super::{Projectile, TriggerGun};
use crate::{ use crate::{
GameState, billboards::Billboard, loading_assets::GameAssets, physics_layers::GameLayer, GameState, billboards::Billboard, global_observer, loading_assets::GameAssets,
sounds::PlaySound, utils::sprite_3d_animation::AnimationTimer, physics_layers::GameLayer, sounds::PlaySound, utils::sprite_3d_animation::AnimationTimer,
}; };
use avian3d::prelude::{ use avian3d::prelude::{
Collider, CollisionLayers, CollisionStarted, LayerMask, PhysicsLayer, Sensor, Collider, CollisionLayers, CollisionStarted, LayerMask, PhysicsLayer, Sensor,
@@ -30,7 +30,8 @@ pub fn plugin(app: &mut App) {
Update, Update,
(update, shot_collision, timeout).run_if(in_state(GameState::Playing)), (update, shot_collision, timeout).run_if(in_state(GameState::Playing)),
); );
app.add_observer(on_trigger_state);
global_observer!(app, on_trigger_gun);
} }
fn setup(mut commands: Commands, assets: Res<GameAssets>, mut sprite_params: Sprite3dParams) { fn setup(mut commands: Commands, assets: Res<GameAssets>, mut sprite_params: Sprite3dParams) {
@@ -43,7 +44,7 @@ fn setup(mut commands: Commands, assets: Res<GameAssets>, mut sprite_params: Spr
}); });
} }
fn on_trigger_state( fn on_trigger_gun(
trigger: Trigger<TriggerGun>, trigger: Trigger<TriggerGun>,
mut commands: Commands, mut commands: Commands,
query_transform: Query<&Transform>, query_transform: Query<&Transform>,

View File

@@ -4,6 +4,7 @@ mod thrown;
use crate::{ use crate::{
GameState, GameState,
aim::AimTarget, aim::AimTarget,
global_observer,
heads::ActiveHeads, heads::ActiveHeads,
hitpoints::Hit, hitpoints::Hit,
physics_layers::GameLayer, physics_layers::GameLayer,
@@ -74,7 +75,7 @@ pub fn plugin(app: &mut App) {
app.add_systems(Update, enemy_hit.run_if(in_state(GameState::Playing))); app.add_systems(Update, enemy_hit.run_if(in_state(GameState::Playing)));
app.add_observer(on_trigger_state); global_observer!(app, on_trigger_state);
} }
fn enemy_hit( fn enemy_hit(

View File

@@ -1,7 +1,12 @@
use super::TriggerThrow; use super::TriggerThrow;
use crate::{ use crate::{
GameState, billboards::Billboard, hitpoints::Hit, loading_assets::GameAssets, GameState,
physics_layers::GameLayer, sounds::PlaySound, utils::sprite_3d_animation::AnimationTimer, billboards::Billboard,
hitpoints::Hit,
loading_assets::GameAssets,
physics_layers::GameLayer,
sounds::PlaySound,
utils::{global_observer, sprite_3d_animation::AnimationTimer},
}; };
use avian3d::prelude::*; use avian3d::prelude::*;
use bevy::{pbr::NotShadowCaster, prelude::*}; use bevy::{pbr::NotShadowCaster, prelude::*};
@@ -35,8 +40,9 @@ pub fn plugin(app: &mut App) {
app.add_systems(OnEnter(GameState::Playing), setup); app.add_systems(OnEnter(GameState::Playing), setup);
app.add_systems(Update, shot_collision.run_if(in_state(GameState::Playing))); app.add_systems(Update, shot_collision.run_if(in_state(GameState::Playing)));
app.add_systems(FixedUpdate, update_auto_rotation); app.add_systems(FixedUpdate, update_auto_rotation);
app.add_observer(on_trigger_state);
app.add_observer(on_explosion); global_observer!(app, on_trigger_thrown);
global_observer!(app, on_explosion);
} }
fn on_explosion( fn on_explosion(
@@ -75,7 +81,7 @@ fn setup(mut commands: Commands, assets: Res<GameAssets>, mut sprite_params: Spr
}); });
} }
fn on_trigger_state( fn on_trigger_thrown(
trigger: Trigger<TriggerThrow>, trigger: Trigger<TriggerThrow>,
mut commands: Commands, mut commands: Commands,
query_transform: Query<&Transform>, query_transform: Query<&Transform>,

View File

@@ -1,4 +1,4 @@
use crate::{GameState, loading_assets::UIAssets, utils::billboards::Billboard}; use crate::{GameState, global_observer, loading_assets::UIAssets, utils::billboards::Billboard};
use bevy::prelude::*; use bevy::prelude::*;
use bevy_sprite3d::{Sprite3dBuilder, Sprite3dParams}; use bevy_sprite3d::{Sprite3dBuilder, Sprite3dParams};
use ops::sin; use ops::sin;
@@ -15,7 +15,7 @@ pub enum MarkerEvent {
pub fn plugin(app: &mut App) { pub fn plugin(app: &mut App) {
app.add_systems(Update, move_marker.run_if(in_state(GameState::Playing))); app.add_systems(Update, move_marker.run_if(in_state(GameState::Playing)));
app.add_observer(marker_event); global_observer!(app, marker_event);
} }
fn move_marker(mut query: Query<&mut Transform, With<TargetMarker>>, time: Res<Time>) { fn move_marker(mut query: Query<&mut Transform, With<TargetMarker>>, time: Res<Time>) {

View File

@@ -1,5 +1,7 @@
use super::{BackbackSwapEvent, Backpack, UiHeadState}; use super::{BackbackSwapEvent, Backpack, UiHeadState};
use crate::{GameState, heads::HeadsImages, loading_assets::UIAssets, sounds::PlaySound}; use crate::{
GameState, global_observer, heads::HeadsImages, loading_assets::UIAssets, sounds::PlaySound,
};
use bevy::prelude::*; use bevy::prelude::*;
static HEAD_SLOTS: usize = 5; static HEAD_SLOTS: usize = 5;
@@ -51,7 +53,7 @@ pub fn plugin(app: &mut App) {
.run_if(in_state(GameState::Playing)), .run_if(in_state(GameState::Playing)),
); );
app.add_observer(swap_head_inputs); global_observer!(app, swap_head_inputs);
} }
fn setup(mut commands: Commands, assets: Res<UIAssets>) { fn setup(mut commands: Commands, assets: Res<UIAssets>) {

View File

@@ -1,4 +1,4 @@
use crate::{GameState, loading_assets::UIAssets, sounds::PlaySound}; use crate::{GameState, global_observer, loading_assets::UIAssets, sounds::PlaySound};
use bevy::prelude::*; use bevy::prelude::*;
#[derive(Component, Reflect, Default)] #[derive(Component, Reflect, Default)]
@@ -25,10 +25,11 @@ pub fn plugin(app: &mut App) {
Update, Update,
(rotate, update_ui).run_if(in_state(GameState::Playing)), (rotate, update_ui).run_if(in_state(GameState::Playing)),
); );
app.add_observer(on_collect);
global_observer!(app, on_cash_collect);
} }
fn on_collect( fn on_cash_collect(
_trigger: Trigger<CashCollectEvent>, _trigger: Trigger<CashCollectEvent>,
mut commands: Commands, mut commands: Commands,
mut cash: ResMut<CashResource>, mut cash: ResMut<CashResource>,

View File

@@ -1,11 +1,11 @@
use crate::{ use crate::{
abilities::TriggerCashHeal, cash::CashResource, hitpoints::Hitpoints, player::Player, abilities::TriggerCashHeal, cash::CashResource, global_observer, hitpoints::Hitpoints,
sounds::PlaySound, player::Player, sounds::PlaySound,
}; };
use bevy::prelude::*; use bevy::prelude::*;
pub fn plugin(app: &mut App) { pub fn plugin(app: &mut App) {
app.add_observer(on_heal_trigger); global_observer!(app, on_heal_trigger);
} }
fn on_heal_trigger( fn on_heal_trigger(

View File

@@ -1,6 +1,7 @@
use crate::{ use crate::{
GameState, GameState,
camera::{CameraState, MainCamera}, camera::{CameraState, MainCamera},
global_observer,
tb_entities::{CameraTarget, CutsceneCamera, CutsceneCameraMovementEnd}, tb_entities::{CameraTarget, CutsceneCamera, CutsceneCameraMovementEnd},
}; };
use bevy::prelude::*; use bevy::prelude::*;
@@ -23,7 +24,8 @@ enum CutsceneState {
pub fn plugin(app: &mut App) { pub fn plugin(app: &mut App) {
app.init_resource::<CutsceneState>(); app.init_resource::<CutsceneState>();
app.add_systems(Update, update.run_if(in_state(GameState::Playing))); app.add_systems(Update, update.run_if(in_state(GameState::Playing)));
app.add_observer(on_start_cutscene);
global_observer!(app, on_start_cutscene);
} }
fn on_start_cutscene( fn on_start_cutscene(

View File

@@ -1,13 +1,14 @@
use crate::{ use crate::{
cutscene::StartCutscene, keys::KeyCollected, movables::TriggerMovableEvent, sounds::PlaySound, cutscene::StartCutscene, global_observer, keys::KeyCollected, movables::TriggerMovableEvent,
sounds::PlaySound,
}; };
use bevy::{prelude::*, utils::hashbrown::HashSet}; use bevy::{prelude::*, utils::hashbrown::HashSet};
pub fn plugin(app: &mut App) { pub fn plugin(app: &mut App) {
app.add_observer(on_key); global_observer!(app, on_key_collected);
} }
fn on_key(trigger: Trigger<KeyCollected>, mut commands: Commands) { fn on_key_collected(trigger: Trigger<KeyCollected>, mut commands: Commands) {
match trigger.event().0.as_str() { match trigger.event().0.as_str() {
"fence_gate" => { "fence_gate" => {
commands.trigger(StartCutscene("fence_01".to_string())); commands.trigger(StartCutscene("fence_01".to_string()));

View File

@@ -4,6 +4,7 @@ use crate::{
GameState, GameState,
abilities::HeadAbility, abilities::HeadAbility,
backpack::{BackbackSwapEvent, Backpack}, backpack::{BackbackSwapEvent, Backpack},
global_observer,
hitpoints::Hitpoints, hitpoints::Hitpoints,
player::{Player, head_id_to_str}, player::{Player, head_id_to_str},
sounds::PlaySound, sounds::PlaySound,
@@ -133,8 +134,8 @@ pub fn plugin(app: &mut App) {
(reload, sync_hp).run_if(in_state(GameState::Playing)), (reload, sync_hp).run_if(in_state(GameState::Playing)),
); );
app.add_observer(on_select_active_head); global_observer!(app, on_select_active_head);
app.add_observer(on_swap_backpack); global_observer!(app, on_swap_backpack);
} }
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) { fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {

View File

@@ -1,5 +1,5 @@
use crate::{ use crate::{
GameState, billboards::Billboard, loading_assets::GameAssets, player::Player, GameState, billboards::Billboard, global_observer, loading_assets::GameAssets, player::Player,
sounds::PlaySound, squish_animation::SquishAnimation, sounds::PlaySound, squish_animation::SquishAnimation,
}; };
use avian3d::prelude::*; use avian3d::prelude::*;
@@ -18,10 +18,11 @@ pub struct KeyCollected(pub String);
pub fn plugin(app: &mut App) { pub fn plugin(app: &mut App) {
app.add_systems(Update, collect_key.run_if(in_state(GameState::Playing))); app.add_systems(Update, collect_key.run_if(in_state(GameState::Playing)));
app.add_observer(on_spawn);
global_observer!(app, on_spawn_key);
} }
fn on_spawn(trigger: Trigger<KeySpawn>, mut commands: Commands, assets: Res<GameAssets>) { fn on_spawn_key(trigger: Trigger<KeySpawn>, mut commands: Commands, assets: Res<GameAssets>) {
let KeySpawn(position, id) = trigger.event(); let KeySpawn(position, id) = trigger.event();
let angle = rand::random::<f32>() * PI * 2.; let angle = rand::random::<f32>() * PI * 2.;

View File

@@ -145,6 +145,7 @@ fn main() {
app.add_plugins(hitpoints::plugin); app.add_plugins(hitpoints::plugin);
app.add_plugins(cash_heal::plugin); app.add_plugins(cash_heal::plugin);
app.add_plugins(debug::plugin); app.add_plugins(debug::plugin);
app.add_plugins(utils::observers::plugin);
app.init_state::<GameState>(); app.init_state::<GameState>();

View File

@@ -1,5 +1,5 @@
use crate::{ use crate::{
GameState, GameState, global_observer,
tb_entities::{Movable, MoveTarget}, tb_entities::{Movable, MoveTarget},
}; };
use bevy::{prelude::*, utils::HashSet}; use bevy::{prelude::*, utils::HashSet};
@@ -20,10 +20,11 @@ pub struct TriggerMovableEvent(pub HashSet<String>);
pub fn plugin(app: &mut App) { pub fn plugin(app: &mut App) {
app.register_type::<ActiveMovable>(); app.register_type::<ActiveMovable>();
app.add_systems(Update, move_active.run_if(in_state(GameState::Playing))); app.add_systems(Update, move_active.run_if(in_state(GameState::Playing)));
app.add_observer(trigger);
global_observer!(app, on_movable_event);
} }
fn trigger( fn on_movable_event(
trigger: Trigger<TriggerMovableEvent>, trigger: Trigger<TriggerMovableEvent>,
mut commands: Commands, mut commands: Commands,
uninit_movables: Query< uninit_movables: Query<

View File

@@ -7,6 +7,7 @@ use crate::{
Controls, Controls,
controller::{CharacterControllerBundle, MovementBundle, PlayerMovement}, controller::{CharacterControllerBundle, MovementBundle, PlayerMovement},
}, },
global_observer,
heads::HeadChanged, heads::HeadChanged,
hitpoints::Hitpoints, hitpoints::Hitpoints,
loading_assets::GameAssets, loading_assets::GameAssets,
@@ -57,7 +58,7 @@ pub fn plugin(app: &mut App) {
(rotate_view_keyboard, rotate_view_gamepad).run_if(in_state(GameState::Playing)), (rotate_view_keyboard, rotate_view_gamepad).run_if(in_state(GameState::Playing)),
); );
app.add_observer(update_head); global_observer!(app, on_update_head);
} }
fn spawn( fn spawn(
@@ -242,7 +243,7 @@ fn toggle_animation(
} }
} }
fn update_head( fn on_update_head(
trigger: Trigger<HeadChanged>, trigger: Trigger<HeadChanged>,
mut commands: Commands, mut commands: Commands,
asset_server: Res<AssetServer>, asset_server: Res<AssetServer>,

View File

@@ -1,4 +1,4 @@
use crate::loading_assets::AudioAssets; use crate::{global_observer, loading_assets::AudioAssets};
use bevy::prelude::*; use bevy::prelude::*;
#[derive(Event, Clone, Debug)] #[derive(Event, Clone, Debug)]
@@ -19,10 +19,10 @@ pub enum PlaySound {
} }
pub fn plugin(app: &mut App) { pub fn plugin(app: &mut App) {
app.add_observer(spawn_sounds); global_observer!(app, on_spawn_sounds);
} }
fn spawn_sounds( fn on_spawn_sounds(
trigger: Trigger<PlaySound>, trigger: Trigger<PlaySound>,
mut commands: Commands, mut commands: Commands,
// sound_res: Res<AudioAssets>, // sound_res: Res<AudioAssets>,

View File

@@ -1,3 +1,6 @@
pub mod billboards; pub mod billboards;
pub mod observers;
pub mod sprite_3d_animation; pub mod sprite_3d_animation;
pub mod squish_animation; pub mod squish_animation;
pub(crate) use observers::global_observer;

35
src/utils/observers.rs Normal file
View File

@@ -0,0 +1,35 @@
use bevy::prelude::*;
#[macro_export]
macro_rules! global_observer {
($app:expr,$system:expr) => {{
$app.world_mut()
.add_observer($system)
.insert(Name::new(stringify!($system)))
}};
}
pub use global_observer;
pub fn plugin(app: &mut App) {
app.add_systems(Update, global_observers);
}
fn global_observers(
mut cmds: Commands,
query: Query<Entity, (With<Observer>, Without<Parent>, Added<Observer>)>,
mut root: Local<Option<Entity>>,
) {
if root.is_none() {
let new_root = cmds.spawn(Name::new("Observers")).id();
*root = Some(new_root);
}
let Some(root) = *root else {
return;
};
for o in query.iter() {
cmds.entity(root).add_child(o);
}
}