diff --git a/bonsai/Cargo.toml b/bonsai/Cargo.toml index 4498b53..9203bbc 100644 --- a/bonsai/Cargo.toml +++ b/bonsai/Cargo.toml @@ -24,6 +24,7 @@ serde = { version = "1.0.137", features = ["derive"], optional = true } [features] visualize = ["dep:petgraph"] +f32 = [] [dev-dependencies] serde_json = { version = "1.0.81" } diff --git a/bonsai/src/behavior.rs b/bonsai/src/behavior.rs index 2b7882a..783fbe4 100644 --- a/bonsai/src/behavior.rs +++ b/bonsai/src/behavior.rs @@ -1,6 +1,8 @@ #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +use crate::Float; + /// Describes a behavior. /// /// This is used for more complex event logic. @@ -10,8 +12,8 @@ use serde::{Deserialize, Serialize}; pub enum Behavior { /// Waits an amount of time before continuing /// - /// f64: Time in seconds - Wait(f64), + /// Float: Time in seconds + Wait(Float), /// Wait forever. WaitForever, /// A high level description of an action. @@ -131,20 +133,23 @@ pub enum Behavior { #[cfg(test)] #[cfg(feature = "serde")] mod tests { - use crate::Behavior::{self, Action, Sequence, Wait, WaitForever, WhenAny, While}; + use crate::{ + Behavior::{self, Action, Sequence, Wait, WaitForever, WhenAny, While}, + Float, + }; #[derive(serde::Deserialize, serde::Serialize, Clone, Debug)] pub(crate) enum EnemyAction { /// Circles forever around target pos. Circling, /// Waits until player is within distance. - PlayerWithinDistance(f64), + PlayerWithinDistance(Float), /// Fly toward player. FlyTowardPlayer, /// Waits until player is far away from target. - PlayerFarAwayFromTarget(f64), + PlayerFarAwayFromTarget(Float), /// Makes player loose more blood. - AttackPlayer(f64), + AttackPlayer(Float), } #[test] diff --git a/bonsai/src/bt.rs b/bonsai/src/bt.rs index cd17b51..cc727f4 100644 --- a/bonsai/src/bt.rs +++ b/bonsai/src/bt.rs @@ -1,6 +1,6 @@ use std::fmt::Debug; -use crate::{state::State, ActionArgs, Behavior, Status, UpdateEvent}; +use crate::{state::State, ActionArgs, Behavior, Float, Status, UpdateEvent}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -45,15 +45,15 @@ impl BT { /// Passes event, delta time in seconds, action and state to closure. /// The closure should return a status and remaining delta time. /// - /// return: (Status, f64) + /// return: (Status, Float) /// function returns the result of the tree traversal, and how long /// it actually took to complete the traversal and propagate the /// results back up to the root node #[inline] - pub fn tick(&mut self, e: &E, f: &mut F) -> Option<(Status, f64)> + pub fn tick(&mut self, e: &E, f: &mut F) -> Option<(Status, Float)> where E: UpdateEvent, - F: FnMut(ActionArgs, &mut B) -> (Status, f64), + F: FnMut(ActionArgs, &mut B) -> (Status, Float), { if self.finished { return None; diff --git a/bonsai/src/event.rs b/bonsai/src/event.rs index 54d0c9d..c3c0530 100644 --- a/bonsai/src/event.rs +++ b/bonsai/src/event.rs @@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize}; #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct UpdateArgs { /// Delta time in seconds. - pub dt: f64, + pub dt: Float, } impl UpdateArgs { @@ -54,7 +54,7 @@ pub trait UpdateEvent: Sized { /// Creates an update event. fn from_update_args(args: &UpdateArgs, old_event: &Self) -> Option; /// Creates an update event with delta time. - fn from_dt(dt: f64, old_event: &Self) -> Option { + fn from_dt(dt: Float, old_event: &Self) -> Option { UpdateEvent::from_update_args(&UpdateArgs { dt }, old_event) } /// Calls closure if this is an update event. @@ -84,6 +84,8 @@ impl UpdateEvent for Event { use std::time::Instant; +use crate::Float; + /// A monotonic clock/timer that can be used to keep track /// of the time increments (delta time) between tick/tree traversals /// and the total duration since the behavior tree was first invoked/traversed @@ -101,18 +103,24 @@ impl Timer { } /// Compute duration since timer started - pub fn duration_since_start(&self) -> f64 { + pub fn duration_since_start(&self) -> Float { let new_now: Instant = Instant::now(); let duration = new_now.duration_since(self.start); - duration.as_secs_f64() + #[cfg(feature = "f32")] + return duration.as_secs_f32(); + #[cfg(not(feature = "f32"))] + return duration.as_secs_f64(); } /// Compute time difference last invocation of `get_dt()` function - pub fn get_dt(&mut self) -> f64 { + pub fn get_dt(&mut self) -> Float { let new_now: Instant = Instant::now(); let duration = new_now.duration_since(self.now); self.now = new_now; - duration.as_secs_f64() + #[cfg(feature = "f32")] + return duration.as_secs_f32(); + #[cfg(not(feature = "f32"))] + return duration.as_secs_f64(); } } diff --git a/bonsai/src/lib.rs b/bonsai/src/lib.rs index a8f7b57..9defa7b 100644 --- a/bonsai/src/lib.rs +++ b/bonsai/src/lib.rs @@ -137,3 +137,9 @@ mod when_all; #[cfg(feature = "visualize")] mod visualizer; + +#[cfg(feature = "f32")] +pub type Float = f32; + +#[cfg(not(feature = "f32"))] +pub type Float = f64; diff --git a/bonsai/src/sequence.rs b/bonsai/src/sequence.rs index 15e3139..c0fc143 100644 --- a/bonsai/src/sequence.rs +++ b/bonsai/src/sequence.rs @@ -1,9 +1,10 @@ use crate::status::Status::*; +use crate::Float; use crate::{event::UpdateEvent, state::State, ActionArgs, Behavior, Status, RUNNING}; pub struct SequenceArgs<'a, A, E, F, B> { pub select: bool, - pub upd: Option, + pub upd: Option, pub seq: &'a [Behavior], pub i: &'a mut usize, pub cursor: &'a mut Box>, @@ -16,11 +17,11 @@ pub struct SequenceArgs<'a, A, E, F, B> { // // `Sequence` fails if any fails and succeeds when all succeeds. // `Select` succeeds if any succeeds and fails when all fails. -pub fn sequence(args: SequenceArgs) -> (Status, f64) +pub fn sequence(args: SequenceArgs) -> (Status, Float) where A: Clone, E: UpdateEvent, - F: FnMut(ActionArgs, &mut B) -> (Status, f64), + F: FnMut(ActionArgs, &mut B) -> (Status, Float), { let SequenceArgs { select, diff --git a/bonsai/src/state.rs b/bonsai/src/state.rs index 73064a7..2c7365f 100644 --- a/bonsai/src/state.rs +++ b/bonsai/src/state.rs @@ -3,7 +3,7 @@ use crate::sequence::{sequence, SequenceArgs}; use crate::state::State::*; use crate::status::Status::*; use crate::when_all::when_all; -use crate::{Behavior, Status}; +use crate::{Behavior, Float, Status}; use std::fmt::Debug; #[cfg(feature = "serde")] @@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize}; /// The action is still running, and thus the action consumes /// all the remaining delta time for the tick -pub const RUNNING: (Status, f64) = (Running, 0.0); +pub const RUNNING: (Status, Float) = (Running, 0.0); /// The arguments in the action callback. pub struct ActionArgs<'a, E: 'a, A: 'a> { @@ -20,7 +20,7 @@ pub struct ActionArgs<'a, E: 'a, A: 'a> { /// The remaining delta time. When one action terminates, /// it can consume some of dt and the remaining is passed /// onto the next action. - pub dt: f64, + pub dt: Float, /// The action running. pub action: &'a A, } @@ -36,7 +36,7 @@ pub(crate) enum State { /// Ignores failures and always return `Success`. AlwaysSucceed(Box>), /// Keeps track of waiting for a period of time before continuing. - Wait { time_to_wait: f64, elapsed_time: f64 }, + Wait { time_to_wait: Float, elapsed_time: Float }, /// Waits forever. WaitForever, /// Keeps track of an `If` behavior. @@ -196,14 +196,14 @@ impl State { /// Passes event, delta time in seconds, action and state to closure. /// The closure should return a status and remaining delta time. /// - /// return: (Status, f64) + /// return: (Status, Float) /// function returns the result of the tree traversal, and how long /// it actually took to complete the traversal and propagate the /// results back up to the root node - pub fn tick(&mut self, e: &E, blackboard: &mut B, f: &mut F) -> (Status, f64) + pub fn tick(&mut self, e: &E, blackboard: &mut B, f: &mut F) -> (Status, Float) where E: UpdateEvent, - F: FnMut(ActionArgs, &mut B) -> (Status, f64), + F: FnMut(ActionArgs, &mut B) -> (Status, Float), { let upd = e.update(|args| Some(args.dt)).unwrap_or(None); @@ -413,7 +413,7 @@ impl State { ) => { // println!("In AfterState: {}", next_success_index); // Get the least delta time left over. - let mut min_dt = f64::MAX; + let mut min_dt = Float::MAX; for (j, item) in states.iter_mut().enumerate().skip(*next_success_index) { match item.tick(e, blackboard, f) { (Running, _) => { diff --git a/bonsai/src/visualizer.rs b/bonsai/src/visualizer.rs index 63def0e..1b601c4 100644 --- a/bonsai/src/visualizer.rs +++ b/bonsai/src/visualizer.rs @@ -1,12 +1,12 @@ #![allow(dead_code, unused_imports, unused_variables)] -use crate::{state::State, Behavior, Select, Sequence, BT}; +use crate::{state::State, Behavior, Float, Select, Sequence, BT}; use petgraph::{graph::Graph, stable_graph::NodeIndex, Direction::Outgoing}; use std::{collections::VecDeque, fmt::Debug}; #[derive(Debug, Clone)] pub(crate) enum NodeType { Root, - Wait(f64), + Wait(Float), WaitForever, Action(A), Invert, @@ -152,7 +152,7 @@ mod tests { } // A test state machine that can increment and decrement. - fn tick(mut acc: i32, dt: f64, bt: &mut BT>) -> (i32, Status, f64) { + fn tick(mut acc: i32, dt: Float, bt: &mut BT>) -> (i32, Status, Float) { let e: Event = UpdateArgs { dt }.into(); let (s, t) = bt .tick(&e, &mut |args, blackboard| match args.action { diff --git a/bonsai/src/when_all.rs b/bonsai/src/when_all.rs index 8a1df76..29503b1 100644 --- a/bonsai/src/when_all.rs +++ b/bonsai/src/when_all.rs @@ -1,4 +1,5 @@ use crate::status::Status::*; +use crate::Float; use crate::{event::UpdateEvent, state::State, ActionArgs, Status, RUNNING}; // `WhenAll` and `WhenAny` share same algorithm. @@ -8,16 +9,16 @@ use crate::{event::UpdateEvent, state::State, ActionArgs, Status, RUNNING}; #[rustfmt::skip] pub fn when_all( any: bool, - upd: Option, + upd: Option, cursors: &mut [Option>], e: &E, f: &mut F, blackboard: &mut B, -) -> (Status, f64) +) -> (Status, Float) where A: Clone, E: UpdateEvent, - F: FnMut(ActionArgs, &mut B) -> (Status, f64), + F: FnMut(ActionArgs, &mut B) -> (Status, Float), { let (status, inv_status) = if any { // `WhenAny` @@ -27,7 +28,7 @@ where (Status::Success, Status::Failure) }; // Get the least delta time left over. - let mut min_dt = f64::MAX; + let mut min_dt = Float::MAX; // Count number of terminated events. let mut terminated = 0; for cur in cursors.iter_mut() { diff --git a/bonsai/tests/behavior_tests.rs b/bonsai/tests/behavior_tests.rs index bfaa03b..fbbe47c 100644 --- a/bonsai/tests/behavior_tests.rs +++ b/bonsai/tests/behavior_tests.rs @@ -1,7 +1,7 @@ use crate::behavior_tests::TestActions::{Dec, Inc, LessThan, LessThanRunningSuccess}; use bonsai_bt::{ - Action, ActionArgs, After, AlwaysSucceed, Event, Failure, If, Invert, Select, Sequence, Status::Running, Success, - UpdateArgs, Wait, WaitForever, WhenAll, While, WhileAll, BT, + Action, ActionArgs, After, AlwaysSucceed, Event, Failure, Float, If, Invert, Select, Sequence, Status::Running, + Success, UpdateArgs, Wait, WaitForever, WhenAll, While, WhileAll, BT, }; /// Some test actions. @@ -18,7 +18,7 @@ enum TestActions { } // A test state machine that can increment and decrement. -fn tick(mut acc: i32, dt: f64, state: &mut BT) -> (i32, bonsai_bt::Status, f64) { +fn tick(mut acc: i32, dt: Float, state: &mut BT) -> (i32, bonsai_bt::Status, Float) { let e: Event = UpdateArgs { dt }.into(); println!("acc {}", acc); let (s, t) = state @@ -59,7 +59,7 @@ fn tick(mut acc: i32, dt: f64, state: &mut BT) -> (i32, bonsai_ } // A test state machine that can increment and decrement. -fn tick_with_ref(acc: &mut i32, dt: f64, state: &mut BT) { +fn tick_with_ref(acc: &mut i32, dt: Float, state: &mut BT) { let e: Event = UpdateArgs { dt }.into(); state diff --git a/bonsai/tests/blackboard_tests.rs b/bonsai/tests/blackboard_tests.rs index 558dc22..a1abd9d 100644 --- a/bonsai/tests/blackboard_tests.rs +++ b/bonsai/tests/blackboard_tests.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use bonsai_bt::{Action, Event, Sequence, Success, UpdateArgs, Wait, BT}; +use bonsai_bt::{Action, Event, Float, Sequence, Success, UpdateArgs, Wait, BT}; use crate::blackboard_tests::TestActions::{Dec, Inc}; @@ -14,7 +14,7 @@ pub enum TestActions { } // A test state machine that can increment and decrement. -fn tick(mut acc: i32, dt: f64, bt: &mut BT>) -> i32 { +fn tick(mut acc: i32, dt: Float, bt: &mut BT>) -> i32 { let e: Event = UpdateArgs { dt }.into(); let (_s, _t) = bt diff --git a/bonsai/tests/bt_tests.rs b/bonsai/tests/bt_tests.rs index 4b96552..50ff582 100644 --- a/bonsai/tests/bt_tests.rs +++ b/bonsai/tests/bt_tests.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use crate::bt_tests::TestActions::{Dec, Inc, LessThan}; -use bonsai_bt::{Action, Behavior::Select, Event, Failure, Success, UpdateArgs, BT}; +use bonsai_bt::{Action, Behavior::Select, Event, Failure, Float, Success, UpdateArgs, BT}; /// Some test actions. #[derive(Clone, Debug)] @@ -15,7 +15,7 @@ enum TestActions { } // A test state machine that can increment and decrement. -fn tick(mut acc: i32, dt: f64, bt: &mut BT>) -> (i32, bonsai_bt::Status, f64) { +fn tick(mut acc: i32, dt: Float, bt: &mut BT>) -> (i32, bonsai_bt::Status, Float) { let e: Event = UpdateArgs { dt }.into(); println!("acc {}", acc); let (s, t) = bt diff --git a/bonsai/tests/dynamic_behavior_tests.rs b/bonsai/tests/dynamic_behavior_tests.rs index 4ae1df4..19d43db 100644 --- a/bonsai/tests/dynamic_behavior_tests.rs +++ b/bonsai/tests/dynamic_behavior_tests.rs @@ -1,7 +1,7 @@ use crate::dynamic_behavior_tests::TestActions::{DynamicWait, Inc}; -use bonsai_bt::{Action, ActionArgs, Event, Success, UpdateArgs, Wait, While, BT, RUNNING}; +use bonsai_bt::{Action, ActionArgs, Event, Float, Success, UpdateArgs, Wait, While, BT, RUNNING}; -type Times = Vec; +type Times = Vec; /// Some test actions. #[derive(Clone, Debug)] enum TestActions { @@ -12,7 +12,7 @@ enum TestActions { } // A test state machine that can increment and decrement. -fn tick(mut acc: usize, dt: f64, t: &mut f64, counter: &mut usize, state: &mut BT) -> usize { +fn tick(mut acc: usize, dt: Float, t: &mut Float, counter: &mut usize, state: &mut BT) -> usize { let e: Event = UpdateArgs { dt }.into(); let (_s, _t) = state @@ -49,7 +49,7 @@ fn tick(mut acc: usize, dt: f64, t: &mut f64, counter: &mut usize, state: &mut B fn test_alter_wait_time() { let a: usize = 0; let mut counter = 0; - let mut timer: f64 = 0.0; + let mut timer: Float = 0.0; let rep = While( Box::new(Wait(50.0)), vec![Action(DynamicWait(vec![1.0, 2.0, 3.0])), Action(Inc)], diff --git a/examples/Cargo.toml b/examples/Cargo.toml index ab78381..fd94ad5 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -25,6 +25,9 @@ rand = "0.8" serde = { version = "1.0.137", features = ["derive"] } serde_json = "1.0.81" +[features] +f32 = ["bonsai-bt/f32"] + [[bin]] name = "async_drone" path = "src/async_drone/main.rs" diff --git a/examples/src/3d/main.rs b/examples/src/3d/main.rs index c4f6e79..094bb8d 100644 --- a/examples/src/3d/main.rs +++ b/examples/src/3d/main.rs @@ -1,6 +1,6 @@ use bonsai_bt::Behavior::{If, Invert, Wait, WhenAny, While}; use bonsai_bt::Status::{self}; -use bonsai_bt::{Action, RUNNING}; +use bonsai_bt::{Action, Float, RUNNING}; use bonsai_bt::{Event, Status::Failure, Status::Success, UpdateArgs}; use bonsai_bt::{Timer, BT}; use kiss3d::event::EventManager; @@ -24,7 +24,7 @@ pub enum Animation { /// check for events with the mouse MouseCallback, /// time has passed longer than - LongerThan(f64), + LongerThan(Float), /// counter /// /// Random complex condition diff --git a/examples/src/boids/boid.rs b/examples/src/boids/boid.rs index d3075ee..dea8876 100644 --- a/examples/src/boids/boid.rs +++ b/examples/src/boids/boid.rs @@ -1,4 +1,4 @@ -use bonsai_bt::{Event, Status::Success, UpdateArgs, BT, RUNNING}; +use bonsai_bt::{Event, Float, Status::Success, UpdateArgs, BT, RUNNING}; use ggez::mint; use std::collections::HashMap; @@ -54,9 +54,9 @@ impl Boid { } } -pub fn game_tick(dt: f32, cursor: mint::Point2, boid: &mut Boid, other_boids: Vec) { +pub fn game_tick(dt: Float, cursor: mint::Point2, boid: &mut Boid, other_boids: Vec) { // proceed to next iteration in event loop - let e: Event = UpdateArgs { dt: dt.into() }.into(); + let e: Event = UpdateArgs { dt }.into(); // unwrap bt for boid let mut bt = boid.bt.clone(); diff --git a/examples/src/boids/main.rs b/examples/src/boids/main.rs index 8453d5e..13d589a 100644 --- a/examples/src/boids/main.rs +++ b/examples/src/boids/main.rs @@ -1,7 +1,7 @@ mod boid; use boid::{game_tick, Action}; -use bonsai_bt::BT; +use bonsai_bt::{Float, BT}; use ggez::{conf, event, graphics, input, timer, Context, ContextBuilder, GameResult}; use std::collections::HashMap; @@ -86,7 +86,18 @@ impl event::EventHandler for GameState { for i in 0..(self.boids).len() { let boids_vec = self.boids.to_vec(); let b = &mut self.boids[i]; - game_tick(self.dt.as_secs_f32(), input::mouse::position(ctx), b, boids_vec); + + let dt: Float = { + #[cfg(feature = "f32")] + { + self.dt.as_secs_f32() + } + #[cfg(not(feature = "f32"))] + { + self.dt.as_secs_f64() + } + }; + game_tick(dt, input::mouse::position(ctx), b, boids_vec); //Convert new velocity to postion change b.x += b.dx * tick;