Discussion
Loading...

#Tag

Log in
  • About
  • Code of conduct
  • Privacy
  • Users
  • Instances
  • About Bonfire
kat
kat
@zkat@toot.cat  ·  activity timestamp 4 months ago

Seeking feedback from Bevy and Big Brain users: how does this new API look?

Under the hood, this would be a high-performance, low-overhead API powered by Observers, but this is all you would actually need to write yourself.

I'm pretty sure I can get this to work with Bevy's current featureset, including the Very Fun async actions situation here.

#Bevy #BigBrain #GameAI #Rust #RustLang

#[derive(Debug, Default, Clone, Copy, Component)]
pub struct Thirsty;

#[scorer_for(Thirsty)]
pub fn score_thirsty(score: Score, thirsts: Query<&Thirst>) -> Score {
    score.update(thirsts.get(score.actor()).unwrap().thirst)
}

#[derive(Debug, Clone, Copy, Component)]
pub struct Drink { rate: f32, per: Duration }
impl Default for Drink {
    fn default() -> Self {
        Self { rate: 0.5, per: Duration::from_millis(500), }
    }
}

#[action_for(Drink)]
pub async fn drink_action(
    action: Action<Drink>,
    mut thirsts: Query<&mut Thirst>
) -> Result<(), ActionFailure> {
    while let Ok(mut thirst) = thirsts.get(action.actor()) && thirst.thirst > 10.0 {
        action.check_cancelled()?;
        thirst.thirst -= action.data().rate;
        action.sleep(action.data().per).await;
    }
    Ok(())
}

fn spawn_entity(cmd: &mut Commands) {
    cmd.spawn((
        Thirst(70.0, 2.0),
        Thinker::new()
            .picker(FirstToScore { threshold: 0.8 })
            .when<Thirsty, Drink>(),
    ));
}
#[derive(Debug, Default, Clone, Copy, Component)] pub struct Thirsty; #[scorer_for(Thirsty)] pub fn score_thirsty(score: Score, thirsts: Query<&Thirst>) -> Score { score.update(thirsts.get(score.actor()).unwrap().thirst) } #[derive(Debug, Clone, Copy, Component)] pub struct Drink { rate: f32, per: Duration } impl Default for Drink { fn default() -> Self { Self { rate: 0.5, per: Duration::from_millis(500), } } } #[action_for(Drink)] pub async fn drink_action( action: Action<Drink>, mut thirsts: Query<&mut Thirst> ) -> Result<(), ActionFailure> { while let Ok(mut thirst) = thirsts.get(action.actor()) && thirst.thirst > 10.0 { action.check_cancelled()?; thirst.thirst -= action.data().rate; action.sleep(action.data().per).await; } Ok(()) } fn spawn_entity(cmd: &mut Commands) { cmd.spawn(( Thirst(70.0, 2.0), Thinker::new() .picker(FirstToScore { threshold: 0.8 }) .when<Thirsty, Drink>(), )); }
#[derive(Debug, Default, Clone, Copy, Component)] pub struct Thirsty; #[scorer_for(Thirsty)] pub fn score_thirsty(score: Score, thirsts: Query<&Thirst>) -> Score { score.update(thirsts.get(score.actor()).unwrap().thirst) } #[derive(Debug, Clone, Copy, Component)] pub struct Drink { rate: f32, per: Duration } impl Default for Drink { fn default() -> Self { Self { rate: 0.5, per: Duration::from_millis(500), } } } #[action_for(Drink)] pub async fn drink_action( action: Action<Drink>, mut thirsts: Query<&mut Thirst> ) -> Result<(), ActionFailure> { while let Ok(mut thirst) = thirsts.get(action.actor()) && thirst.thirst > 10.0 { action.check_cancelled()?; thirst.thirst -= action.data().rate; action.sleep(action.data().per).await; } Ok(()) } fn spawn_entity(cmd: &mut Commands) { cmd.spawn(( Thirst(70.0, 2.0), Thinker::new() .picker(FirstToScore { threshold: 0.8 }) .when<Thirsty, Drink>(), )); }
Federation Bot
Federation Bot
@Federation_Bot replied  ·  activity timestamp 4 months ago

Big Brain, btw, is designed to be data-oriented, so I might provide an API that lets you define game AI in .kdl files that look like this. It could also, for example, eventually use a hypothetical node editor (thing Blender Geometry Nodes), to define the same data.

#KDL #Bevy #BigBrain #GameAI

Thinker {
    picker FirstToScore threshold=0.8
    when Thirsty {
        GoToWater
        Drink
    }
    when Hungry {
        Eat
    }
    or Bored Paranoid {
        Thinker {
            when EnemySpotted {
                ShootEnemy
            }
            when FlowersSpotted {
                WalkToFlowers
                PickAFlower
                SmellFlower
            }
            otherwise {
                Parallel {
                    Wander
                    HumATune
                }
            }
        }
    }
}
Thinker { picker FirstToScore threshold=0.8 when Thirsty { GoToWater Drink } when Hungry { Eat } or Bored Paranoid { Thinker { when EnemySpotted { ShootEnemy } when FlowersSpotted { WalkToFlowers PickAFlower SmellFlower } otherwise { Parallel { Wander HumATune } } } } }
Thinker { picker FirstToScore threshold=0.8 when Thirsty { GoToWater Drink } when Hungry { Eat } or Bored Paranoid { Thinker { when EnemySpotted { ShootEnemy } when FlowersSpotted { WalkToFlowers PickAFlower SmellFlower } otherwise { Parallel { Wander HumATune } } } } }
  • Copy link
  • Flag this comment
  • Block
kat
kat
@zkat@toot.cat  ·  activity timestamp 4 months ago

FYI: As part of a larger move away from GitHub, I've archived Big Brain on it and moved all future development over to Codeberg, at https://codeberg.org/zkat/big-brain

Please use that repo from now on.

Additionally: I am in the process of trying a major rewrite of the crate that I'm hoping will be much simpler, and much more efficient, thanks to features now available in recent version of Bevy! I'm very excited :)

#GiveUpGitHub #GitHub #Bevy #Rust #RustLang #Codeberg

kat
kat
@zkat@toot.cat replied  ·  activity timestamp 4 months ago

Seeking feedback from Bevy and Big Brain users: how does this new API look?

Under the hood, this would be a high-performance, low-overhead API powered by Observers, but this is all you would actually need to write yourself.

I'm pretty sure I can get this to work with Bevy's current featureset, including the Very Fun async actions situation here.

#Bevy #BigBrain #GameAI #Rust #RustLang

#[derive(Debug, Default, Clone, Copy, Component)]
pub struct Thirsty;

#[scorer_for(Thirsty)]
pub fn score_thirsty(score: Score, thirsts: Query<&Thirst>) -> Score {
    score.update(thirsts.get(score.actor()).unwrap().thirst)
}

#[derive(Debug, Clone, Copy, Component)]
pub struct Drink { rate: f32, per: Duration }
impl Default for Drink {
    fn default() -> Self {
        Self { rate: 0.5, per: Duration::from_millis(500), }
    }
}

#[action_for(Drink)]
pub async fn drink_action(
    action: Action<Drink>,
    mut thirsts: Query<&mut Thirst>
) -> Result<(), ActionFailure> {
    while let Ok(mut thirst) = thirsts.get(action.actor()) && thirst.thirst > 10.0 {
        action.check_cancelled()?;
        thirst.thirst -= action.data().rate;
        action.sleep(action.data().per).await;
    }
    Ok(())
}

fn spawn_entity(cmd: &mut Commands) {
    cmd.spawn((
        Thirst(70.0, 2.0),
        Thinker::new()
            .picker(FirstToScore { threshold: 0.8 })
            .when<Thirsty, Drink>(),
    ));
}
#[derive(Debug, Default, Clone, Copy, Component)] pub struct Thirsty; #[scorer_for(Thirsty)] pub fn score_thirsty(score: Score, thirsts: Query<&Thirst>) -> Score { score.update(thirsts.get(score.actor()).unwrap().thirst) } #[derive(Debug, Clone, Copy, Component)] pub struct Drink { rate: f32, per: Duration } impl Default for Drink { fn default() -> Self { Self { rate: 0.5, per: Duration::from_millis(500), } } } #[action_for(Drink)] pub async fn drink_action( action: Action<Drink>, mut thirsts: Query<&mut Thirst> ) -> Result<(), ActionFailure> { while let Ok(mut thirst) = thirsts.get(action.actor()) && thirst.thirst > 10.0 { action.check_cancelled()?; thirst.thirst -= action.data().rate; action.sleep(action.data().per).await; } Ok(()) } fn spawn_entity(cmd: &mut Commands) { cmd.spawn(( Thirst(70.0, 2.0), Thinker::new() .picker(FirstToScore { threshold: 0.8 }) .when<Thirsty, Drink>(), )); }
#[derive(Debug, Default, Clone, Copy, Component)] pub struct Thirsty; #[scorer_for(Thirsty)] pub fn score_thirsty(score: Score, thirsts: Query<&Thirst>) -> Score { score.update(thirsts.get(score.actor()).unwrap().thirst) } #[derive(Debug, Clone, Copy, Component)] pub struct Drink { rate: f32, per: Duration } impl Default for Drink { fn default() -> Self { Self { rate: 0.5, per: Duration::from_millis(500), } } } #[action_for(Drink)] pub async fn drink_action( action: Action<Drink>, mut thirsts: Query<&mut Thirst> ) -> Result<(), ActionFailure> { while let Ok(mut thirst) = thirsts.get(action.actor()) && thirst.thirst > 10.0 { action.check_cancelled()?; thirst.thirst -= action.data().rate; action.sleep(action.data().per).await; } Ok(()) } fn spawn_entity(cmd: &mut Commands) { cmd.spawn(( Thirst(70.0, 2.0), Thinker::new() .picker(FirstToScore { threshold: 0.8 }) .when<Thirsty, Drink>(), )); }
  • Copy link
  • Flag this comment
  • Block
kat
kat
@zkat@toot.cat  ·  activity timestamp 4 months ago

I'm just gonna keep waiting until the Bevy Editor finally comes out to try and write a game with the engine in earnest. I keep getting ideas but I just don't really wanna deal with writing something as complex and difficult as a game, with my hands tied behind my back any more than I have to.

that said, I'll probably be poking around the ecosystem sometime soon, after reading those updates on the observers in 0.17. They would make big-brain so much nicer to use, and probably simplify the implementation a lot (it would probably be a full rewrite?)

#bevy #bigbrain #gamedev #rust #rustlang

  • Copy link
  • Flag this post
  • Block

bonfire.cafe

A space for Bonfire maintainers and contributors to communicate

bonfire.cafe: About · Code of conduct · Privacy · Users · Instances
Bonfire social · 1.0.2-alpha.7 no JS en
Automatic federation enabled
Log in
  • Explore
  • About
  • Members
  • Code of Conduct