├── .github └── FUNDING.yml ├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── README.md ├── examples └── select.rs ├── src ├── behavior.rs ├── lib.rs ├── state.rs └── status.rs └── tests ├── test_events.rs └── tests.rs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: bvssvni 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 8 | Cargo.lock 9 | 10 | # These are backup files generated by rustfmt 11 | **/*.rs.bk 12 | 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "piston-ai_behavior" 3 | version = "0.33.0" 4 | edition = "2018" 5 | authors = [ 6 | "bvssvni ", 7 | "Coeuvre " 8 | ] 9 | keywords = ["ai", "behavior", "piston", "game", "logic"] 10 | description = "AI behavior tree" 11 | license = "MIT" 12 | readme = "README.md" 13 | repository = "https://github.com/pistondevelopers/ai_behavior.git" 14 | homepage = "https://github.com/pistondevelopers/ai_behavior" 15 | autotests = false 16 | 17 | [lib] 18 | name = "ai_behavior" 19 | 20 | [dependencies] 21 | pistoncore-input = "1.0.0" 22 | serde_derive = "1.0" 23 | serde = "1.0" 24 | 25 | [[test]] 26 | name = "tests" 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 PistonDevelopers 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ai_behavior [![Build Status](https://travis-ci.org/PistonDevelopers/ai_behavior.svg?branch=master)](https://travis-ci.org/PistonDevelopers/ai_behavior) [![Docs](https://docs.rs/piston-ai_behavior/badge.svg)](https://docs.rs/piston-ai_behavior) 2 | =========== 3 | 4 | AI behavior tree 5 | 6 | You can serialize the 7 | behavior tree using [Serde](https://crates.io/crates/serde) and 8 | e.g. [Ron](https://crates.io/crates/ron). 9 | 10 | ### What is an AI behavior tree? 11 | 12 | An AI behavior tree is a kind of state machine logic for processes. 13 | 14 | Many things that a game logic does, e.g. controlling AI characters, 15 | fits the pattern of AI behavior trees. 16 | 17 | An AI behavior tree is a very generic way of organizing interactive logic. 18 | It has built-in semantics for processes that signals `Running`, `Success` or 19 | `Failure`. 20 | 21 | For example, if you have a state `A` and a state `B`: 22 | 23 | - Move from state `A` to state `B` if `A` succeeds: `Sequence([A, B])` 24 | - Try `A` first and then try `B` if `A` fails: `Select([A, B])` 25 | - Do `B` repeatedly while `A` runs: `While(A, [B])` 26 | - Do `A`, `B` forever: `While(WaitForever, [A, B])` 27 | - Wait for both `A` and `B` to complete: `WhenAll([A, B])` 28 | - Wait for either `A` or `B` to complete: `WhenAny([A, B])` 29 | 30 | See the `Behavior` enum for more information. 31 | 32 | ### Parallel semantics 33 | 34 | This library has parallel semantics for AI behavior trees. 35 | It means that multiple processes can happen at the same time 36 | and the logic can be constructed around how these processes runs or terminate. 37 | 38 | For example, `While(A, [B])` runs both `A` and `B` at the same time. 39 | If either `A` or `B` fails, then the whole while-behavior fails. 40 | 41 | A property of AI behavior trees with parallel semantics is that you can 42 | control termination conditions externally, as opposed to most 43 | programming languages where termination condition is controlled internally: 44 | 45 | ```text 46 | while A() { 47 | // This inner loop will never terminate unless `B` fails. 48 | while true { 49 | B(); // Runs `B` forever. 50 | } 51 | } 52 | ``` 53 | 54 | ```text 55 | // This will terminate if `A` stops running, which also stops `B`. 56 | WhenAny([A, 57 | While(WaitForever, [ 58 | B 59 | ]) 60 | ]) 61 | ``` 62 | 63 | [How to contribute](https://github.com/PistonDevelopers/piston/blob/master/CONTRIBUTING.md) 64 | -------------------------------------------------------------------------------- /examples/select.rs: -------------------------------------------------------------------------------- 1 | use ai_behavior::*; 2 | use input::{Event, UpdateArgs}; 3 | 4 | #[derive(Clone)] 5 | pub enum MyAction { 6 | A, 7 | B, 8 | } 9 | 10 | fn main() { 11 | let behavior = Select(vec![ 12 | Action(MyAction::A), 13 | Action(MyAction::B), 14 | ]); 15 | let mut state: State = State::new(behavior); 16 | let e: Event = UpdateArgs {dt: 1.0}.into(); 17 | 18 | // Prints `A`. 19 | state.event(&e, &mut |action_args| { 20 | match action_args.action { 21 | MyAction::A => println!("A"), 22 | MyAction::B => println!("B"), 23 | }; 24 | (Success, action_args.dt) 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /src/behavior.rs: -------------------------------------------------------------------------------- 1 | use input::Button; 2 | 3 | /// Describes a behavior. 4 | /// 5 | /// This is used for more complex event logic. 6 | /// Can also be used for game AI. 7 | #[derive(Clone, Deserialize, Serialize, PartialEq)] 8 | pub enum Behavior { 9 | /// Wait for a button to be pressed. 10 | /// 11 | /// Returns `Success` when the button is pressed, 12 | /// otherwise it returns `Running`. 13 | WaitForPressed(Button), 14 | /// Wait for a button to be released. 15 | /// 16 | /// Returns `Success` when the button is released, 17 | /// otherwise it returns `Running`. 18 | WaitForReleased(Button), 19 | /// Waits an amount of time before continuing. 20 | /// 21 | /// f64: Time in seconds 22 | Wait(f64), 23 | /// Wait forever. 24 | WaitForever, 25 | /// A high level description of an action. 26 | Action(A), 27 | /// Converts `Success` into `Failure` and vice versa. 28 | Fail(Box>), 29 | /// Ignores failures and returns `Success`. 30 | AlwaysSucceed(Box>), 31 | /// Runs behaviors one by one until a behavior succeeds. 32 | /// 33 | /// If a behavior fails it will try the next one. 34 | /// Fails if the last behavior fails. 35 | /// Can be thought of as a short-circuited logical OR gate. 36 | Select(Vec>), 37 | /// `If(condition, success, failure)` 38 | If(Box>, Box>, Box>), 39 | /// Runs behaviors one by one until all succeeded. 40 | /// 41 | /// The sequence fails if a behavior fails. 42 | /// The sequence succeeds if all the behavior succeeds. 43 | /// Can be thought of as a short-circuited logical AND gate. 44 | Sequence(Vec>), 45 | /// Loops while conditional behavior is running. 46 | /// 47 | /// Succeeds if the conditional behavior succeeds. 48 | /// Fails if the conditional behavior fails, 49 | /// or if any behavior in the loop body fails. 50 | While(Box>, Vec>), 51 | /// Runs all behaviors in parallel until all succeeded. 52 | /// 53 | /// Succeeds if all behaviors succeed. 54 | /// Fails is any behavior fails. 55 | WhenAll(Vec>), 56 | /// Runs all behaviors in parallel until one succeeds. 57 | /// 58 | /// Succeeds if one behavior succeeds. 59 | /// Fails if all behaviors failed. 60 | WhenAny(Vec>), 61 | /// Runs all behaviors in parallel until all succeeds in sequence. 62 | /// 63 | /// Succeeds if all behaviors succeed, but only if succeeding in sequence. 64 | /// Fails if one behavior fails. 65 | After(Vec>), 66 | } 67 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(missing_docs)] 2 | #![deny(missing_copy_implementations)] 3 | 4 | //! AI behavior tree 5 | //! 6 | //! You can serialize the 7 | //! behavior tree using [Serde](https://crates.io/crates/serde) and 8 | //! e.g. [Ron](https://crates.io/crates/ron). 9 | //! 10 | //! ### What is an AI behavior tree? 11 | //! 12 | //! An AI behavior tree is a kind of state machine logic for processes. 13 | //! 14 | //! Many things that a game logic does, e.g. controlling AI characters, 15 | //! fits the pattern of AI behavior trees. 16 | //! 17 | //! An AI behavior tree is a very generic way of organizing interactive logic. 18 | //! It has built-in semantics for processes that signals `Running`, `Success` or 19 | //! `Failure`. 20 | //! 21 | //! For example, if you have a state `A` and a state `B`: 22 | //! 23 | //! - Move from state `A` to state `B` if `A` succeeds: `Sequence([A, B])` 24 | //! - Try `A` first and then try `B` if `A` fails: `Select([A, B])` 25 | //! - Do `B` repeatedly while `A` runs: `While(A, [B])` 26 | //! - Do `A`, `B` forever: `While(WaitForever, [A, B])` 27 | //! - Wait for both `A` and `B` to complete: `WhenAll([A, B])` 28 | //! - Wait for either `A` or `B` to complete: `WhenAny([A, B])` 29 | //! 30 | //! See the `Behavior` enum for more information. 31 | //! 32 | //! ### Parallel semantics 33 | //! 34 | //! This library has parallel semantics for AI behavior trees. 35 | //! It means that multiple processes can happen at the same time 36 | //! and the logic can be constructed around how these processes runs or terminate. 37 | //! 38 | //! For example, `While(A, [B])` runs both `A` and `B` at the same time. 39 | //! If either `A` or `B` fails, then the whole while-behavior fails. 40 | //! 41 | //! A property of AI behavior trees with parallel semantics is that you can 42 | //! control termination conditions externally, as opposed to most 43 | //! programming languages where termination condition is controlled internally: 44 | //! 45 | //! ```text 46 | //! while A() { 47 | //! // This inner loop will never terminate unless `B` fails. 48 | //! while true { 49 | //! B(); // Runs `B` forever. 50 | //! } 51 | //! } 52 | //! ``` 53 | //! 54 | //! ```text 55 | //! // This will terminate if `A` stops running, which also stops `B`. 56 | //! WhenAny([A, 57 | //! While(WaitForever, [ 58 | //! B 59 | //! ]) 60 | //! ]) 61 | //! ``` 62 | 63 | extern crate input; 64 | #[macro_use] 65 | extern crate serde_derive; 66 | extern crate serde; 67 | 68 | pub use behavior::Behavior::{ 69 | self, Action, After, AlwaysSucceed, Fail, If, Select, Sequence, Wait, WaitForPressed, 70 | WaitForReleased, WaitForever, WhenAll, WhenAny, While, 71 | }; 72 | pub use state::{ActionArgs, State, RUNNING}; 73 | pub use status::Status::{self, Failure, Running, Success}; 74 | 75 | mod behavior; 76 | mod state; 77 | mod status; 78 | -------------------------------------------------------------------------------- /src/state.rs: -------------------------------------------------------------------------------- 1 | use std::f64; 2 | 3 | use crate::state::State::{ 4 | ActionState, AfterState, AlwaysSucceedState, FailState, IfState, SelectState, SequenceState, 5 | WaitForPressedState, WaitForReleasedState, WaitForeverState, WaitState, WhenAllState, 6 | WhenAnyState, WhileState, 7 | }; 8 | use crate::{ 9 | Action, After, AlwaysSucceed, Behavior, Fail, Failure, If, Running, Select, Sequence, Status, 10 | Success, Wait, WaitForPressed, WaitForReleased, WaitForever, WhenAll, WhenAny, While, 11 | }; 12 | use input::{GenericEvent, UpdateEvent}; 13 | 14 | /// The action is still running. 15 | pub const RUNNING: (Status, f64) = (Running, 0.0); 16 | 17 | /// The arguments in the action callback. 18 | pub struct ActionArgs<'a, E: 'a, A: 'a, S: 'a> { 19 | /// The event. 20 | pub event: &'a E, 21 | /// The remaining delta time. 22 | pub dt: f64, 23 | /// The action running. 24 | pub action: &'a A, 25 | /// The state of the running action, if any. 26 | pub state: &'a mut Option, 27 | } 28 | 29 | /// Keeps track of a behavior. 30 | #[derive(Clone, Deserialize, Serialize, PartialEq)] 31 | pub enum State { 32 | /// Returns `Success` when button is pressed. 33 | WaitForPressedState(input::Button), 34 | /// Returns `Success` when button is released. 35 | WaitForReleasedState(input::Button), 36 | /// Executes an action. 37 | ActionState(A, Option), 38 | /// Converts `Success` into `Failure` and vice versa. 39 | FailState(Box>), 40 | /// Ignores failures and always return `Success`. 41 | AlwaysSucceedState(Box>), 42 | /// Keeps track of waiting for a period of time before continuing. 43 | /// 44 | /// f64: Total time in seconds to wait 45 | /// 46 | /// f64: Time elapsed in seconds 47 | WaitState(f64, f64), 48 | /// Waits forever. 49 | WaitForeverState, 50 | /// Keeps track of an `If` behavior. 51 | /// If status is `Running`, then it evaluates the condition. 52 | /// If status is `Success`, then it evaluates the success behavior. 53 | /// If status is `Failure`, then it evaluates the failure behavior. 54 | IfState(Box>, Box>, Status, Box>), 55 | /// Keeps track of a `Select` behavior. 56 | SelectState(Vec>, usize, Box>), 57 | /// Keeps track of an `Sequence` behavior. 58 | SequenceState(Vec>, usize, Box>), 59 | /// Keeps track of a `While` behavior. 60 | WhileState(Box>, Vec>, usize, Box>), 61 | /// Keeps track of a `WhenAll` behavior. 62 | WhenAllState(Vec>>), 63 | /// Keeps track of a `WhenAny` behavior. 64 | WhenAnyState(Vec>>), 65 | /// Keeps track of an `After` behavior. 66 | AfterState(usize, Vec>), 67 | } 68 | 69 | // `Sequence` and `Select` share same algorithm. 70 | // 71 | // `Sequence` fails if any fails and succeeds when all succeeds. 72 | // `Select` succeeds if any succeeds and fails when all fails. 73 | fn sequence( 74 | select: bool, 75 | upd: Option, 76 | seq: &[Behavior], 77 | i: &mut usize, 78 | cursor: &mut Box>, 79 | e: &E, 80 | f: &mut F, 81 | ) -> (Status, f64) 82 | where 83 | A: Clone, 84 | E: GenericEvent, 85 | F: FnMut(ActionArgs) -> (Status, f64), 86 | { 87 | let (status, inv_status) = if select { 88 | // `Select` 89 | (Failure, Success) 90 | } else { 91 | // `Sequence` 92 | (Success, Failure) 93 | }; 94 | let mut remaining_dt = upd.unwrap_or(0.0); 95 | let mut remaining_e; 96 | while *i < seq.len() { 97 | match cursor.event( 98 | match upd { 99 | Some(_) => { 100 | remaining_e = UpdateEvent::from_dt(remaining_dt, e).unwrap(); 101 | &remaining_e 102 | } 103 | _ => e, 104 | }, 105 | f, 106 | ) { 107 | (Running, _) => { 108 | break; 109 | } 110 | (s, new_dt) if s == inv_status => { 111 | return (inv_status, new_dt); 112 | } 113 | (s, new_dt) if s == status => { 114 | remaining_dt = match upd { 115 | // Change update event with remaining delta time. 116 | Some(_) => new_dt, 117 | // Other events are 'consumed' and not passed to next. 118 | // If this is the last event, then the sequence succeeded. 119 | _ => { 120 | if *i == seq.len() - 1 { 121 | return (status, new_dt); 122 | } else { 123 | *i += 1; 124 | // Create a new cursor for next event. 125 | // Use the same pointer to avoid allocation. 126 | **cursor = State::new(seq[*i].clone()); 127 | return RUNNING; 128 | } 129 | } 130 | } 131 | } 132 | _ => unreachable!(), 133 | }; 134 | *i += 1; 135 | // If end of sequence, 136 | // return the 'dt' that is left. 137 | if *i >= seq.len() { 138 | return (status, remaining_dt); 139 | } 140 | // Create a new cursor for next event. 141 | // Use the same pointer to avoid allocation. 142 | **cursor = State::new(seq[*i].clone()); 143 | } 144 | RUNNING 145 | } 146 | 147 | // `WhenAll` and `WhenAny` share same algorithm. 148 | // 149 | // `WhenAll` fails if any fails and succeeds when all succeeds. 150 | // `WhenAny` succeeds if any succeeds and fails when all fails. 151 | fn when_all( 152 | any: bool, 153 | upd: Option, 154 | cursors: &mut Vec>>, 155 | e: &E, 156 | f: &mut F, 157 | ) -> (Status, f64) 158 | where 159 | A: Clone, 160 | E: GenericEvent, 161 | F: FnMut(ActionArgs) -> (Status, f64), 162 | { 163 | let (status, inv_status) = if any { 164 | // `WhenAny` 165 | (Failure, Success) 166 | } else { 167 | // `WhenAll` 168 | (Success, Failure) 169 | }; 170 | // Get the least delta time left over. 171 | let mut min_dt = f64::MAX; 172 | // Count number of terminated events. 173 | let mut terminated = 0; 174 | for cur in cursors.iter_mut() { 175 | match *cur { 176 | None => {} 177 | Some(ref mut cur) => { 178 | match cur.event(e, f) { 179 | (Running, _) => { 180 | continue; 181 | } 182 | (s, new_dt) if s == inv_status => { 183 | // Fail for `WhenAll`. 184 | // Succeed for `WhenAny`. 185 | return (inv_status, new_dt); 186 | } 187 | (s, new_dt) if s == status => { 188 | min_dt = min_dt.min(new_dt); 189 | } 190 | _ => unreachable!(), 191 | } 192 | } 193 | } 194 | 195 | terminated += 1; 196 | *cur = None; 197 | } 198 | match terminated { 199 | // If there are no events, there is a whole 'dt' left. 200 | 0 if cursors.is_empty() => ( 201 | status, 202 | match upd { 203 | Some(dt) => dt, 204 | // Other kind of events happen instantly. 205 | _ => 0.0, 206 | }, 207 | ), 208 | // If all events terminated, the least delta time is left. 209 | n if cursors.len() == n => (status, min_dt), 210 | _ => RUNNING, 211 | } 212 | } 213 | 214 | impl State { 215 | /// Creates a state from a behavior. 216 | pub fn new(behavior: Behavior) -> Self { 217 | match behavior { 218 | WaitForPressed(button) => WaitForPressedState(button), 219 | WaitForReleased(button) => WaitForReleasedState(button), 220 | Action(action) => ActionState(action, None), 221 | Fail(ev) => FailState(Box::new(State::new(*ev))), 222 | AlwaysSucceed(ev) => AlwaysSucceedState(Box::new(State::new(*ev))), 223 | Wait(dt) => WaitState(dt, 0.0), 224 | WaitForever => WaitForeverState, 225 | If(condition, success, failure) => { 226 | let state = State::new(*condition); 227 | IfState(success, failure, Running, Box::new(state)) 228 | } 229 | Select(sel) => { 230 | let state = State::new(sel[0].clone()); 231 | SelectState(sel, 0, Box::new(state)) 232 | } 233 | Sequence(seq) => { 234 | let state = State::new(seq[0].clone()); 235 | SequenceState(seq, 0, Box::new(state)) 236 | } 237 | While(ev, rep) => { 238 | let state = State::new(rep[0].clone()); 239 | WhileState(Box::new(State::new(*ev)), rep, 0, Box::new(state)) 240 | } 241 | WhenAll(all) => WhenAllState(all.into_iter().map(|ev| Some(State::new(ev))).collect()), 242 | WhenAny(all) => WhenAnyState(all.into_iter().map(|ev| Some(State::new(ev))).collect()), 243 | After(seq) => AfterState(0, seq.into_iter().map(State::new).collect()), 244 | } 245 | } 246 | 247 | /// Updates the cursor that tracks an event. 248 | /// 249 | /// The action need to return status and remaining delta time. 250 | /// Returns status and the remaining delta time. 251 | /// 252 | /// Passes event, delta time in seconds, action and state to closure. 253 | /// The closure should return a status and remaining delta time. 254 | pub fn event(&mut self, e: &E, f: &mut F) -> (Status, f64) 255 | where 256 | E: GenericEvent, 257 | F: FnMut(ActionArgs) -> (Status, f64), 258 | { 259 | let upd = e.update(|args| Some(args.dt)).unwrap_or(None); 260 | match (upd, self) { 261 | (None, &mut WaitForPressedState(button)) => { 262 | e.press(|button_pressed| { 263 | if button_pressed != button { 264 | return RUNNING; 265 | } 266 | 267 | // Button press is considered to happen instantly. 268 | // There is no remaining delta time because 269 | // this is input event. 270 | (Success, 0.0) 271 | }) 272 | .unwrap_or(RUNNING) 273 | } 274 | (None, &mut WaitForReleasedState(button)) => { 275 | e.release(|button_released| { 276 | if button_released != button { 277 | return RUNNING; 278 | } 279 | 280 | // Button release is considered to happen instantly. 281 | // There is no remaining delta time because 282 | // this is input event. 283 | (Success, 0.0) 284 | }) 285 | .unwrap_or(RUNNING) 286 | } 287 | (_, &mut ActionState(ref action, ref mut state)) => { 288 | // Execute action. 289 | f(ActionArgs { 290 | event: e, 291 | dt: upd.unwrap_or(0.0), 292 | action, 293 | state, 294 | }) 295 | } 296 | (_, &mut FailState(ref mut cur)) => match cur.event(e, f) { 297 | (Running, dt) => (Running, dt), 298 | (Failure, dt) => (Success, dt), 299 | (Success, dt) => (Failure, dt), 300 | }, 301 | (_, &mut AlwaysSucceedState(ref mut cur)) => match cur.event(e, f) { 302 | (Running, dt) => (Running, dt), 303 | (_, dt) => (Success, dt), 304 | }, 305 | (Some(dt), &mut WaitState(wait_t, ref mut t)) => { 306 | if *t + dt >= wait_t { 307 | let remaining_dt = *t + dt - wait_t; 308 | *t = wait_t; 309 | (Success, remaining_dt) 310 | } else { 311 | *t += dt; 312 | RUNNING 313 | } 314 | } 315 | (_, &mut IfState(ref success, ref failure, ref mut status, ref mut state)) => { 316 | let mut remaining_dt = upd.unwrap_or(0.0); 317 | let remaining_e; 318 | // Run in a loop to evaluate success or failure with 319 | // remaining delta time after condition. 320 | loop { 321 | *status = match *status { 322 | Running => match state.event(e, f) { 323 | (Running, dt) => { 324 | return (Running, dt); 325 | } 326 | (Success, dt) => { 327 | **state = State::new((**success).clone()); 328 | remaining_dt = dt; 329 | Success 330 | } 331 | (Failure, dt) => { 332 | **state = State::new((**failure).clone()); 333 | remaining_dt = dt; 334 | Failure 335 | } 336 | }, 337 | _ => { 338 | return state.event( 339 | match upd { 340 | Some(_) => { 341 | remaining_e = 342 | UpdateEvent::from_dt(remaining_dt, e).unwrap(); 343 | &remaining_e 344 | } 345 | _ => e, 346 | }, 347 | f, 348 | ); 349 | } 350 | } 351 | } 352 | } 353 | (_, &mut SelectState(ref seq, ref mut i, ref mut cursor)) => { 354 | let select = true; 355 | sequence(select, upd, seq, i, cursor, e, f) 356 | } 357 | (_, &mut SequenceState(ref seq, ref mut i, ref mut cursor)) => { 358 | let select = false; 359 | sequence(select, upd, seq, i, cursor, e, f) 360 | } 361 | (_, &mut WhileState(ref mut ev_cursor, ref rep, ref mut i, ref mut cursor)) => { 362 | // If the event terminates, do not execute the loop. 363 | match ev_cursor.event(e, f) { 364 | (Running, _) => {} 365 | x => return x, 366 | }; 367 | let cur = cursor; 368 | let mut remaining_dt = upd.unwrap_or(0.0); 369 | let mut remaining_e; 370 | loop { 371 | match cur.event( 372 | match upd { 373 | Some(_) => { 374 | remaining_e = UpdateEvent::from_dt(remaining_dt, e).unwrap(); 375 | &remaining_e 376 | } 377 | _ => e, 378 | }, 379 | f, 380 | ) { 381 | (Failure, x) => return (Failure, x), 382 | (Running, _) => break, 383 | (Success, new_dt) => { 384 | remaining_dt = match upd { 385 | // Change update event with remaining delta time. 386 | Some(_) => new_dt, 387 | // Other events are 'consumed' and not passed to next. 388 | _ => return RUNNING, 389 | } 390 | } 391 | }; 392 | *i += 1; 393 | // If end of repeated events, 394 | // start over from the first one. 395 | if *i >= rep.len() { 396 | *i = 0; 397 | } 398 | // Create a new cursor for next event. 399 | // Use the same pointer to avoid allocation. 400 | **cur = State::new(rep[*i].clone()); 401 | } 402 | RUNNING 403 | } 404 | (_, &mut WhenAllState(ref mut cursors)) => { 405 | let any = false; 406 | when_all(any, upd, cursors, e, f) 407 | } 408 | (_, &mut WhenAnyState(ref mut cursors)) => { 409 | let any = true; 410 | when_all(any, upd, cursors, e, f) 411 | } 412 | (_, &mut AfterState(ref mut i, ref mut cursors)) => { 413 | // Get the least delta time left over. 414 | let mut min_dt = f64::MAX; 415 | for j in *i..cursors.len() { 416 | match cursors[j].event(e, f) { 417 | (Running, _) => { 418 | min_dt = 0.0; 419 | } 420 | (Success, new_dt) => { 421 | // Remaining delta time must be less to succeed. 422 | if *i == j && new_dt < min_dt { 423 | *i += 1; 424 | min_dt = new_dt; 425 | } else { 426 | // Return least delta time because 427 | // that is when failure is detected. 428 | return (Failure, min_dt.min(new_dt)); 429 | } 430 | } 431 | (Failure, new_dt) => { 432 | return (Failure, new_dt); 433 | } 434 | }; 435 | } 436 | if *i == cursors.len() { 437 | (Success, min_dt) 438 | } else { 439 | RUNNING 440 | } 441 | } 442 | _ => RUNNING, 443 | } 444 | } 445 | } 446 | -------------------------------------------------------------------------------- /src/status.rs: -------------------------------------------------------------------------------- 1 | /// The result of a behavior or action. 2 | #[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Eq, Debug)] 3 | pub enum Status { 4 | /// The behavior or action succeeded. 5 | Success, 6 | /// The behavior or action failed. 7 | Failure, 8 | /// The behavior or action is still running. 9 | Running, 10 | } 11 | -------------------------------------------------------------------------------- /tests/test_events.rs: -------------------------------------------------------------------------------- 1 | use ai_behavior::{Action, Sequence, State, Success, Wait, WaitForever, WhenAll, While}; 2 | use input::{Event, UpdateArgs}; 3 | 4 | use crate::test_events::TestActions::{Dec, Inc}; 5 | 6 | /// Some test actions. 7 | #[derive(Clone)] 8 | #[allow(dead_code)] 9 | pub enum TestActions { 10 | /// Increment accumulator. 11 | Inc, 12 | /// Decrement accumulator. 13 | Dec, 14 | } 15 | 16 | // A test state machine that can increment and decrement. 17 | fn exec(mut acc: u32, dt: f64, state: &mut State) -> u32 { 18 | let e: Event = UpdateArgs { dt }.into(); 19 | state.event(&e, &mut |args| match *args.action { 20 | Inc => { 21 | acc += 1; 22 | (Success, args.dt) 23 | } 24 | Dec => { 25 | acc -= 1; 26 | (Success, args.dt) 27 | } 28 | }); 29 | acc 30 | } 31 | 32 | // Each action that terminates immediately 33 | // consumes a time of 0.0 seconds. 34 | // This makes it possible to execute one action 35 | // after another without delay or waiting for next update. 36 | #[test] 37 | fn print_2() { 38 | let a: u32 = 0; 39 | let seq = Sequence(vec![Action(Inc), Action(Inc)]); 40 | let mut state = State::new(seq); 41 | let a = exec(a, 0.0, &mut state); 42 | assert_eq!(a, 2); 43 | } 44 | 45 | // If you wait the exact amount before to execute an action, 46 | // it will execute. This behavior makes it easy to predict 47 | // when an action will run. 48 | #[test] 49 | fn wait_sec() { 50 | let a: u32 = 0; 51 | let seq = Sequence(vec![Wait(1.0), Action(Inc)]); 52 | let mut state = State::new(seq); 53 | let a = exec(a, 1.0, &mut state); 54 | assert_eq!(a, 1); 55 | } 56 | 57 | // When we execute half the time and then the other half, 58 | // then the action should be executed. 59 | #[test] 60 | fn wait_half_sec() { 61 | let a: u32 = 0; 62 | let seq = Sequence(vec![Wait(1.0), Action(Inc)]); 63 | let mut state = State::new(seq); 64 | let a = exec(a, 0.5, &mut state); 65 | assert_eq!(a, 0); 66 | let a = exec(a, 0.5, &mut state); 67 | assert_eq!(a, 1); 68 | } 69 | 70 | // A sequence of one event is like a bare event. 71 | #[test] 72 | fn sequence_of_one_event() { 73 | let a: u32 = 0; 74 | let seq = Sequence(vec![Action(Inc)]); 75 | let mut state = State::new(seq); 76 | let a = exec(a, 1.0, &mut state); 77 | assert_eq!(a, 1); 78 | } 79 | 80 | // A sequence of wait events is the same as one wait event. 81 | #[test] 82 | fn wait_two_waits() { 83 | let a: u32 = 0; 84 | let seq = Sequence(vec![Wait(0.5), Wait(0.5), Action(Inc)]); 85 | let mut state = State::new(seq); 86 | let a = exec(a, 1.0, &mut state); 87 | assert_eq!(a, 1); 88 | } 89 | 90 | // Increase counter ten times. 91 | #[test] 92 | fn loop_ten_times() { 93 | let a: u32 = 0; 94 | let rep = While( 95 | Box::new(Wait(50.0)), 96 | vec![Wait(0.5), Action(Inc), Wait(0.5)], 97 | ); 98 | let mut state = State::new(rep); 99 | let a = exec(a, 10.0, &mut state); 100 | assert_eq!(a, 10); 101 | } 102 | 103 | #[test] 104 | fn when_all_wait() { 105 | let a: u32 = 0; 106 | let all = Sequence(vec![ 107 | // Wait in parallel. 108 | WhenAll(vec![Wait(0.5), Wait(1.0)]), 109 | Action(Inc), 110 | ]); 111 | let mut state = State::new(all); 112 | let a = exec(a, 0.5, &mut state); 113 | assert_eq!(a, 0); 114 | let a = exec(a, 0.5, &mut state); 115 | assert_eq!(a, 1); 116 | } 117 | 118 | #[test] 119 | fn while_wait_sequence() { 120 | let mut a: u32 = 0; 121 | let w = While( 122 | Box::new(Wait(9.999999)), 123 | vec![Sequence(vec![ 124 | Wait(0.5), 125 | Action(Inc), 126 | Wait(0.5), 127 | Action(Inc), 128 | ])], 129 | ); 130 | let mut state = State::new(w); 131 | for _ in 0..100 { 132 | a = exec(a, 0.1, &mut state); 133 | } 134 | // The last increment is never executed, because there is not enough time. 135 | assert_eq!(a, 19); 136 | } 137 | 138 | #[test] 139 | fn while_wait_forever_sequence() { 140 | let mut a: u32 = 0; 141 | let w = While( 142 | Box::new(WaitForever), 143 | vec![Sequence(vec![Action(Inc), Wait(1.0)])], 144 | ); 145 | let mut state = State::new(w); 146 | a = exec(a, 1.001, &mut state); 147 | assert_eq!(a, 2); 148 | } 149 | -------------------------------------------------------------------------------- /tests/tests.rs: -------------------------------------------------------------------------------- 1 | extern crate ai_behavior; 2 | extern crate input; 3 | 4 | mod test_events; 5 | --------------------------------------------------------------------------------