From 7fbf24a49b994d7de4fe92ed40c9e61a127096c7 Mon Sep 17 00:00:00 2001 From: extrawurst Date: Tue, 1 Apr 2025 21:11:01 +0800 Subject: [PATCH] thrown projectiles area damage --- src/abilities/thrown.rs | 58 +++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 8 deletions(-) diff --git a/src/abilities/thrown.rs b/src/abilities/thrown.rs index d9237cd..d985589 100644 --- a/src/abilities/thrown.rs +++ b/src/abilities/thrown.rs @@ -1,10 +1,10 @@ use super::TriggerState; use crate::{ GameState, - abilities::Projectile, aim::AimState, billboards::Billboard, loading_assets::GameAssets, + npc::Hit, physics_layers::GameLayer, player::{Player, PlayerRig}, sounds::PlaySound, @@ -23,6 +23,13 @@ struct ThrownProjectile; #[reflect(Component)] struct AutoRotation(Quat); +#[derive(Event, Debug)] +struct Explosion { + position: Vec3, + radius: f32, + damage: u32, +} + #[derive(Resource)] struct ShotAssets { image: Handle, @@ -36,6 +43,33 @@ pub fn plugin(app: &mut App) { app.add_systems(Update, shot_collision.run_if(in_state(GameState::Playing))); app.add_systems(FixedUpdate, update_auto_rotation); app.add_observer(on_trigger_state); + app.add_observer(on_explosion); +} + +fn on_explosion( + explosion: Trigger, + mut commands: Commands, + spatial_query: SpatialQuery, +) { + let explosion = explosion.event(); + let intersections = { + spatial_query.shape_intersections( + &Collider::sphere(explosion.radius), + explosion.position, + Quat::default(), + &SpatialQueryFilter::default().with_mask(LayerMask( + GameLayer::Npc.to_bits() | GameLayer::Player.to_bits(), + )), + ) + }; + + for entity in intersections.iter() { + if let Some(mut e) = commands.get_entity(*entity) { + e.trigger(Hit { + damage: explosion.damage, + }); + } + } } fn setup(mut commands: Commands, assets: Res, mut sprite_params: Sprite3dParams) { @@ -103,13 +137,13 @@ fn on_trigger_state( .spawn(( Name::new("projectile-thrown"), ThrownProjectile, - Projectile { damage: 20 }, Collider::sphere(0.5), CollisionLayers::new( LayerMask(GameLayer::Projectile.to_bits()), LayerMask(GameLayer::Npc.to_bits() | GameLayer::Level.to_bits()), ), RigidBody::Dynamic, + Mass(0.01), LinearVelocity(vel), Visibility::default(), t, @@ -140,12 +174,14 @@ fn shot_collision( commands.entity(shot_entity).despawn_recursive(); - let texture_atlas = TextureAtlas { - layout: assets.layout.clone(), - index: 0, - }; - commands.trigger(PlaySound::ThrowHit); + + commands.trigger(Explosion { + damage: 20, + position: shot_pos, + radius: 2., + }); + commands .spawn( Sprite3dBuilder { @@ -155,7 +191,13 @@ fn shot_collision( unlit: true, ..default() } - .bundle_with_atlas(&mut sprite_params, texture_atlas), + .bundle_with_atlas( + &mut sprite_params, + TextureAtlas { + layout: assets.layout.clone(), + index: 0, + }, + ), ) .insert(( Billboard,