pruttned / owl-bt

owl-bt is editor for Behavior trees. It has been inspired by Unreal engine behavior trees in a way, that it supports special node items like decorators and services. This makes trees smaller and much more readable.
174 stars 28 forks source link
ai artificial-intelligence behavior behavior-tree game tree

owl-bt

owl-bt is editor for Behavior trees. It has been inspired by Unreal engine behavior trees in a way, that it supports special node items like decorators and services. This makes trees smaller and much more readable.

Why

owl-bt has been created because we needed a behavior tree editor for our game Tendril: Echo Received, where we are focusing on live npc behavior.

We have tried some of the existing solutions, but they haven't meet our requirements like:

Install

npm install owl-bt -g

Usage

Configuration

owl-bt runs as a service on port 8955 by default. This can be changed in config file .owlbtrc, that must be created in the user`s home directory.

{
    "port" : 1234
}

Tree items

bt node

In owl-bt, there are three types of items:

Features

bt node

bt node

Project file

Project file (owl-bt.json) defines all nodes and node item types that can be used in trees.

Node

Decorator

Service

Property

Types

Enables to define custom property types

Example:

{
  "types":{
    "myString" : {
      "type" : "string",
      "pattern" : "v[0-9]"
    }
  },
  "nodes": [
    {
      "name": "SetAlertLevel",
      "icon": "exclamation",
      "description": "Set alert level to \"{{Level}}\"",
      "isComposite": false,
      "properties": [
        {
          "name": "Level",
          "default": "None",
          "type": "enum",
          "values": [
            "None",
            "Investigate",
            "HighAlert",
            "Panic"
          ]
        }
      ]
    }
  ],
  "decorators": [
    {
      "name": "HasZoneReportedEnemy",
      "icon": "phone",
      "properties": [
        {
          "name": "MaxReportAge",
          "default": 1,
          "type": "number"
        }
      ]
    }
  ],
  "services": [
    {
      "name": "ReadPlayerPos",
      "icon": "pencil",
      "description": "Store player pos to \"{{BlackboardKey}}\"",
      "properties": [
        {
          "name": "BlackboardKey",
          "default": "Target",
          "type": "string"
        }
      ]
    }
  ]
}

Tree file

{
    "type": "Selector",
    "name": "rootNode",
    "childNodes": [
        {
            "type": "Sequence",
            "services": [
                {
                    "type": "Sample service"
                }
            ],
            "decorators": [
                {
                    "type": "IsBlackboardValueSet",
                    "properties": [
                        {
                            "name": "Field",
                            "value": "myValue"
                        }
                    ],
                    "periodic": true
                }
            ]
        }
    ]
}

Inheritance

It is possible to derive a node item type from another type using base setting.

It is possible to use string or array of strings for base setting. In case of array, base item types are applied in a specified order. That means, that the later item type overrides item specified before it.

E.q. we may create a base node:

{
      "name": "MyBaseNode",
      "icon": "arrow-right",
      "color": "red",
      "isAbstract" : true,
      "properties": [
        {
          "name": "prop-from-base1",
          "type": "string"
        },
        {
          "name": "prop-from-base2",
          "type": "number"
        }
      ]
    },

And derived node:

{
      "name": "MyDerivedNode",
      "color": "blue",
      "base": "MyBaseNode",
      "properties": [
        {
          "name": "prop1",
          "type": "string"
        },
        {
          "name": "prop-from-base2",
          "default" : "abc",          
          "type": "string"
        }
      ]
    },

Resulting node after applying inheritance is going to look like:

{
      "name": "MyDerivedNode",
      "icon": "arrow-right",      
      "color": "blue",
      "base": "MyBaseNode",
      "properties": [
        {
          "name": "prop-from-base1",
          "type": "string"
        },
        {
          "name": "prop-from-base2",
          "default" : "abc",          
          "type": "string"
        },
        {
          "name": "prop1",
          "type": "string"
        }
      ]
    },

Plugins

owl-bt.js file in the same directory as project file owl-bt.json is considered plugin. Plugin js file exports object with plugin functions.

module.exports = {
    onTreeSave: ({ tree, path, project, projectPath }) => {
    },
    onTreeLoad: ({ tree, path, project, projectPath }) => {
    }
}

It is possible for example to create a custom tree file formats using onTreeSave and onTreeLoad. If we wanted to have project path stored in the tree file, we could create the following plugin:

module.exports = {
    onTreeSave: ({ tree, path, project, projectPath }) => {
        tree.projectPath = projectPath;
    }
}

Changelog

1.1.0

1.2.0

1.3.0

2.0.0

2.1.0