use crate::{
self as behaviortree, Control,
behavior::{Behavior, BehaviorData, BehaviorError, BehaviorResult, BehaviorState},
tree::BehaviorTreeElementList,
};
use alloc::boxed::Box;
use tinyscript::SharedRuntime;
#[derive(Control, Debug)]
#[behavior(groot2)]
pub struct SequenceWithMemory {
child_idx: usize,
all_skipped: bool,
}
impl Default for SequenceWithMemory {
fn default() -> Self {
Self {
child_idx: 0,
all_skipped: true,
}
}
}
#[async_trait::async_trait]
impl Behavior for SequenceWithMemory {
#[inline]
fn on_halt(&mut self) -> Result<(), BehaviorError> {
self.child_idx = 0;
self.all_skipped = true;
Ok(())
}
#[inline]
fn on_start(
&mut self,
behavior: &mut BehaviorData,
_children: &mut BehaviorTreeElementList,
_runtime: &SharedRuntime,
) -> Result<(), BehaviorError> {
behavior.set_state(BehaviorState::Running);
Ok(())
}
async fn tick(
&mut self,
_behavior: &mut BehaviorData,
children: &mut BehaviorTreeElementList,
runtime: &SharedRuntime,
) -> BehaviorResult {
while self.child_idx < children.len() {
let child = &mut children[self.child_idx];
let new_state = child.tick(runtime).await?;
self.all_skipped &= new_state == BehaviorState::Skipped;
match new_state {
BehaviorState::Failure => {
children.halt_from(self.child_idx, runtime)?;
return Ok(BehaviorState::Failure);
}
BehaviorState::Idle => {
return Err(BehaviorError::State {
behavior: "SequenceWithMemory".into(),
state: new_state,
});
}
BehaviorState::Running => return Ok(BehaviorState::Running),
BehaviorState::Skipped | BehaviorState::Success => {
self.child_idx += 1;
}
}
}
if self.child_idx >= children.len() {
children.halt(runtime)?;
self.child_idx = 0;
}
if self.all_skipped {
Ok(BehaviorState::Skipped)
} else {
Ok(BehaviorState::Success)
}
}
}