npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@sv-gray/fluent-behavior-tree

v1.2.9

Published

Behavior tree library with a fluent API

Downloads

4

Readme

Fluent Behavior Tree

This is a Typescript/Javascript implementation of https://github.com/codecapers/Fluent-Behaviour-Tree

JS/TS behaviour tree library with a fluent API. This fork includes a different return structure that can be used for logging.

For a background and walk-through please see the accompanying article.

Understanding Behaviour Trees

Here are some resources to help you understand behaviour trees:

Installation

Install with npm:

npm install -s fluent-behavior-tree

Usage

A behavior tree is created through BehaviorTreeBuilder. The tree is returned when the build function is called.

import {BehaviorTreeBuilder, BehaviorTreeStatus, TimeData} from "fluent-behavior-tree";

// ...

const builder = new BehaviorTreeBuilder();
this.tree = builder
    .sequence("my-sequence")
        .do("action1", async (t) => {
            // Action 1.

            return BehaviorTreeStatus.Success;
        })
        .do("action2", async (t) => {
            //Action 2.

            return BehaviorTreeStatus.Failure;
        })
    .end()
    .build();

Then, Tick the behavior tree on each update of your loop

public async update(deltaTime: number): Promise<void> {
    await this.tree.tick(new TimeData(deltaTime));
}

Behavior Tree Status

Behavior tree nodes must return the following status codes:

  • BehaviorTreeStatus.Success: The node has finished what it was doing and succeeded.
  • BehaviorTreeStatus.Failure: The node has finished, but failed.
  • BehaviorTreeStatus.Running: The node is still working on something.

Node Types

Action / Leaf-Node

Call the do function to create an action node at the leaves of the behavior tree.

.do("do-something", async (t) => {
    // ... Do something ...

    return BehaviorTreeStatus.Success;
});

The return value defines the status of the node. Return one of the statuses from above.

Sequence

Runs each child node in sequence. Fails for the first child node that fails. Moves to the next child when the current running child succeeds. Stays on the current child node while it returns running. Succeeds when all child nodes have succeeded.

.sequence("my-sequence")
    .do("action1", async (t) => { // Run this.
        // Action 1.

        return BehaviorTreeStatus.Success;
    })
    .do("action2", async (t) => { // Then run this.
        //Action 2.

        return BehaviorTreeStatus.Failure;
    })
.end()

Parallel

Runs all child nodes in parallel. Continues to run until a required number of child nodes have either failed or succeeded.

let numRequiredToFail: number = 2;
let numRequiredToSuccess: number = 2;

.parallel("my-parallel"m numRequiredtoFail, numRequiredToSucceed)
    .do("action1", async (t) => { // Run this at the same time as action2
        // Parallel action 1

        return BehaviorTreeStatus.Running;
    })
    .do("action12, async (t) => { // Run this at the same time as action1
        // Parallel action 2

        return BehaviorTreeStatus.Running;
    })
.end();

Selector

Runs child nodes in sequence until it finds one that succeeds. Succeeds when it finds the first child that succeeds. For child nodes that fail, it moves forward to the next child node. While a child is running it stays on that child node without moving forward.

.selector("my-selector")
    .do("action1", async (t) => {
        // Action 1

        return BehaviorTreeStatus.Failure; // Fail, move onto the next child
    })
    .do("action2", async (t) => {
        // Action 2

        return BehaviorTreeStatus.Success; // Success, stop here.
    })
    .do("action3", async (t) => {
        // Action 3

        return BehaviorTreeStatus.Success; // Doesn't get this far.
    })
.end();

Condition

The condition function is syntatic sugar for the do function. It allows the return of a boolean value that is then converted to success or failure. It is intended to be used with Selector.

.selector("my-selector")
    .Condition("condition1", async (t) => this.someBooleanConditional()) // Predicate that returns *true* or *false*
    .do("action1", async (t) => this.someAction()) // Action to run if the predicate evaluates to *true*
.end()

Inverter

Inverts the success or failure of the child node. Continues running while the child node is running.

.inverter("inverter1")
    .do("action1", async (t) => BehaviourTreeStatus.Success) // *Success* will be inverted to *failure*.
.end()


.inverter("inverter1")
    .do("action1", async (t) => BehaviourTreeStatus.Failure) // *Failure* will be inverted to *success*.
.end()

Nesting Behaviour Trees

Behaviour trees can be nested to any depth, for example:

.selector("parent")
    .sequence("child-1")
        ...
        .parallel("grand-child")
            ...
        .end()
        ...
    .end()
    .sequence("child-2")
        ...
    .end()
.end()

Splicing a Sub-tree

Separately created sub-trees can be spliced into parent trees. This makes it easy to build behaviour trees from reusable components.

private createSubTree(): BehaviorTreeNodeInterface
{
    return new BehaviourTreeBuilder()
        .sequence("my-sub-tree")
            .do("action1", async (t) => {
                // Action 1.

                return BehaviourTreeStatus.Success;
            })
            .Do("action2", async (t) => {
                // Action 2.

                return BehaviourTreeStatus.Success;
            });
        .end()
        .build();
}

public startup(): void
{
    this.tree = new BehaviourTreeBuilder()
        .sequence("my-parent-sequence")
            .Splice(this.createSubTree()) // Splice the child tree in.
            .Splice(this.createSubTree()) // Splice again.
        .end()
        .build();
}