diff options
author | Alexander Foremny <aforemny@posteo.de> | 2024-03-19 05:14:57 +0100 |
---|---|---|
committer | Alexander Foremny <aforemny@posteo.de> | 2024-03-19 05:14:57 +0100 |
commit | 6805c6db39c1a9409b39aaf601f78db92b684c0d (patch) | |
tree | 2f9657d97c3b188a82c07cf228c9def712223414 | |
parent | ee2bc9dca88e52b92a49a9ff21db8832b3b66255 (diff) |
feat: pull ability
-rw-r--r-- | src/client.rs | 24 | ||||
-rw-r--r-- | src/shared/ability.rs | 122 | ||||
-rw-r--r-- | src/shared/champion.rs | 1 |
3 files changed, 147 insertions, 0 deletions
diff --git a/src/client.rs b/src/client.rs index 22e3960..1768b2e 100644 --- a/src/client.rs +++ b/src/client.rs @@ -445,6 +445,30 @@ fn gizmos_attack_indicator( ); gizmos.arrow_2d(position.0, dash_end, Color::YELLOW); } + Ability::Directional(DirectionalAbility::Pull) => { + let Some(world_position) = cursor_world_position(&windows, &cameras) else { + return; + }; + let Some(direction) = (world_position - position.0).try_normalize() else { + return; + }; + let Some((_, pull_start, pull_end)) = pull_collision( + PlayerId(client_id.0), + position.0, + direction, + 150., + &player_positions, + ) else { + let pull_direction = -150. * direction; + let pull_start = position.0 - pull_direction; + let pull_end = pull_start + + (pull_direction.length() - 2. * PLAYER_RADIUS) + * pull_direction.normalize_or_zero(); + gizmos.arrow_2d(pull_start, pull_end, Color::YELLOW); + return; + }; + gizmos.arrow_2d(pull_start, pull_end, Color::YELLOW); + } Ability::Directional(_) => { let Some(world_position) = cursor_world_position(&windows, &cameras) else { return; diff --git a/src/shared/ability.rs b/src/shared/ability.rs index e8b2a26..2c581e7 100644 --- a/src/shared/ability.rs +++ b/src/shared/ability.rs @@ -51,6 +51,7 @@ pub enum ActivatedAbility { #[derive(Copy, Clone, PartialEq, Debug, Deserialize, Serialize)] pub enum DirectionalAbility { Dash, + Pull, Spear, } @@ -62,6 +63,7 @@ impl DirectionalAbility { pub fn activate(self) -> DirectionalAbilityActivation { match self { DirectionalAbility::Dash => DirectionalAbilityActivation(dash_activation), + DirectionalAbility::Pull => DirectionalAbilityActivation(pull_activation), DirectionalAbility::Spear => DirectionalAbilityActivation(spear_activation), } } @@ -159,6 +161,126 @@ pub fn dash_collision( } } +fn pull_activation(commands: &mut Commands, source_player: PlayerId, direction: Vec2) { + commands.add(move |world: &mut World| { + world.run_system_once( + move |players: Query<(Entity, &PlayerId)>, + mut set: ParamSet<( + Query<&mut PlayerPosition>, + Query<(&PlayerId, &PlayerPosition)>, + )>| { + let Some(source_entity) = ({ + let mut source_entity = None; + for (entity, player_id) in players.iter() { + if *player_id != source_player { + continue; + } + source_entity = Some(entity); + break; + } + source_entity + }) else { + return; + }; + + let Some(source_position) = ({ + let positions = set.p0(); + if let Ok(position) = positions.get(source_entity) { + Some(*position) + } else { + None + } + }) else { + return; + }; + + let Some((target_player, _, pull_end)) = ({ + let pull_targets = set.p1(); + pull_collision( + source_player, + source_position.0, + direction, + 150., + &pull_targets, + ) + }) else { + return; + }; + + let Some(target_entity) = ({ + let mut target_entity = None; + for (entity, player_id) in players.iter() { + if *player_id != target_player { + continue; + } + target_entity = Some(entity); + break; + } + target_entity + }) else { + return; + }; + + let mut positions = set.p0(); + if let Ok(mut position) = positions.get_mut(target_entity) { + position.0 = pull_end; + } + }, + ) + }); +} + +pub fn pull_collision( + source_id: PlayerId, + pull_start: Vec2, + pull_direction: Vec2, + pull_max_distance: f32, + player_positions: &Query<(&PlayerId, &PlayerPosition)>, +) -> Option<(PlayerId, Vec2, Vec2)> { + let mut pull_collision = pull_max_distance * pull_direction; + let mut pull_player_id = None; + let mut pull_player_position = None; + for (player_id, position) in player_positions.iter() { + if *player_id == source_id { + continue; + } + + let player_position = position.0 - pull_start; + let player_projection = player_position.project_onto(pull_collision); + let player_rejection = player_position - player_projection; + let scalar_factor = player_projection.dot(pull_collision).signum() + * player_projection.length() + / pull_collision.length(); + + if scalar_factor < 0. || scalar_factor > 1.0 { + continue; + } + + if player_rejection.length() < 2. * PLAYER_RADIUS { + pull_player_id = Some(player_id); + pull_player_position = Some(position.0); + pull_collision = player_projection; + } + } + + if let Some(target_id) = pull_player_id { + if let Some(target_position) = pull_player_position { + let pull_direction = pull_start - target_position; + Some(( + *target_id, + target_position, + target_position + + (pull_direction.length() - 2. * PLAYER_RADIUS) + * pull_direction.normalize_or_zero(), + )) + } else { + None + } + } else { + None + } +} + fn spear_activation(commands: &mut Commands, source_player: PlayerId, direction: Vec2) { commands.add(move |world: &mut World| { world.run_system_once( diff --git a/src/shared/champion.rs b/src/shared/champion.rs index 8dadd9b..ccc2fcd 100644 --- a/src/shared/champion.rs +++ b/src/shared/champion.rs @@ -31,6 +31,7 @@ impl Champion { match self { Champion::Meele => match ability_slot { AbilitySlot::Q => Ability::Directional(DirectionalAbility::Dash), + AbilitySlot::W => Ability::Directional(DirectionalAbility::Pull), AbilitySlot::G => Ability::Activated(ActivatedAbility::Speed), _ => Ability::Targeted(TargetedAbility::MeeleAttack), }, |