diff options
Diffstat (limited to 'src/shared/ability.rs')
-rw-r--r-- | src/shared/ability.rs | 301 |
1 files changed, 165 insertions, 136 deletions
diff --git a/src/shared/ability.rs b/src/shared/ability.rs index b7b3664..4723e59 100644 --- a/src/shared/ability.rs +++ b/src/shared/ability.rs @@ -3,6 +3,7 @@ use crate::shared::area_of_effect::*; use crate::shared::buffs::*; use crate::shared::player::*; use crate::shared::projectile::*; +use crate::shared::shape::*; use crate::shared::*; use bevy::ecs::system::*; use bevy::utils::Duration; @@ -248,79 +249,61 @@ fn dash_activation(dash: Dash) -> DirectionalAbilityActivation { move |commands: &mut Commands, source_player: PlayerId, direction: Vec2| { commands.add(move |world: &mut World| { world.run_system_once( - move |players: Query<(Entity, &PlayerId)>, + move |entity_map: Res<EntityMap>, mut imperatives: Query<&mut Imperative>, mut set: ParamSet<( Query<&mut PlayerPosition>, - Query<(&PlayerId, &PlayerPosition)>, + Query<(Entity, &PlayerId, &PlayerPosition, &Shape)>, )>, mut commands: Commands| { - 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 { + let Some(source_entity) = entity_map.0.get(&source_player.0) 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 DashCollisionResult { + let Some(DashCollisionResult { dash_end, dash_collision, - } = { + }) = ({ let dash_targets = set.p1(); dash_collision( - source_player, - source_position.0, + *source_entity, direction.normalize_or_zero(), dash.max_distance, &dash_targets, ) + }) + else { + return; }; let mut positions = set.p0(); - if let Ok(mut position) = positions.get_mut(source_entity) { + if let Ok(mut position) = positions.get_mut(*source_entity) { position.0 = dash_end; } if let Some(DashCollision { - collision_id, - collision_position, + collision_player_id, + collision_player_position, + .. }) = dash_collision { commands.spawn(AreaOfEffectBundle::new(AreaOfEffect { - position: collision_position, - radius: 1.5 * PLAYER_RADIUS, + position: collision_player_position.0, + radius: 1.5 * Shape::player().radius, duration: None, source_player, area_of_effect_type: AreaOfEffectType::Slow, })); commands.spawn(ProjectileBundle::new(Projectile { type_: ProjectileType::Instant(InstantProjectile { - target_player: collision_id, + target_player: collision_player_id, }), source_player, damage: dash.damage, })); - if let Ok(mut imperative) = imperatives.get_mut(source_entity) { + if let Ok(mut imperative) = imperatives.get_mut(*source_entity) { *imperative = - Imperative::AttackTarget(AbilitySlot::A, collision_id); + Imperative::AttackTarget(AbilitySlot::A, collision_player_id); } } }, @@ -335,61 +318,52 @@ pub struct DashCollisionResult { pub dash_collision: Option<DashCollision>, } +impl DashCollisionResult { + fn from_player_player_collision_result( + player_player_collision_result: PlayerPlayerCollisionResult, + ) -> Self { + DashCollisionResult { + dash_end: player_player_collision_result.final_position, + dash_collision: player_player_collision_result.collision.map( + |player_player_collision| { + DashCollision::from_player_player_collision(player_player_collision) + }, + ), + } + } +} + pub struct DashCollision { - pub collision_id: PlayerId, - pub collision_position: Vec2, + pub collision_entity: Entity, + pub collision_player_id: PlayerId, + pub collision_player_position: PlayerPosition, + pub collision_shape: Shape, +} + +impl DashCollision { + fn from_player_player_collision(player_player_collision: PlayerPlayerCollision) -> Self { + DashCollision { + collision_entity: player_player_collision.collision_entity, + collision_player_id: player_player_collision.collision_player_id, + collision_player_position: player_player_collision.collision_player_position, + collision_shape: player_player_collision.collision_shape, + } + } } pub fn dash_collision( - source_id: PlayerId, - dash_start: Vec2, + source_entity: Entity, dash_direction: Vec2, dash_max_distance: f32, - player_positions: &Query<(&PlayerId, &PlayerPosition)>, -) -> DashCollisionResult { - let mut dash_collision = dash_max_distance * dash_direction; - let mut collision_id = None; - let mut collision_position = None; - for (player_id, position) in player_positions.iter() { - if *player_id == source_id { - continue; - } - - let player_position = position.0 - dash_start; - let player_projection = player_position.project_onto(dash_collision); - let player_rejection = player_position - player_projection; - let scalar_factor = player_projection.dot(dash_collision).signum() - * player_projection.length() - / dash_collision.length(); - - if scalar_factor < 0. || scalar_factor > 1.0 { - continue; - } - - if player_rejection.length() < 2. * PLAYER_RADIUS { - dash_collision = player_projection; - collision_id = Some(*player_id); - collision_position = Some(position.0); - } - } - - if let (Some(collision_id), Some(collision_position)) = (collision_id, collision_position) { - let dash_end = dash_start - + (dash_collision.length() - 2. * PLAYER_RADIUS) * dash_collision.normalize_or_zero(); - DashCollisionResult { - dash_end, - dash_collision: Some(DashCollision { - collision_id, - collision_position, - }), - } - } else { - let dash_end = dash_start + dash_max_distance * dash_direction; - DashCollisionResult { - dash_end, - dash_collision: None, - } - } + dash_targets: &Query<(Entity, &PlayerId, &PlayerPosition, &Shape)>, +) -> Option<DashCollisionResult> { + player_player_collision( + source_entity, + dash_direction, + dash_max_distance, + dash_targets, + ) + .map(DashCollisionResult::from_player_player_collision_result) } fn pull_activation(pull: Pull) -> DirectionalAbilityActivation { @@ -401,7 +375,7 @@ fn pull_activation(pull: Pull) -> DirectionalAbilityActivation { mut imperatives: Query<&mut Imperative>, mut set: ParamSet<( Query<&mut PlayerPosition>, - Query<(&PlayerId, &PlayerPosition)>, + Query<(Entity, &PlayerId, &PlayerPosition, &Shape)>, )>, mut commands: Commands| { let Some(source_entity) = ({ @@ -418,26 +392,14 @@ fn pull_activation(pull: Pull) -> DirectionalAbilityActivation { 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(PullCollision { + let Some(PullCollisionResult { pull_end, - collision_id, + collision_player_id, .. }) = ({ let pull_targets = set.p1(); pull_collision( - source_player, - source_position.0, + source_entity, direction.normalize_or_zero(), pull.max_distance, &pull_targets, @@ -450,7 +412,7 @@ fn pull_activation(pull: Pull) -> DirectionalAbilityActivation { let Some(target_entity) = ({ let mut target_entity = None; for (entity, player_id) in players.iter() { - if *player_id != collision_id { + if *player_id != collision_player_id { continue; } target_entity = Some(entity); @@ -468,13 +430,14 @@ fn pull_activation(pull: Pull) -> DirectionalAbilityActivation { commands.spawn(ProjectileBundle::new(Projectile { type_: ProjectileType::Instant(InstantProjectile { - target_player: collision_id, + target_player: collision_player_id, }), source_player, damage: pull.damage, })); if let Ok(mut imperative) = imperatives.get_mut(source_entity) { - *imperative = Imperative::AttackTarget(AbilitySlot::A, collision_id); + *imperative = + Imperative::AttackTarget(AbilitySlot::A, collision_player_id); } }, ) @@ -483,56 +446,122 @@ fn pull_activation(pull: Pull) -> DirectionalAbilityActivation { ) } -pub struct PullCollision { +#[derive(Clone, Copy)] +pub struct PullCollisionResult { pub pull_end: Vec2, - pub collision_id: PlayerId, - pub collision_position: Vec2, + pub collision_entity: Entity, + pub collision_player_id: PlayerId, + pub collision_player_position: PlayerPosition, + pub collision_shape: Shape, +} + +impl PullCollisionResult { + fn from_player_player_collision_result( + player_player_collision_result: PlayerPlayerCollisionResult, + ) -> Option<Self> { + player_player_collision_result + .collision + .map(|player_player_collision| PullCollisionResult { + pull_end: player_player_collision.collision_player_position.0 + - (player_player_collision_result.final_position + - player_player_collision_result.source_player_position.0), + collision_entity: player_player_collision.collision_entity, + collision_player_id: player_player_collision.collision_player_id, + collision_player_position: player_player_collision.collision_player_position, + collision_shape: player_player_collision.collision_shape, + }) + } } pub fn pull_collision( - source_id: PlayerId, - pull_start: Vec2, + source_entity: Entity, pull_direction: Vec2, pull_max_distance: f32, - player_positions: &Query<(&PlayerId, &PlayerPosition)>, -) -> Option<PullCollision> { - 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 { + pull_targets: &Query<(Entity, &PlayerId, &PlayerPosition, &Shape)>, +) -> Option<PullCollisionResult> { + player_player_collision( + source_entity, + pull_direction, + pull_max_distance, + pull_targets, + ) + .and_then(PullCollisionResult::from_player_player_collision_result) +} + +pub struct PlayerPlayerCollisionResult { + pub final_position: Vec2, + pub source_entity: Entity, + pub source_player_id: PlayerId, + pub source_player_position: PlayerPosition, + pub source_shape: Shape, + pub collision: Option<PlayerPlayerCollision>, +} + +pub struct PlayerPlayerCollision { + pub collision_entity: Entity, + pub collision_player_id: PlayerId, + pub collision_player_position: PlayerPosition, + pub collision_shape: Shape, +} + +pub fn player_player_collision( + source_entity: Entity, + direction: Vec2, + max_distance: f32, + targets: &Query<(Entity, &PlayerId, &PlayerPosition, &Shape)>, +) -> Option<PlayerPlayerCollisionResult> { + let Ok((_, source_player_id, source_player_position, source_shape)) = + targets.get(source_entity) + else { + return None; + }; + let start = source_player_position.0; + + let mut result = PlayerPlayerCollisionResult { + final_position: max_distance * direction, + source_entity, + source_player_id: *source_player_id, + source_player_position: *source_player_position, + source_shape: *source_shape, + collision: None, + }; + for (entity, player_id, position, shape) in targets.iter() { + if entity == source_entity { 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(); + let target_position = position.0 - start; + let target_projection = target_position.project_onto(result.final_position); + let target_rejection = target_position - target_projection; + let scalar_factor = target_projection.dot(result.final_position).signum() + * target_projection.length() + / result.final_position.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 target_rejection.length() < source_shape.radius + shape.radius { + result.final_position = target_projection; + result.collision = Some(PlayerPlayerCollision { + collision_entity: entity, + collision_player_id: *player_id, + collision_player_position: *position, + collision_shape: *shape, + }); } } - if let (Some(target_id), Some(target_position)) = (pull_player_id, pull_player_position) { - let pull_direction = pull_start - target_position; - let pull_end = target_position - + (pull_direction.length() - 2. * PLAYER_RADIUS) * pull_direction.normalize_or_zero(); - Some(PullCollision { - pull_end, - collision_id: *target_id, - collision_position: target_position, - }) + if let Some(ref mut collision) = result.collision { + result.final_position = start + + (result.final_position.length() + - source_shape.radius + - collision.collision_shape.radius) + * result.final_position.normalize_or_zero(); + Some(result) } else { - None + result.final_position += start; + Some(result) } } |