ThePat02 / BehaviourToolkit

A collection of tools for AI Behaviour in the Godot 4 Game Engine!
MIT License
368 stars 15 forks source link

BTSequence does not return SUCCESS when the last action is successful until the after first action has run again in some cases. #81

Closed nickswebsite closed 1 month ago

nickswebsite commented 6 months ago

BTSequence does not return a SUCCESSful status when the last action is successful. Currently it waits for the next tick to reset itself and report success.

While this doesn't appear to be a problem for trivial cases, when a child node of an FSMStateIntegratedBT that is configured to fire an event on success, the event does not get fired until the first task of the sequence has already run. This is particularly problematic if the first task is intended to check conditions based on the current state of the game world.

The 'minimal' scene setup:

Ultimately what will happen is this:

I would have expected this sequence:

The offending lines of code appear to be in bt_sequence.gd:

func tick(delta: float, actor: Node, blackboard: Blackboard):
    if current_leaf > leaves.size() -1:
        current_leaf = 0
        return BTStatus.SUCCESS

    var response = leaves[current_leaf].tick(delta, actor, blackboard)

    if response == BTStatus.RUNNING:
        return response

    if response == BTStatus.FAILURE:
        current_leaf = 0
        return response

    current_leaf += 1
    return BTStatus.RUNNING

I can put in a PR for a fix, but I really don't have any good way to know if doing so would introduce issues elsewhere. When I see a slightly awkward construction like this, I have to think there is a reason for it.

nickswebsite commented 6 months ago

After digging a little deeper, it appears that the BTRoot and the FiniteStateMachine nodes are fighting each other during the _process_code(). BTRoot._process_code() runs after FiniteStateMachine._process_code(), so BTRoot.current_status doesn't get updated (and no event is fired) during the frame.

I had to make sure SUCCESS was returned from BTSequence when the last action was completed successfully, AND alter FSMStateIntegratedBT in the following manner:

nickswebsite commented 6 months ago

I added an example scene here: https://github.com/ThePat02/BehaviourToolkit/pull/83