use gizmo_core::World;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BtStatus {
Success,
Failure,
Running,
}
pub trait BtNode: Send + Sync {
fn tick(&mut self, entity: u32, world: &mut World, dt: f32) -> BtStatus;
}
pub struct Sequence {
children: Vec<Box<dyn BtNode>>,
current_idx: usize,
}
impl Sequence {
pub fn new(children: Vec<Box<dyn BtNode>>) -> Self {
Self {
children,
current_idx: 0,
}
}
}
impl BtNode for Sequence {
fn tick(&mut self, entity: u32, world: &mut World, dt: f32) -> BtStatus {
while self.current_idx < self.children.len() {
let status = self.children[self.current_idx].tick(entity, world, dt);
match status {
BtStatus::Success => {
self.current_idx += 1; }
BtStatus::Failure => {
self.current_idx = 0; return BtStatus::Failure;
}
BtStatus::Running => {
return BtStatus::Running;
}
}
}
self.current_idx = 0; BtStatus::Success
}
}
pub struct Selector {
children: Vec<Box<dyn BtNode>>,
current_idx: usize,
}
impl Selector {
pub fn new(children: Vec<Box<dyn BtNode>>) -> Self {
Self {
children,
current_idx: 0,
}
}
}
impl BtNode for Selector {
fn tick(&mut self, entity: u32, world: &mut World, dt: f32) -> BtStatus {
while self.current_idx < self.children.len() {
let status = self.children[self.current_idx].tick(entity, world, dt);
match status {
BtStatus::Success => {
self.current_idx = 0; return BtStatus::Success;
}
BtStatus::Failure => {
self.current_idx += 1; }
BtStatus::Running => {
return BtStatus::Running;
}
}
}
self.current_idx = 0; BtStatus::Failure
}
}
pub struct Inverter {
child: Box<dyn BtNode>,
}
impl Inverter {
pub fn new(child: Box<dyn BtNode>) -> Self {
Self { child }
}
}
impl BtNode for Inverter {
fn tick(&mut self, entity: u32, world: &mut World, dt: f32) -> BtStatus {
match self.child.tick(entity, world, dt) {
BtStatus::Success => BtStatus::Failure,
BtStatus::Failure => BtStatus::Success,
BtStatus::Running => BtStatus::Running,
}
}
}
pub struct Action<F>
where
F: FnMut(u32, &mut World, f32) -> BtStatus + Send + Sync,
{
func: F,
}
impl<F> Action<F>
where
F: FnMut(u32, &mut World, f32) -> BtStatus + Send + Sync,
{
pub fn new(func: F) -> Self {
Self { func }
}
}
impl<F> BtNode for Action<F>
where
F: FnMut(u32, &mut World, f32) -> BtStatus + Send + Sync,
{
fn tick(&mut self, entity: u32, world: &mut World, dt: f32) -> BtStatus {
(self.func)(entity, world, dt)
}
}
pub struct Condition<F>
where
F: FnMut(u32, &mut World) -> bool + Send + Sync,
{
func: F,
}
impl<F> Condition<F>
where
F: FnMut(u32, &mut World) -> bool + Send + Sync,
{
pub fn new(func: F) -> Self {
Self { func }
}
}
impl<F> BtNode for Condition<F>
where
F: FnMut(u32, &mut World) -> bool + Send + Sync,
{
fn tick(&mut self, entity: u32, world: &mut World, _dt: f32) -> BtStatus {
if (self.func)(entity, world) {
BtStatus::Success
} else {
BtStatus::Failure
}
}
}
pub struct BehaviorTree {
pub root: Option<Box<dyn BtNode>>,
}
impl gizmo_core::component::Component for BehaviorTree {}
impl Clone for BehaviorTree {
fn clone(&self) -> Self {
panic!("BehaviorTree cannot be cloned!");
}
}
impl BehaviorTree {
pub fn new(root: Box<dyn BtNode>) -> Self {
Self { root: Some(root) }
}
pub fn tick(&mut self, entity: u32, world: &mut World, dt: f32) -> BtStatus {
if let Some(root) = &mut self.root {
root.tick(entity, world, dt)
} else {
BtStatus::Failure
}
}
}
pub fn behavior_tree_system(world: &mut World, dt: f32) {
let entities: Vec<u32> = {
let trees = world.borrow_mut::<BehaviorTree>();
trees.entities().collect()
};
for entity in entities {
let mut root_opt = None;
if let Some(mut tree) = world.borrow_mut::<BehaviorTree>().get_mut(entity) {
root_opt = tree.root.take();
}
if let Some(mut root) = root_opt {
root.tick(entity, world, dt);
if let Some(mut tree) = world.borrow_mut::<BehaviorTree>().get_mut(entity) {
tree.root = Some(root);
}
}
}
}