Skip to content

Commit

Permalink
Clean up entity chasing API
Browse files Browse the repository at this point in the history
  • Loading branch information
Indy2222 committed Feb 6, 2023
1 parent 3fa1d4e commit 0a94c32
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 33 deletions.
91 changes: 77 additions & 14 deletions crates/behaviour/src/chase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,65 @@ pub(crate) struct ChasePlugin;

impl Plugin for ChasePlugin {
fn build(&self, app: &mut App) {
app.add_system_set_to_stage(
GameStage::Update,
SystemSet::new().with_system(chase.run_in_state(GameState::Playing)),
);
app.add_event::<ChaseTargetEvent>()
.add_system_to_stage(
GameStage::PreUpdate,
handle_chase_events
.run_in_state(GameState::Playing)
.label(ChaseLabel::ChaseTargetEvent),
)
.add_system_set_to_stage(
GameStage::Update,
SystemSet::new().with_system(chase.run_in_state(GameState::Playing)),
);
}
}

#[derive(Copy, Clone, Hash, Debug, PartialEq, Eq, SystemLabel)]
pub enum ChaseLabel {
ChaseTargetEvent,
}

/// Send this event to start or stop chasing of an entity (movable or static).
pub struct ChaseTargetEvent {
entity: Entity,
target: Option<ChaseTarget>,
}

impl ChaseTargetEvent {
/// Creates a new chase event.
///
/// # Arguments
///
/// * `entity` - the chasing entity.
///
/// * `target` - target to chase or None if chasing shall be stopped.
pub fn new(entity: Entity, target: Option<ChaseTarget>) -> Self {
Self { entity, target }
}

fn entity(&self) -> Entity {
self.entity
}

fn target(&self) -> Option<&ChaseTarget> {
self.target.as_ref()
}
}

/// Units with this component will chase the target entity.
#[derive(Component)]
#[derive(Component, Deref)]
pub struct ChaseTargetComponent(ChaseTarget);

impl ChaseTargetComponent {
fn new(target: ChaseTarget) -> Self {
Self(target)
}
}

#[derive(Clone)]
pub struct ChaseTarget {
entity: Entity,
target: Entity,
min_distance: f32,
max_distance: f32,
}
Expand All @@ -27,7 +75,7 @@ impl ChaseTarget {
///
/// # Arguments
///
/// * `entity` - entity to chase.
/// * `target` - entity to chase.
///
/// * `min_distance` - minimum distance between the chasing entity and the
/// cased entity. Elevation is ignored during the distance calculation.
Expand All @@ -40,22 +88,22 @@ impl ChaseTarget {
/// May panic if `min_distance` or `max_distance` is not non-negative
/// finite number or when `min_distance` is greater or equal to
/// `max_distance`.
pub fn new(entity: Entity, min_distance: f32, max_distance: f32) -> Self {
pub fn new(target: Entity, min_distance: f32, max_distance: f32) -> Self {
debug_assert!(min_distance.is_finite());
debug_assert!(max_distance.is_finite());
debug_assert!(min_distance >= 0.);
debug_assert!(max_distance >= 0.);
debug_assert!(min_distance < max_distance);

Self {
entity,
target,
min_distance,
max_distance,
}
}

pub fn entity(&self) -> Entity {
self.entity
pub fn target(&self) -> Entity {
self.target
}

fn min_distance(&self) -> f32 {
Expand All @@ -67,17 +115,32 @@ impl ChaseTarget {
}
}

fn handle_chase_events(mut commands: Commands, mut events: EventReader<ChaseTargetEvent>) {
for event in events.iter() {
let mut entity_commands = commands.entity(event.entity());
match event.target() {
Some(target) => entity_commands.insert(ChaseTargetComponent::new(target.clone())),
None => entity_commands.remove::<ChaseTargetComponent>(),
};
}
}

fn chase(
mut commands: Commands,
mut path_events: EventWriter<UpdateEntityPath>,
chasing: Query<(Entity, &Transform, &ChaseTarget, Option<&PathTarget>)>,
chasing: Query<(
Entity,
&Transform,
&ChaseTargetComponent,
Option<&PathTarget>,
)>,
targets: Query<&Transform>,
) {
for (entity, transform, chase_target, path_target) in chasing.iter() {
let target_position = match targets.get(chase_target.entity()) {
let target_position = match targets.get(chase_target.target()) {
Ok(transform) => transform.translation.to_flat(),
Err(_) => {
commands.entity(entity).remove::<ChaseTarget>();
commands.entity(entity).remove::<ChaseTargetComponent>();
continue;
}
};
Expand Down
2 changes: 1 addition & 1 deletion crates/behaviour/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use bevy::{app::PluginGroupBuilder, prelude::PluginGroup};
use chase::ChasePlugin;
pub use chase::ChaseTarget;
pub use chase::{ChaseLabel, ChaseTarget, ChaseTargetComponent, ChaseTargetEvent};

mod chase;

Expand Down
23 changes: 13 additions & 10 deletions crates/combat/src/attack.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{cmp::Ordering, collections::BinaryHeap};

use bevy::prelude::*;
use de_behaviour::ChaseTarget;
use de_behaviour::{ChaseLabel, ChaseTarget, ChaseTargetComponent, ChaseTargetEvent};
use de_core::{objects::ObjectType, stages::GameStage, state::GameState};
use de_objects::{ColliderCache, LaserCannon, ObjectCache};
use iyes_loopless::prelude::*;
Expand All @@ -24,7 +24,9 @@ impl Plugin for AttackPlugin {
app.add_event::<AttackEvent>()
.add_system_to_stage(
GameStage::PreUpdate,
attack.run_in_state(GameState::Playing),
attack
.run_in_state(GameState::Playing)
.before(ChaseLabel::ChaseTargetEvent),
)
.add_system_set_to_stage(
GameStage::Update,
Expand Down Expand Up @@ -67,17 +69,18 @@ impl AttackEvent {
struct Attacking;

fn attack(
mut commands: Commands,
mut events: EventReader<AttackEvent>,
mut attack_events: EventReader<AttackEvent>,
cannons: Query<&LaserCannon>,
mut chase_events: EventWriter<ChaseTargetEvent>,
) {
for event in events.iter() {
for event in attack_events.iter() {
if let Ok(cannon) = cannons.get(event.attacker()) {
commands.entity(event.attacker()).insert(ChaseTarget::new(
let target = ChaseTarget::new(
event.enemy(),
MIN_CHASE_DISTNACE * cannon.range(),
MAX_CHASE_DISTNACE * cannon.range(),
));
);
chase_events.send(ChaseTargetEvent::new(event.attacker(), Some(target)));
}
}
}
Expand All @@ -95,7 +98,7 @@ fn aim_and_fire(
Entity,
&Transform,
&mut LaserCannon,
&ChaseTarget,
&ChaseTargetComponent,
Option<&Attacking>,
)>,
targets: Query<(&Transform, &ObjectType)>,
Expand All @@ -108,7 +111,7 @@ fn aim_and_fire(
let mut fire_queue = BinaryHeap::new();

for (attacker, attacker_transform, mut cannon, target, marker) in attackers {
let target_position = match targets.get(target.entity()) {
let target_position = match targets.get(target.target()) {
Ok((transform, &object_type)) => {
let centroid: Vec3 = cache.get_collider(object_type).aabb().center().into();
transform.translation + centroid
Expand All @@ -124,7 +127,7 @@ fn aim_and_fire(
let aims_at_target = sightline
.sight(&ray, cannon.range(), attacker)
.entity()
.map_or(true, |e| e != target.entity());
.map_or(true, |e| e != target.target());

if aims_at_target {
if marker.is_some() {
Expand Down
13 changes: 5 additions & 8 deletions crates/controller/src/commands/executor.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use bevy::prelude::*;
use de_behaviour::ChaseTarget;
use de_behaviour::ChaseTargetEvent;
use de_combat::AttackEvent;
use de_core::{objects::MovableSolid, stages::GameStage, state::AppState};
use de_pathing::{PathQueryProps, PathTarget, UpdateEntityPath};
Expand Down Expand Up @@ -67,17 +67,14 @@ impl GroupAttackEvent {
type SelectedMovable = (With<Selected>, With<MovableSolid>);

fn send_selected_system(
mut commands: Commands,
mut send_events: EventReader<SendSelectedEvent>,
selected: Query<(Entity, Option<&ChaseTarget>), SelectedMovable>,
selected: Query<Entity, SelectedMovable>,
mut path_events: EventWriter<UpdateEntityPath>,
mut chase_events: EventWriter<ChaseTargetEvent>,
) {
if let Some(send) = send_events.iter().last() {
for (entity, chase) in selected.iter() {
if chase.is_some() {
commands.entity(entity).remove::<ChaseTarget>();
}

for entity in selected.iter() {
chase_events.send(ChaseTargetEvent::new(entity, None));
path_events.send(UpdateEntityPath::new(
entity,
PathTarget::new(send.target(), PathQueryProps::exact(), false),
Expand Down

0 comments on commit 0a94c32

Please sign in to comment.