behavior3go

repository·master·Indexed 43 days ago

https://github.com/magicsea/behavior3go

A Go implementation of the Behavior3 behavior tree library. It features a stateless tree structure where all node states are stored in a blackboard, allowing multiple agents to share a single tree. It is compatible with the official Behavior3 online editor and supports loading trees from exported project files, raw project files, and JSON.

Tokens
1.9K
Snippets
4
Records
13
Agent score
55%

What's inside behavior3go

  1. Access the target in Tick functions

    master
    When writing AI logic within a Tick, the target typically refers to the owner of the AI. The owner should have access to the blackboard members to facilitate communication between the tree and the game entity.
  2. Understand the behavior3go stateless tree model

    master

    Unlike many behavior tree implementations where each agent holds its own copy of the tree structure containing state, behavior3go uses a stateless tree structure.

    • Tree Structure: A single, shared instance that remains stateless.
    • State Management: All state information is stored in a Blackboard.

    This design allows multiple agents to share the same tree structure while maintaining individual states via their own blackboards.

  3. Load behavior trees from different file formats

    master

    The library provides several ways to load behavior tree logic depending on your source data:

    • Load from Tree: Loading from an exported tree file.
    • Load from Project: Loading from an exported project file.
    • Load from Raw Project: Loading from a native project file.
    • Subtree Support: Using subtrees (requires the dedicated editor branch).

    For example, if you have a bin/b3.json file from an IO-style game, you can import it into the editor via Project -> Import -> Tree as json to reconstruct the project.

  4. Set up the web-based editor locally

    master

    To run the official online editor locally for editing logic nodes, follow these steps:

    1. Clone the editor source: https://github.com/magicsea/behavior3editor
    2. Ensure Node.js and npm are installed.
    3. Install bower: npm install -g bower
    4. Install dependencies:
      cd behavior3editor
      npm install
      bower install
    5. Install gulp: npm install --global gulp
    6. Run the server: gulp serve
    7. Access the editor in your browser at: http://127.0.0.1:8000

    Deployment: To deploy your own web version, simply move the generated build directory to your web server (e.g., Tomcat or IIS).

  5. Troubleshoot memory node chain closure issues

    master

    In certain behavior tree configurations involving memory nodes (specifically memseq nodes), a bug may prevent the first node in a memory node chain from executing its onclose method.

    Symptoms:

    • The runningChild state is not cleared/reset in the memseq node.
    • The behavior tree skips expected nodes (e.g., jumping directly from Wait0-2 to Wait1-2 instead of entering the next logical job like job 1-0).

    Debugging: To reproduce and verify this issue, enable print logging for Wait nodes to track job transitions and timing.

  6. Use the memsubtree example to handle subtree reuse

    master

    The memsubtree example demonstrates how to resolve issues where multiple subtrees are reused, which can lead to inconsistent or chaotic running states.

    To fix this, the standard subtree implementation is modified to consolidate multiple tick calls into a single primary tick. This ensures that state management remains consistent even when the same subtree structure is utilized across different parts of the behavior tree.

  7. Create unique IDs with CreateUUID()

    master

    Use CreateUUID() to generate a unique identifier for behavior trees and nodes. The implementation generates a 32-character MD5 string derived from random bytes, intended to serve as a unique ID (referencing RFC 4122 concepts).

    import "github.com/magicsea/magicsea/behavior3go"
    
    // Generate a unique ID for a node or tree
    uid := behavior3go.CreateUUID()
  8. Register and instantiate structs with RegisterStructMaps

    master

    The RegisterStructMaps type allows you to map string names to Go types, enabling dynamic instantiation of structs by name. This is useful for deserializing behavior tree definitions where node types are identified by strings.

    Workflow

    1. Initialize: Create a new registry using NewRegisterStructMaps().
    2. Register: Map a name to a struct type using Register(name string, c interface{}). Note that c should be a pointer to the struct, as the registry uses reflect.TypeOf(c).Elem() to store the underlying type.
    3. Check: Verify if a type is registered using CheckElem(name string).
    4. Instantiate: Create a new instance of the registered type using New(name string). This returns an interface{} which you can type-assert to your desired struct pointer.
    import "github.com/magicsea/magicsea/behavior3go"
    
    type MyNode struct {
    	Value int
    }
    
    // 1. Initialize
    rsm := behavior3go.NewRegisterStructMaps()
    
    // 2. Register (pass a pointer to the struct)
    rsm.Register("MyNode", &MyNode{})
    
    // 3. Check
    if rsm.CheckElem("MyNode") {
    	// 4. Instantiate	instance, err := rsm.New("MyNode")
    	if err == nil {
    		// Type assert to the pointer type
    		node := instance.(*MyNode)
    		node.Value = 10
    	}
    }
  9. RegisterStructMaps API Reference

    master

    Methods available on the *RegisterStructMaps type:

    MethodSignatureDescription
    Newfunc (rsm *RegisterStructMaps) New(name string) (interface{}, error)Returns a new instance of the registered type as an interface{}. Returns an error if the name is not found.
    Registerfunc (rsm *RegisterStructMaps) Register(name string, c interface{})Registers a type under the provided name. The type is extracted from reflect.TypeOf(c).Elem().
    CheckElemfunc (rsm *RegisterStructMaps) CheckElem(name string) boolReturns true if a type is registered under the given name, false otherwise.
    NewRegisterStructMapsfunc NewRegisterStructMaps() *RegisterStructMapsConstructor that initializes an empty RegisterStructMaps instance.
  10. Identify Behavior Tree node categories

    master

    The library uses string constants to categorize different types of nodes within a behavior tree. These categories help define the structural role of a node:

    • COMPOSITE: Nodes that manage multiple children (e.g., Selector, Sequence).
    • DECORATOR: Nodes that wrap a single child to modify its behavior.
    • ACTION: Nodes that perform a specific task or effect.
    • CONDITION: Nodes that check a specific state or predicate.
    const (
    	COMPOSITE = "composite"
    	DECORATOR = "decorator"
    	ACTION    = "action"
    	CONDITION = "condition"
    )