use bevy::log::LogPlugin;
use bevy::prelude::*;
use bevy::utils::tracing::{debug, trace};
use big_brain::prelude::*;
#[derive(Component, Debug)]
pub struct Thirst {
pub per_second: f32,
pub thirst: f32,
}
impl Thirst {
pub fn new(thirst: f32, per_second: f32) -> Self {
Self { thirst, per_second }
}
}
pub fn thirst_system(time: Res<Time>, mut thirsts: Query<&mut Thirst>) {
for mut thirst in &mut thirsts {
thirst.thirst += thirst.per_second * (time.delta().as_micros() as f32 / 1_000_000.0);
if thirst.thirst >= 100.0 {
thirst.thirst = 100.0;
}
trace!("Thirst: {}", thirst.thirst);
}
}
#[derive(Clone, Component, Debug, ActionBuilder)]
pub struct Drink {
until: f32,
per_second: f32,
}
fn drink_action_system(
time: Res<Time>,
mut thirsts: Query<&mut Thirst>,
mut query: Query<(&Actor, &mut ActionState, &Drink, &ActionSpan)>,
) {
for (Actor(actor), mut state, drink, span) in &mut query {
let _guard = span.span().enter();
if let Ok(mut thirst) = thirsts.get_mut(*actor) {
match *state {
ActionState::Requested => {
debug!("Time to drink some water!");
*state = ActionState::Executing;
}
ActionState::Executing => {
trace!("Drinking...");
thirst.thirst -=
drink.per_second * (time.delta().as_micros() as f32 / 1_000_000.0);
if thirst.thirst <= drink.until {
debug!("Done drinking water");
*state = ActionState::Success;
}
}
ActionState::Cancelled => {
debug!("Action was cancelled. Considering this a failure.");
*state = ActionState::Failure;
}
_ => {}
}
}
}
}
#[derive(Clone, Component, Debug, ScorerBuilder)]
pub struct Thirsty;
pub fn thirsty_scorer_system(
thirsts: Query<&Thirst>,
mut query: Query<(&Actor, &mut Score, &ScorerSpan), With<Thirsty>>,
) {
for (Actor(actor), mut score, span) in &mut query {
if let Ok(thirst) = thirsts.get(*actor) {
score.set(thirst.thirst / 100.0);
if thirst.thirst >= 80.0 {
span.span().in_scope(|| {
debug!("Thirst above threshold! Score: {}", thirst.thirst / 100.0)
});
}
}
}
}
pub fn init_entities(mut cmd: Commands) {
cmd.spawn((
Thirst::new(75.0, 2.0),
Thinker::build()
.label("My Thinker")
.picker(FirstToScore { threshold: 0.8 })
.when(
Thirsty,
Drink {
until: 70.0,
per_second: 5.0,
},
),
));
}
fn main() {
App::new()
.add_plugins(MinimalPlugins)
.add_plugins(LogPlugin {
filter: "big_brain=debug,thirst=debug".to_string(),
..default()
})
.add_plugins(BigBrainPlugin::new(PreUpdate))
.add_systems(Startup, init_entities)
.add_systems(Update, thirst_system)
.add_systems(
PreUpdate,
(
drink_action_system.in_set(BigBrainSet::Actions),
thirsty_scorer_system.in_set(BigBrainSet::Scorers),
),
)
.run();
}