Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reset BT if tick returns Success or Failure. #44

Closed
wants to merge 4 commits into from

Conversation

andriyDev
Copy link
Collaborator

@andriyDev andriyDev commented Jan 18, 2025

Today, ticking a behavior tree after it has finished has confusing results. Looking at the code, it seems the intent was that once a State finishes, it is not expected to tick again. For example, if you tick a Sequence/Select after it has finished, it always returns Running. Here's an example test that shows this strange behavior:

#[test]
fn weird_behavior() {
    let a = 4;

    let mut bt = BT::new(
        Select(vec![
            Invert(Box::new(Action(Dec))),
            Invert(Box::new(Action(Dec))),
            Invert(Box::new(Action(Dec))),
        ]),
        (),
    );

    let (a, s, _) = tick(a, 0.1, &mut bt);
    assert_eq!(a, 1);
    assert_eq!(s, Failure);
    let (a, s, _) = tick(a, 0.1, &mut bt);
    assert_eq!(a, 1);
    assert_eq!(s, Running);
    let (a, s, _) = tick(a, 0.1, &mut bt);
    assert_eq!(a, 1);
    assert_eq!(s, Running);
}

This is clearly wrong. We could fix this particular issue (make Sequence/Select return a finished status if you tick it again), but it's not clear that ticking a finished behavior makes sense at all - so perhaps we should stop that.

There are two options then:

  1. Prevent the BT from being used after it's finished. We could make the State an Option and take it once the State finishes. This requires us to return an error to the user, and the user to for example, reset the tree.
  2. Make the tree just reset to its initial state.

This PR does the latter. It is likely what users would expect (you can keep ticking your tree), and the behavior is well defined.

Users shouldn't be messing with the internal state of the behavior tree. That could result in the behavior tree producing all sorts of strange behavior.
@andriyDev
Copy link
Collaborator Author

andriyDev commented Jan 18, 2025

I've written this atop #42 since that one is likely to be merged soon and I'd rather not have to rewrite this PR. I will rebase this PR once that's done.

I really wish Github had support for dependent PRs :'(

@kaphula
Copy link
Collaborator

kaphula commented Jan 18, 2025

I agree that the handling with finished tree is a bit messy at the moment, but I am not sure automatically resetting the tree by default is a good idea either. At very least it would be good to have an option to toggle the automatic reset off.

Could not the returned Status of tick be wrapped inside an Option to notify if the tree has finished, thus leaving a user an option to reset the tree manually when None is returned? Alternatively, maybe the Status enum could have an additional variant Finish that would notify that the tree has finished, and in addition to that, the user could use Finish to finish the tree manually by returning Finish from tick's callback. Maybe with these cases the user could also manually toggle the tree to reset automatically if that is the default behavior the user wants.

What do you think?

@andriyDev
Copy link
Collaborator Author

@kaphula yup that's basically the first option I provided there (unless I'm misunderstanding)! I'm happy to implement that instead. I'll open another PR soon.

@andriyDev
Copy link
Collaborator Author

Closing this in favour of #45.

@andriyDev andriyDev closed this Jan 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants