Calamari / BehaviorTree.js

An JavaScript implementation of Behavior Trees.
326 stars 53 forks source link

Not able to create a custom decorator #22

Open gsommavilla opened 6 years ago

gsommavilla commented 6 years ago

I have an issue while trying to create a custom decorator.

I have tried a MWE using a decorator that is already present in the library, namely CooldownDecorator, and it works just fine.

But when I try to build a custom decorator, problems arise.

I created the following decorator:

$ cat IsBallNearDecorator.js
// const { run, SUCCESS, FAILURE, Decorator } = require('behaviortree') // (*)
import { run, SUCCESS, FAILURE, Decorator } from 'behaviortree';

export default class IsBallNearDecorator extends Decorator {
// class IsBallNearDecorator extends Decorator { // (*)

  nodeType = 'IsBallNearDecorator';

  decorate (run, blackboard) {
    console.log("blackboard.isBallNear: "+blackboard.isBallNear);
    if (blackboard.isBallNear)
      return run()
    else
      return FAILURE
  }
}

// module.exports = IsBallNearDecorator // (*)

Which is very similar to the test src/BehaviorTreeImporter.spec.js that is present in the library of the behaviortree module.

The class IsBallNearDecorator is imported into a minimal behaviortree, like this:

$ cat bt__IsBallNearDecorator.js
// const { BehaviorTreeImporter, BehaviorTree, Sequence, Task, SUCCESS, FAILURE } = require('behaviortree') // (*)
import { BehaviorTreeImporter, BehaviorTree, Sequence, Task, SUCCESS, FAILURE } from 'behaviortree';

import { IsBallNearDecorator } from './IsBallNearDecorator.js';
// const IsBallNearDecorator = require('./IsBallNearDecorator'); // (*)

const takeBallTask = new Task({
  run: function(blackboard) {
    console.log("DEBUG1: takeBall task");
    return SUCCESS;
  }
});

let importer = new BehaviorTreeImporter();

const json = {
  type: 'selector',
  name: 'the root',
  nodes: [
    {
      type: 'IsBallNearDecorator',
//      type: 'cooldown', cooldown: 1,
      name: 'testing around',
      node: {
    type: 'takeBall',
    name: 'take the ball'
      }
    }
  ]
};

BehaviorTree.register('IsBallNearDecorator', new IsBallNearDecorator());
BehaviorTree.register('takeBall', takeBallTask);

const blb = {
  isBallNear: "asdf"
}

const bTree = new BehaviorTree({
  tree: importer.parse(json),
  blackboard: blb,
})

setInterval(function () {
  bTree.step()
}, 1000 )

When trying to execute the tree, I get the following error:

$ babel-node bt__IsBallNearDecorator.js 
/usr/lib/node_modules/babel-cli/node_modules/babel-core/lib/transformation/file/index.js:558
      throw err;
      ^

SyntaxError: /home/giacomo/DEV/behaviortree--nodejs--Calamari/IsBallNearDecorator.js: Unexpected token (7:11)
   5 | // class IsBallNearDecorator extends Decorator { // (*)
   6 | 
>  7 |   nodeType = 'IsBallNearDecorator';
     |            ^
   8 | 
   9 |   decorate (run, blackboard) {
  10 |     console.log("blackboard.isBallNear: "+blackboard.isBallNear);
    at Parser.pp$5.raise (/usr/lib/node_modules/babel-cli/node_modules/babylon/lib/index.js:4454:13)
    at Parser.pp.unexpected (/usr/lib/node_modules/babel-cli/node_modules/babylon/lib/index.js:1761:8)
    at Parser.pp$1.parseClassProperty (/usr/lib/node_modules/babel-cli/node_modules/babylon/lib/index.js:2571:50)
    at Parser.pp$1.parseClassBody (/usr/lib/node_modules/babel-cli/node_modules/babylon/lib/index.js:2516:34)
    at Parser.pp$1.parseClass (/usr/lib/node_modules/babel-cli/node_modules/babylon/lib/index.js:2406:8)
    at Parser.pp$1.parseExport (/usr/lib/node_modules/babel-cli/node_modules/babylon/lib/index.js:2642:19)
    at Parser.pp$1.parseStatement (/usr/lib/node_modules/babel-cli/node_modules/babylon/lib/index.js:1884:74)
    at Parser.pp$1.parseBlockBody (/usr/lib/node_modules/babel-cli/node_modules/babylon/lib/index.js:2268:21)
    at Parser.pp$1.parseTopLevel (/usr/lib/node_modules/babel-cli/node_modules/babylon/lib/index.js:1778:8)
    at Parser.parse (/usr/lib/node_modules/babel-cli/node_modules/babylon/lib/index.js:1673:17)

I am not sure if nodeType is mandatory, so I tried to comment it out (// nodeType = 'IsBallNearDecorator';), but then I get another error:

$ babel-node bt__IsBallNearDecorator.js 
/home/giacomo/DEV/behaviortree--nodejs--Calamari/bt__IsBallNearDecorator.js:33
_behaviortree.BehaviorTree.register('IsBallNearDecorator', new _IsBallNearDecorator.IsBallNearDecorator());
                                                           ^

TypeError: _IsBallNearDecorator.IsBallNearDecorator is not a constructor
    at Object.<anonymous> (/home/giacomo/DEV/behaviortree--nodejs--Calamari/bt__IsBallNearDecorator.js:32:46)
    at Module._compile (internal/modules/cjs/loader.js:654:30)
    at loader (/usr/lib/node_modules/babel-cli/node_modules/babel-register/lib/node.js:144:5)
    at Object.require.extensions.(anonymous function) [as .js] (/usr/lib/node_modules/babel-cli/node_modules/babel-register/lib/node.js:154:7)
    at Module.load (internal/modules/cjs/loader.js:566:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:506:12)
    at Function.Module._load (internal/modules/cjs/loader.js:498:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:695:10)
    at Object.<anonymous> (/usr/lib/node_modules/babel-cli/lib/_babel-node.js:154:22)
    at Module._compile (internal/modules/cjs/loader.js:654:30)

I also tried invoking node instead of babel-node (replacing import with require(..), export default with module.exports, ..), but the result is the same error.

I tried to modify the behaviortree library, but I haven't been able to get webpack compile the source code.

Can anyone help me with this issue?

sxtxixtxcxh commented 4 years ago

i know this is late, but for anyone else, that's a static property feature that's supported in this project through babel: https://babeljs.io/docs/en/babel-plugin-proposal-class-properties

you can fix this by setting it in the constructor, like:

import { Decorator, RUNNING, SUCCESS, FAILURE } from "behaviortree";

export class InvertDecorator extends Decorator {
  constructor(props) {
    super(props);
    this.nodeType = "InvertDecorator";
  }
  decorate(run) {
    const result = run();
    if (result === RUNNING) return RUNNING;
    return result === SUCCESS ? FAILURE : SUCCESS;
  }
}

(and be sure to pass props along to super)