From 278b2204ae2680cd33baf63b85baa7dd147bd82f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kat=20March=C3=A1n?= Date: Sat, 9 Dec 2023 15:26:53 -0800 Subject: [PATCH] wip new tutorial --- src/_topic/mod.rs | 0 src/_tutorial/chapter_0.rs | 149 +++++++++++++++++++++++++++++++++++++ src/_tutorial/chapter_1.rs | 6 ++ src/_tutorial/mod.rs | 6 ++ src/lib.rs | 126 ++----------------------------- 5 files changed, 168 insertions(+), 119 deletions(-) create mode 100644 src/_topic/mod.rs create mode 100644 src/_tutorial/chapter_0.rs create mode 100644 src/_tutorial/chapter_1.rs create mode 100644 src/_tutorial/mod.rs diff --git a/src/_topic/mod.rs b/src/_topic/mod.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/_tutorial/chapter_0.rs b/src/_tutorial/chapter_0.rs new file mode 100644 index 0000000..66c2e3a --- /dev/null +++ b/src/_tutorial/chapter_0.rs @@ -0,0 +1,149 @@ +//! # Chapter 0 - Overview +//! +//! Big Brain is a highliy-concurrent [Utility +//! AI](https://en.wikipedia.org/wiki/Utility_system) library for games, built +//! for the [Bevy Game Engine](https://bevyengine.org/). The building blocks +//! for Big Brain can be highly-generic and highly-composable, letting you +//! reuse logic across your game by defining them in small pieces and then +//! just putting them all together in a declarative way. +//! +//! ### High-level Overview +//! +//! As a developer, you write application-dependent code to define [`Scorer`]s +//! and [`Action`]s, and then put it all together like building blocks, using +//! [`Thinker`]s that will define the actual behavior. +//! +//! We'll go over each of these at a high-level, and cover them in more +//! details later. +//! +//! #### Scorers +//! +//! [`Scorer`]s are entities that look at the world and evaluate into +//! [`Score`] values. You can think of them as the "eyes" of the AI system. +//! They're a highly-parallel way of being able to look at the `World` and use +//! it to make some decisions later. +//! +//! They are constructed using [`ScorerBuilder`]s, for which there's a handy +//! shortcut `derive` macro. +//! +//! ```rust +//! use bevy::prelude::*; +//! use big_brain::prelude::*; +//! # #[derive(Component, Debug)] +//! # struct Thirst { thirst: f32 } +//! +//! #[derive(Debug, Clone, Component, ScorerBuilder)] +//! pub struct Thirsty; +//! +//! pub fn thirsty_scorer_system( +//! thirsts: Query<&Thirst>, +//! mut query: Query<(&Actor, &mut Score), With>, +//! ) { +//! for (Actor(actor), mut score) in query.iter_mut() { +//! if let Ok(thirst) = thirsts.get(*actor) { +//! score.set(thirst.thirst); +//! } +//! } +//! } +//! ``` +//! +//! #### Actions +//! +//! [`Action`]s are the actual things your entities will _do_. They are +//! connected to [`ActionState`]s that represent the current execution state +//! of the state machine. You can think of them as deconstructed async +//! functions. +//! +//! They are constructed using [`ActionBuilder`]s, for which there's a handy +//! shortcut `derive` macro. +//! +//! ```rust +//! use bevy::prelude::*; +//! use big_brain::prelude::*; +//! # #[derive(Component, Debug)] +//! # struct Thirst { thirst: f32 } +//! +//! #[derive(Debug, Clone, Component, ActionBuilder)] +//! pub struct Drink; +//! +//! fn drink_action_system( +//! mut thirsts: Query<&mut Thirst>, +//! mut query: Query<(&Actor, &mut ActionState), With>, +//! ) { +//! for (Actor(actor), mut state) in query.iter_mut() { +//! if let Ok(mut thirst) = thirsts.get_mut(*actor) { +//! match *state { +//! ActionState::Requested => { +//! thirst.thirst = 10.0; +//! *state = ActionState::Success; +//! } +//! ActionState::Cancelled => { +//! *state = ActionState::Failure; +//! } +//! _ => {} +//! } +//! } +//! } +//! } +//! ``` +//! +//! #### Thinkers +//! +//! Finally, you can use it when define the [`Thinker`], which you can attach +//! as a regular [`Component`]: +//! +//! ```rust +//! # use bevy::prelude::*; +//! # use big_brain::prelude::*; +//! # #[derive(Debug, Component)] +//! # struct Thirst(f32, f32); +//! # #[derive(Debug, Clone, Component, ScorerBuilder)] +//! # struct Thirsty; +//! # #[derive(Debug, Clone, Component, ActionBuilder)] +//! # struct Drink; +//! fn spawn_entity(cmd: &mut Commands) { +//! cmd.spawn(( +//! Thirst(70.0, 2.0), +//! Thinker::build() +//! .picker(FirstToScore { threshold: 0.8 }) +//! .when(Thirsty, Drink), +//! )); +//! } +//! ``` +//! +//! #### App +//! +//! Once all that's done, we just add our systems and off we go! +//! +//! ```no_run +//! # use bevy::prelude::*; +//! # use big_brain::prelude::*; +//! # fn init_entities() {} +//! # fn thirst_system() {} +//! # fn drink_action_system() {} +//! # fn thirsty_scorer_system() {} +//! fn main() { +//! App::new() +//! .add_plugins(DefaultPlugins) +//! .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)) +//! .add_systems(PreUpdate, thirsty_scorer_system.in_set(BigBrainSet::Scorers)) +//! .run(); +//! } +//! ``` +//! +//! #### What's next? +//! +//! You can read the general [crate docs][crate], or continue with the [next +//! chapter of the tutorial][_tutorial::chapter_1] for an expanded guide on +//! how to build out and organize the AI for your game using Big Brain!. +#[allow(unused_imports)] +use bevy::prelude::*; + +#[allow(unused_imports)] +use crate::prelude::{Action, ActionBuilder, ActionState, Score, Scorer, ScorerBuilder, Thinker}; + +pub use super::chapter_1 as next; +pub use crate::_tutorial as table_of_contents; diff --git a/src/_tutorial/chapter_1.rs b/src/_tutorial/chapter_1.rs new file mode 100644 index 0000000..0fa84c3 --- /dev/null +++ b/src/_tutorial/chapter_1.rs @@ -0,0 +1,6 @@ +//! # Chapter 1 +//! +//! + +// pub use super::chapter_2 as next; +pub use crate::_tutorial as table_of_contents; diff --git a/src/_tutorial/mod.rs b/src/_tutorial/mod.rs new file mode 100644 index 0000000..a371158 --- /dev/null +++ b/src/_tutorial/mod.rs @@ -0,0 +1,6 @@ +//! # Tutorial +//! +//! Table of Contents + +pub mod chapter_0; +pub mod chapter_1; diff --git a/src/lib.rs b/src/lib.rs index 20aa39e..be2fadb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,8 @@ //! perform actual behaviors upon the world). No other code is needed for //! actual AI behavior. //! -//! See [the documentation](https://docs.rs/big-brain) for more details. +//! See [the documentation](https://docs.rs/big-brain), alone with [the +//! tutorial][_tutorial::chapter_0] for more details. //! //! ### Features //! @@ -25,124 +26,6 @@ //! * State machine-style continuous actions/behaviors. //! * Action cancellation. //! -//! ### Example -//! -//! As a developer, you write application-dependent code to define -//! [`Scorers`](#scorers) and [`Actions`](#actions), and then put it all -//! together like building blocks, using [`Thinkers`](#thinkers) that will -//! define the actual behavior. -//! -//! #### Scorers -//! -//! `Scorer`s are entities that look at the world and evaluate into `Score` -//! values. You can think of them as the "eyes" of the AI system. They're a -//! highly-parallel way of being able to look at the `World` and use it to -//! make some decisions later. -//! -//! ```rust -//! use bevy::prelude::*; -//! use big_brain::prelude::*; -//! # #[derive(Component, Debug)] -//! # struct Thirst { thirst: f32 } -//! -//! #[derive(Debug, Clone, Component, ScorerBuilder)] -//! pub struct Thirsty; -//! -//! pub fn thirsty_scorer_system( -//! thirsts: Query<&Thirst>, -//! mut query: Query<(&Actor, &mut Score), With>, -//! ) { -//! for (Actor(actor), mut score) in query.iter_mut() { -//! if let Ok(thirst) = thirsts.get(*actor) { -//! score.set(thirst.thirst); -//! } -//! } -//! } -//! ``` -//! -//! #### Actions -//! -//! `Action`s are the actual things your entities will _do_. They are -//! connected to `ActionState`s that represent the current execution state of -//! the state machine. -//! -//! ```rust -//! use bevy::prelude::*; -//! use big_brain::prelude::*; -//! # #[derive(Component, Debug)] -//! # struct Thirst { thirst: f32 } -//! -//! #[derive(Debug, Clone, Component, ActionBuilder)] -//! pub struct Drink; -//! -//! fn drink_action_system( -//! mut thirsts: Query<&mut Thirst>, -//! mut query: Query<(&Actor, &mut ActionState), With>, -//! ) { -//! for (Actor(actor), mut state) in query.iter_mut() { -//! if let Ok(mut thirst) = thirsts.get_mut(*actor) { -//! match *state { -//! ActionState::Requested => { -//! thirst.thirst = 10.0; -//! *state = ActionState::Success; -//! } -//! ActionState::Cancelled => { -//! *state = ActionState::Failure; -//! } -//! _ => {} -//! } -//! } -//! } -//! } -//! ``` -//! -//! #### Thinkers -//! -//! Finally, you can use it when define the `Thinker`, which you can attach as -//! a regular Component: -//! -//! ```rust -//! # use bevy::prelude::*; -//! # use big_brain::prelude::*; -//! # #[derive(Debug, Component)] -//! # struct Thirst(f32, f32); -//! # #[derive(Debug, Clone, Component, ScorerBuilder)] -//! # struct Thirsty; -//! # #[derive(Debug, Clone, Component, ActionBuilder)] -//! # struct Drink; -//! fn spawn_entity(cmd: &mut Commands) { -//! cmd.spawn(( -//! Thirst(70.0, 2.0), -//! Thinker::build() -//! .picker(FirstToScore { threshold: 0.8 }) -//! .when(Thirsty, Drink), -//! )); -//! } -//! ``` -//! -//! #### App -//! -//! Once all that's done, we just add our systems and off we go! -//! -//! ```no_run -//! # use bevy::prelude::*; -//! # use big_brain::prelude::*; -//! # fn init_entities() {} -//! # fn thirst_system() {} -//! # fn drink_action_system() {} -//! # fn thirsty_scorer_system() {} -//! fn main() { -//! App::new() -//! .add_plugins(DefaultPlugins) -//! .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)) -//! .add_systems(PreUpdate, thirsty_scorer_system.in_set(BigBrainSet::Scorers)) -//! .run(); -//! } -//! ``` -//! //! ### bevy version and MSRV //! //! The current version of `big-brain` is compatible with `bevy` 0.12.1. @@ -180,6 +63,11 @@ pub mod measures; pub mod scorers; pub mod thinker; +//#[cfg(feature = "documentation")] +pub mod _topic; +//#[cfg(feature = "documentation")] +pub mod _tutorial; + pub mod prelude { /*! Convenience module with the core types you're most likely to use when working with Big Brain. Mean to be used like `use big_brain::prelude::*;`