diff --git a/examples/thirst.rs b/examples/thirst.rs index b9bab55cd44e0af7546f2acf4b102204a9b2aa81..062eeca9a6b5a272c30d06291c7f9b53eb7b2213 100644 --- a/examples/thirst.rs +++ b/examples/thirst.rs @@ -78,9 +78,9 @@ fn drink_action_system( // usually happen because the target action changed (due to a different // Scorer winning). But you can also cancel the actions yourself by // setting the state in the Action system. - mut query: Query<(&Parent, &mut ActionState), With<Drink>>, + mut query: Query<(&Actor, &mut ActionState), With<Drink>>, ) { - for (Parent(actor), mut state) in query.iter_mut() { + for (Actor(actor), mut state) in query.iter_mut() { // Use the drink_action's actor to look up the corresponding Thirst. if let Ok(mut thirst) = thirsts.get_mut(*actor) { match *state { @@ -128,9 +128,9 @@ impl ScorerBuilder for ThirstyBuilder { pub fn thirsty_scorer_system( thirsts: Query<&Thirst>, // Same dance with the Parent here, but now Big Brain has added a Score component! - mut query: Query<(&Parent, &mut Score), With<Thirsty>>, + mut query: Query<(&Actor, &mut Score), With<Thirsty>>, ) { - for (Parent(actor), mut score) in query.iter_mut() { + for (Actor(actor), mut score) in query.iter_mut() { if let Ok(thirst) = thirsts.get(*actor) { // This is really what the job of a Scorer is. To calculate a // generic Utility value that the Big Brain engine will compare @@ -153,13 +153,15 @@ pub fn init_entities(mut cmd: Commands) { let actor = cmd.spawn().insert(Thirst::new(70.0, 2.0)).id(); // And finally, we put all the pieces together! - Thinker::build() + let thinker = Thinker::build() .picker(FirstToScore { threshold: 80.0 }) // Note that what we pass in are _builders_, not components! .when(Thirsty::build(), Drink::build()) // .attach will do all the necessary work of attaching this component // and hooking it up to the AI system. .attach(&mut cmd, actor); + // TODO: this is a footgun and a pita. Please ignore. + cmd.entity(actor).push_children(&[thinker]); } fn main() { diff --git a/src/actions.rs b/src/actions.rs index 336540b989497926a1c886c4a397bc09bc0754c7..849752f7a149b192593d4198bae815e6198fdbbf 100644 --- a/src/actions.rs +++ b/src/actions.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use bevy::prelude::*; -use crate::ActionEnt; +use crate::{ActionEnt, Actor}; #[derive(Debug, Clone, Eq, PartialEq)] pub enum ActionState { @@ -42,8 +42,7 @@ pub trait ActionBuilder: std::fmt::Debug + Send + Sync { fn build(&self, cmd: &mut Commands, action: Entity, actor: Entity); fn attach(&self, cmd: &mut Commands, actor: Entity) -> Entity { let action_ent = ActionEnt(cmd.spawn().id()); - cmd.entity(action_ent.0).insert(ActionState::new()); - cmd.entity(actor).push_children(&[action_ent.0]); + cmd.entity(action_ent.0).insert(ActionState::new()).insert(Actor(actor)); self.build(cmd, action_ent.0, actor); action_ent.0 } @@ -68,7 +67,7 @@ impl ActionBuilder for StepsBuilder { active_step: 0, active_ent: ActionEnt(child_action), steps: self.steps.clone(), - }); + }).push_children(&[child_action]); } } #[derive(Debug)] @@ -86,11 +85,11 @@ impl Steps { pub fn steps_system( mut cmd: Commands, - mut steps_q: Query<(Entity, &Parent, &mut Steps)>, + mut steps_q: Query<(Entity, &Actor, &mut Steps)>, mut states: Query<&mut ActionState>, ) { use ActionState::*; - for (seq_ent, Parent(actor), mut steps_action) in steps_q.iter_mut() { + for (seq_ent, Actor(actor), mut steps_action) in steps_q.iter_mut() { let current_state = states.get_mut(seq_ent).expect("uh oh").clone(); match current_state { Requested => { @@ -131,6 +130,7 @@ pub fn steps_system( steps_action.active_step += 1; let step_builder = steps_action.steps[steps_action.active_step].clone(); let step_ent = step_builder.attach(&mut cmd, *actor); + cmd.entity(seq_ent).push_children(&[step_ent]); let mut step_state = states.get_mut(step_ent).expect("oops"); *step_state = ActionState::Requested; } diff --git a/src/choices.rs b/src/choices.rs index 205896457e0dc786621768c4a9da3d71c20b7111..cc8a30e5157646161e58ec48a0146d470ec7625b 100644 --- a/src/choices.rs +++ b/src/choices.rs @@ -36,7 +36,9 @@ impl ChoiceBuilder { } } - pub fn build(&self, cmd: &mut Commands, actor: Entity) -> Choice { + pub fn build(&self, cmd: &mut Commands, actor: Entity, parent: Entity) -> Choice { + let scorer_ent = self.when.attach(cmd, actor); + cmd.entity(parent).push_children(&[scorer_ent]); Choice { scorer: ScorerEnt(self.when.attach(cmd, actor)), action: ActionBuilderWrapper::new(self.then.clone()), diff --git a/src/scorers.rs b/src/scorers.rs index 19ee5356ec44e2602458b6aec62746a0a580c8a9..4ed43106601963c5199d3c52cd81417e9fb933e6 100644 --- a/src/scorers.rs +++ b/src/scorers.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use bevy::prelude::*; -use crate::ScorerEnt; +use crate::{Actor, ScorerEnt}; #[derive(Debug, Clone, Default)] pub struct Score(pub(crate) f32); @@ -23,8 +23,9 @@ pub trait ScorerBuilder: std::fmt::Debug + Sync + Send { fn build(&self, cmd: &mut Commands, scorer: Entity, actor: Entity); fn attach(&self, cmd: &mut Commands, actor: Entity) -> Entity { let scorer_ent = cmd.spawn().id(); - cmd.entity(scorer_ent).insert(Score::default()); - cmd.entity(actor).push_children(&[scorer_ent]); + cmd.entity(scorer_ent) + .insert(Score::default()) + .insert(Actor(actor)); self.build(cmd, scorer_ent, actor); scorer_ent } @@ -114,6 +115,7 @@ impl ScorerBuilder for AllOrNothingBuilder { .collect(); cmd.entity(scorer) .insert(Score::default()) + .push_children(&scorers[..]) .insert(super::AllOrNothing { threshold: self.threshold, scorers: scorers.into_iter().map(ScorerEnt).collect(), diff --git a/src/thinker.rs b/src/thinker.rs index b8bcce66b1afb3ff1401de2bbc076424f9a1cbf4..a9ec2df1053859c1e551962b398b910cf5f87fac 100644 --- a/src/thinker.rs +++ b/src/thinker.rs @@ -12,6 +12,9 @@ use crate::{ scorers::{Score, ScorerBuilder}, }; +#[derive(Debug, Clone, Copy)] +pub struct Actor(pub Entity); + #[derive(Debug, Clone, Copy)] pub struct ActionEnt(pub Entity); @@ -74,7 +77,7 @@ impl ActionBuilder for ThinkerBuilder { let choices = self .choices .iter() - .map(|choice| choice.build(cmd, actor)) + .map(|choice| choice.build(cmd, actor, action_ent)) .collect(); cmd.entity(action_ent) .insert(Thinker { @@ -116,12 +119,12 @@ impl Default for ThinkerIterations { pub fn thinker_system( mut cmd: Commands, mut iterations: Local<ThinkerIterations>, - mut thinker_q: Query<(Entity, &Parent, &mut Thinker, &ActiveThinker)>, + mut thinker_q: Query<(Entity, &Actor, &mut Thinker, &ActiveThinker)>, utilities: Query<&Score>, mut action_states: Query<&mut actions::ActionState>, ) { let start = Instant::now(); - for (thinker_ent, Parent(actor), mut thinker, active_thinker) in + for (thinker_ent, Actor(actor), mut thinker, active_thinker) in thinker_q.iter_mut().skip(iterations.index) { iterations.index += 1; @@ -189,7 +192,7 @@ pub fn thinker_system( actions::ActionState::Init | actions::ActionState::Success | actions::ActionState::Failure => { - cmd.entity(current.0 .0).despawn_recursive(); + cmd.entity(current.0.0).despawn_recursive(); thinker.current_action = None; } _ => {