aboutsummaryrefslogtreecommitdiffstats
path: root/src/shared/ability.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared/ability.rs')
-rw-r--r--src/shared/ability.rs301
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)
}
}