diff options
author | Alexander Foremny <aforemny@posteo.de> | 2024-03-19 14:13:16 +0100 |
---|---|---|
committer | Alexander Foremny <aforemny@posteo.de> | 2024-03-19 15:12:22 +0100 |
commit | 2d21d709901c96b05d7f0169dd9d1207436c658c (patch) | |
tree | 8f1a094c46e96e13a0a5395ba69c0eb402555133 /src | |
parent | 2e39423d11a6cd1e25b54c30d9afd22e8eff9dfe (diff) |
feat: area of effect
Diffstat (limited to 'src')
-rw-r--r-- | src/client.rs | 27 | ||||
-rw-r--r-- | src/protocol.rs | 2 | ||||
-rw-r--r-- | src/server.rs | 54 | ||||
-rw-r--r-- | src/shared.rs | 1 | ||||
-rw-r--r-- | src/shared/ability.rs | 12 | ||||
-rw-r--r-- | src/shared/area_of_effect.rs | 64 |
6 files changed, 158 insertions, 2 deletions
diff --git a/src/client.rs b/src/client.rs index 8da77dc..7e0cebf 100644 --- a/src/client.rs +++ b/src/client.rs @@ -2,6 +2,7 @@ use crate::client::network::*; use crate::protocol::*; use crate::shared::ability::*; use crate::shared::activation::*; +use crate::shared::area_of_effect::*; use crate::shared::champion::*; use crate::shared::cooldown::*; use crate::shared::health::*; @@ -76,6 +77,7 @@ impl Plugin for ClientPlugin { ( render_players.after(move_players), render_projectiles.after(move_projectiles), + render_area_of_effects, render_health, ), ) @@ -226,6 +228,31 @@ fn render_projectiles( } } +fn render_area_of_effects( + mut commands: Commands, + mut materials: ResMut<Assets<ColorMaterial>>, + mut meshes: ResMut<Assets<Mesh>>, + area_of_effects: Query<(Entity, &AreaOfEffect), Added<AreaOfEffect>>, +) { + for (entity, area_of_effect) in area_of_effects.iter() { + if area_of_effect.duration.is_none() { + continue; + } + commands.entity(entity).insert(MaterialMesh2dBundle { + mesh: Mesh2dHandle(meshes.add(Circle { + radius: area_of_effect.radius, + })), + material: materials.add(Color::BLACK), + transform: Transform::from_xyz( + area_of_effect.position.x, + area_of_effect.position.y, + 1., + ), + ..Default::default() + }); + } +} + fn move_projectiles(mut projectiles: Query<(&mut Transform, &Projectile), Changed<Projectile>>) { for (mut transform, projectile) in projectiles.iter_mut() { let Some(position) = (match projectile.type_ { diff --git a/src/protocol.rs b/src/protocol.rs index 8a83260..646974c 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -1,4 +1,5 @@ use crate::shared::activation::*; +use crate::shared::area_of_effect::*; use crate::shared::champion::*; use crate::shared::cooldown::*; use crate::shared::health::*; @@ -42,6 +43,7 @@ pub enum Components { Health(Health), Champion(Champion), EffectiveStats(EffectiveStats), + AreaOfEffect(AreaOfEffect), } #[derive(Channel)] diff --git a/src/server.rs b/src/server.rs index fc44120..4593cfa 100644 --- a/src/server.rs +++ b/src/server.rs @@ -3,6 +3,7 @@ use crate::server::entity_map::*; use crate::server::network::*; use crate::shared::ability::*; use crate::shared::activation::*; +use crate::shared::area_of_effect::*; use crate::shared::buffs::*; use crate::shared::champion::*; use crate::shared::cooldown::*; @@ -71,8 +72,17 @@ impl Plugin for ServerPlugin { .add_systems( FixedUpdate, ( - projectile_move.after(imperative_walk_to), projectile_despawn, + projectile_move.after(imperative_walk_to), + ) + .chain(), + ) + .add_systems( + FixedUpdate, + ( + area_of_effect_despawn, + area_of_effect_tick.after(imperative_walk_to), + area_of_effect_activate, ) .chain(), ) @@ -580,3 +590,45 @@ fn buffs_despawn(mut buffses: Query<&mut Buffs>) { } } } + +fn area_of_effect_tick(mut area_of_effects: Query<&mut AreaOfEffect>, time: Res<Time>) { + let dt = time.delta(); + for mut area_of_effect in area_of_effects.iter_mut() { + if let Some(ref mut duration) = area_of_effect.duration { + *duration = (*duration - dt.as_secs_f32()).max(0.); + } else { + area_of_effect.duration = Some(0.); + } + } +} + +fn area_of_effect_despawn(area_of_effects: Query<(Entity, &AreaOfEffect)>, mut commands: Commands) { + for (entity, area_of_effect) in area_of_effects.iter() { + let Some(duration) = area_of_effect.duration else { + continue; + }; + if duration > 0. { + continue; + }; + commands.entity(entity).despawn(); + } +} + +fn area_of_effect_activate( + players: Query<(&PlayerId, &PlayerPosition)>, + area_of_effects: Query<&AreaOfEffect>, + mut commands: Commands, +) { + for area_of_effect in area_of_effects.iter() { + for (player_id, player_position) in players.iter() { + if *player_id == area_of_effect.source_player { + continue; + } + if area_of_effect.position.distance(player_position.0) + < area_of_effect.radius + PLAYER_RADIUS + { + area_of_effect.activate()(&mut commands, area_of_effect.source_player, *player_id); + } + } + } +} diff --git a/src/shared.rs b/src/shared.rs index 678c592..8ec056d 100644 --- a/src/shared.rs +++ b/src/shared.rs @@ -11,6 +11,7 @@ use std::default::Default; pub mod ability; pub mod activation; +pub mod area_of_effect; pub mod buffs; pub mod champion; pub mod cooldown; diff --git a/src/shared/ability.rs b/src/shared/ability.rs index 80c74b2..2cd44c4 100644 --- a/src/shared/ability.rs +++ b/src/shared/ability.rs @@ -1,4 +1,5 @@ use crate::server::entity_map::*; +use crate::shared::area_of_effect::*; use crate::shared::buffs::*; use crate::shared::player::*; use crate::shared::projectile::*; @@ -220,7 +221,8 @@ fn dash_activation(dash: Dash) -> DirectionalAbilityActivation { mut set: ParamSet<( Query<&mut PlayerPosition>, Query<(&PlayerId, &PlayerPosition)>, - )>| { + )>, + mut commands: Commands| { let Some(source_entity) = ({ let mut source_entity = None; for (entity, player_id) in players.iter() { @@ -261,6 +263,14 @@ fn dash_activation(dash: Dash) -> DirectionalAbilityActivation { if let Ok(mut position) = positions.get_mut(source_entity) { position.0 = dash_end; } + + commands.spawn(AreaOfEffectBundle::new(AreaOfEffect { + position: dash_end, + radius: 1.5 * PLAYER_RADIUS, + duration: None, + source_player, + area_of_effect_type: AreaOfEffectType::Slow, + })); }, ) }); diff --git a/src/shared/area_of_effect.rs b/src/shared/area_of_effect.rs new file mode 100644 index 0000000..dcdc86c --- /dev/null +++ b/src/shared/area_of_effect.rs @@ -0,0 +1,64 @@ +use crate::server::entity_map::*; +use crate::shared::buffs::*; +use crate::shared::player::*; +use crate::shared::*; +use bevy::ecs::system::*; + +#[derive(Bundle)] +pub struct AreaOfEffectBundle { + area_of_effect: AreaOfEffect, + replicate: Replicate, +} + +impl AreaOfEffectBundle { + pub fn new(area_of_effect: AreaOfEffect) -> Self { + AreaOfEffectBundle { + area_of_effect, + replicate: Replicate::default(), + } + } +} + +#[derive(Component, Message, Serialize, Deserialize, Clone, PartialEq, Debug)] +pub struct AreaOfEffect { + pub position: Vec2, + pub radius: f32, + // `duration = None` means `AreaOfEffect` exists only for a single server tick + pub duration: Option<f32>, + pub source_player: PlayerId, + pub area_of_effect_type: AreaOfEffectType, +} + +#[derive(Component, Message, Serialize, Deserialize, Clone, PartialEq, Debug)] +pub enum AreaOfEffectType { + Slow, +} + +pub type AreaOfEffectActivation = Box<dyn FnOnce(&mut Commands, PlayerId, PlayerId) -> ()>; + +impl AreaOfEffect { + pub fn activate(&self) -> AreaOfEffectActivation { + match self.area_of_effect_type { + AreaOfEffectType::Slow => Box::new( + move |commands: &mut Commands, + _source_player_id: PlayerId, + target_player_id: PlayerId| { + commands.add(move |world: &mut World| { + world.run_system_once( + move |entity_map: Res<EntityMap>, mut buffs: Query<&mut Buffs>| { + let Some(target_entity) = entity_map.0.get(&target_player_id.0) + else { + return; + }; + let Ok(mut buffs) = buffs.get_mut(*target_entity) else { + return; + }; + buffs.slow = Some(0.75); + }, + ) + }) + }, + ), + } + } +} |