Consider the following code where I've created a decorator that will add a custom cooldown timer to a BT that will start as soon as the tree experiences a SUCCESS in the sequence that it is wrapping. This concept works excellent when there is 1 tree present.
However, as soon as I instance the class a second time, the two trees exhibit shared behavior. Meaning, as soon as one of the trees experiences a SUCCESS, both of their decorators fire and the cooldown begins for BOTH trees instead of just the one that had the SUCCESS as you would expect.
// Custom decorator that adds a cooldown after a SUCCESS// Modified from the CooldownDecorator in the repo.// Original CooldownDecorator times the cooldown from the START of// the sequence. I need to time from the end of the sequence getting a SUCCESS.classSuccessCooldownDecoratorextendsDecorator{nodeType='SuccessCooldownDecorator'setConfig({ cooldown }){this.config={ cooldown }}decorate(run){if(this.lock){returnFAILURE}constresult=run()if(result===SUCCESS){this.lock=truesetTimeout(()=>{this.lock=false},this.config.cooldown*1000)}returnresult}}// Create a new sequenceBehaviorTree.register('my-sequence',newSequence({nodes: [ ... ]}))// Implement a custom Decorator around the SequenceBehaviorTree.register('decorated',newSuccessCooldownDecorator({node: 'my-sequence',config: {cooldown: 2}}))// Place the BT inside of a classclassMyContainer{contructor(){this.tree=newBehaviorTree({node: 'decorated',blackboard: { ... }})}update(){this.tree.step()}}constinst1=newMyContainer()constinst2=newMyContainer()
If I move the decorator being created out of the register and into the class constructor, it works as expected.
classMyContainer{contructor(){this.tree=newBehaviorTree({node: newSuccessCooldownDecorator({node: 'my-sequence',config: {cooldown: 2}}),blackboard: { ... }})}
...
}I tried looking through the Decorator and Node classes to see if I could identify the issue I'm having, but I couldn't find any instances of any global state being used. I'm not sure why doing new Sequence in the global scope works fine, but doing new Decorator in the global scope doesn't allow this use case.
Is my custom decorator implementation incorrect? Am I doing something else wrong?
Consider the following code where I've created a decorator that will add a custom cooldown timer to a BT that will start as soon as the tree experiences a SUCCESS in the sequence that it is wrapping. This concept works excellent when there is 1 tree present.
However, as soon as I instance the class a second time, the two trees exhibit shared behavior. Meaning, as soon as one of the trees experiences a SUCCESS, both of their decorators fire and the cooldown begins for BOTH trees instead of just the one that had the SUCCESS as you would expect.
If I move the decorator being created out of the register and into the class constructor, it works as expected.
I tried looking through the Decorator and Node classes to see if I could identify the issue I'm having, but I couldn't find any instances of any global state being used. I'm not sure why doing
new Sequencein the global scope works fine, but doingnew Decoratorin the global scope doesn't allow this use case.Is my custom decorator implementation incorrect? Am I doing something else wrong?