NodeCanvas Forums › Support › BT sequence of actions that starts&restarts when receiving a specific Event
I can’t seem to figure out how to do this. I’d like to have a sequence of actions that triggers as soon as a specific event is received. However, the sequence should also start from the beginning if that same event is received while executing that sequence. I hope someone here could give me an example. Thanks!
Edit: I’m trying to get this to work in a BT.
I now have this:
– Top level node is a dynamic selector
– The first child will check for the event and set a variable $ButtonIndex when the event is received
– The second branch checks for this value
– In the first action of the sequence, the variable $ButtonIndex is set to the value -1.
This will make sure that the branch is not selected again before a new event has been received.
It’s working as intended, but I wonder if there is a more elegant way of doing it without requiring me to use a special value for $ButtonIndex (-1).
I guess I’d like to have an easy way to get this pattern:
– Some starting condition
– A sequence of actions (the ‘plan’)
– Some continue condition
The continue condition should only be evaluated when the plan is running. If the condition fails while running, the plan should be reset and starting condition + plan should be reevaluated. This would then possibly restart the plan.
I guess I could make a node that is similar to Interrupt, but instead of returning failure it would reset the decorated connection before executing it. Is there any other obvious way that I’m missing to implement this pattern?
I tried making the Reset node, but it’s not working as expected. This is the code that I have:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
using NodeCanvas.Framework; using ParadoxNotion.Design; using UnityEngine; namespace NodeCanvas.BehaviourTrees { [Name("Reset")] [Category("Decorators")] [Description("Reset the child node if the condition is true while running. Always runs the decorated child node and returns its status")] [Icon("Resetter")] public class Resetter : BTDecorator, ITaskAssignable<ConditionTask> { [SerializeField] private ConditionTask _condition; public ConditionTask condition { get { return _condition; } set { _condition = value; } } public Task task { get { return condition; } set { condition = (ConditionTask)value; } } protected override Status OnExecute(Component agent, IBlackboard blackboard) { if (decoratedConnection == null) return Status.Resting; if (condition != null && status == Status.Running && condition.CheckCondition(agent, blackboard)) decoratedConnection.Reset(); return decoratedConnection.Execute(agent, blackboard); } } } |
See the attached image for my current BT-test setup. The root node is this new Reset node that I made.
The Log actions execute normally when I fire the very first event. The log action tasks also get interrupted and restarted as intended if I fire events before the actions finish.
However, if I wait for the action node to finish, the next event will trigger only the “On” message, and interrupt the action node immediately, or so it seems. Is there anything wrong with my code?
Hello there,
Sorry for the late reply.
If I understood correctly based on your 3rd post explanation, the following image shows the pattern that you are probably after, where the key node used here, is the Parallel Composite:
– The first node is a Conditional Decorator and simply checks a condition to allow “passage” or “access”. A pre-condition.
– The Parallel node here is key, because it evaluates all it’s children in parallel and as such, both the Condition Node and Action Node (it could be a Sequencer node of course) are evaluated together. As soon as the Condition Node returns Failure, the Parallel node will bail out in Failure too, because it is set to use the “First Failure” policy as well as it is set to be Dynamic (so that the condition is continuously evaluated).
Please let me know if that is indeed what you were after, or whether or not you have any questions about this.
Thank you!
Join us on Discord: https://discord.gg/97q2Rjh
Thank you for your message. I do have a couple of questions/remarks about this:
The wording of the Parallel node sounded to me like it will execute all children concurrently. I regularly do parallel programming (in multi-threaded applications), and this seemed a recipe for race conditions. However, looking at the code it seems the evaluation order of the children of Parallel is still left to right, just like other composites. So the difference is that multiple children/branches can be in running state. I think the documentation could be improved a bit here to avoid this confusion.
There are some differences in what I tried to achieve and what your solution does.
* In your example, the $ParallelCondition check is also performed before the action node has started running. The pattern I´m looking for should skip this condition when the actions are not yet running. It should however break off the actions as quickly as possible, so just changing the order of the children of the Parallel node is also not an option.
* Correct me if I´m wrong, but it seems that the action node cannot be reset and restarted in the same BT update using your pattern. In one update the $ParallelCondition and Parralel node will trigger failure. The next update the action may (or may not) trigger again. Unfortunately this doesn’t seem to be an option for me as I’m checking for events that are only there for one frame.
These are the things I was trying to solve with my Reset node. It would be great if you could also have a look at that post.
Thank you for your help!
I managed to fix the Resetter node by changing this
1 2 |
if (condition != null && status == Status.Running && condition.CheckCondition(agent, blackboard)) decoratedConnection.Reset(); |
into this
1 2 3 |
bool condition_is_true = condition == null ? false : condition.CheckCondition(agent, blackboard); if (status == Status.Running && condition_is_true) decoratedConnection.Reset(); |
Now my example “reset_example.png” is working as intended. It looks like the CheckEvent condition task keeps its value and does not reset if it is not evaluated during the update. So it seems I cannot skip the evaluation of the condition. Is this correct?
Hello,
The CheckEvent condition is implemented so that whenever the target event is received, the CheckEvent condition will return true for one frame. It does not latch/keep it’s value, but if it’s next evaluation happens on the same or next frame apart from when the event was received, it will still return true. After 1 frame has passed, it’s return value will reset to false, until the event is received again.
I think that for your case where you want to have nodes being reset and re-evaluated within same frame as far as I understand, it would be better to work with boolean variables rather than events, since events within the context of Behaviour Trees, are a bit tricky due to how Behaviour Trees work in general.
I hope this helps.
Thanks!
Join us on Discord: https://discord.gg/97q2Rjh