From 6805c6db39c1a9409b39aaf601f78db92b684c0d Mon Sep 17 00:00:00 2001 From: Alexander Foremny Date: Tue, 19 Mar 2024 05:14:57 +0100 Subject: feat: pull ability --- src/shared/ability.rs | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) (limited to 'src/shared/ability.rs') 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( -- cgit v1.2.3