Behavior Tree

Behavior Tree in Editor

This is experimental. A Behavior tree implemetation enables a conditional call for an action node. If conditions are not satisfied for a button, the associated action to the button will not be executed when user clicks it

editor/controller/BTree/selectors.tree

BTree calls BThandler when actionNode is activated. The parameters are stored in backboard.

  • editor.index

    M.commands = {
      {name="selectApp", btree=nil},
      {name="selectBook", btree="load book"},
      {name="selectPage", btree="load page"},
      {name="selectLayer", btree="load layer"},
      {name="selectPageIcons", btree=nil},
      -- {name="selectAction", btree=""},
      {name="selectTool", btree="editor component"},
      -- {name="selectActionCommand", btree=""}
      {name="selectAudio", btree="load audio"},
      {name="selectGroup", btree="load group"},
      {name="selectTimer", btree="load timer"},
      {name="selectVariable", btree="load variable"},
      -- {name="selectVideo", btree="load video"},
    
    }
    
    -- connects with BTree ----
    local BTMap = {}
    for i=1, #M.commands do
      if M.commands[i].btree then
        BTMap[M.commands[i].btree] ={eventName = "editor.selector."..M.commands[i].name, name = M.commands[i].name}
      end
    end
    -- BTree calls this when activating actionNode
    M.BThandler = function(name, status)
      --  print("#BTHandler: dispathEvent")
      --  print("", name,  bt.getFriendlyStatus( nil,status ))
      local target = BTMap[name]
      -- print("", target)
      if  target then
        --  print("", target.eventName)
        --local obj = M.UI.editor.sceneGroup[target.name]
        local params = {
          name = target.eventName,
          UI = M.UI, -- beaware UI is belonged to a page
          -- show = not obj.isVisible,
        }
        if tree.backboard then
          for k, v in pairs(tree.backboard) do
            params[k] = v
          end
        end
        M.UI.scene.app:dispatchEvent(params)
      end
      return bt.SUCCESS
    end

  1. editor/index.lua

    Add {name = “selectXXX”, btree= “load xxx”}

    M.commands = {{name="selectApp", btree=nil},
      {name="selectBook", btree="load book"},
      {name="selectPage", btree="load page"},
      {name="selectLayer", btree="load layer"},
      -- {name="selectAction", btree=""},
      {name="selectTool", btree="editor component"},
      -- {name="selectActionCommand", btree=""}
      {name="selectAudio", btree="load audio"},
      {name="selectGroup", btree="load group"},
      -- {name="selectTimer", btree="load timer"},
      -- {name="selectVariable", btree="load variable"},
      -- {name="selectVideo", btree="load video"},
    }
  2. new xxxTable out of baseTable.lua

    write like this

    local name = ...
    local parent = name:match("(.-)[^%.]+$")
    
    local Props = {
      name = "group",
      anchorName = "selectGroup",
      icons = {"Groups", "trash"},
      id = "group"
    }
    
    local M = require(parent.."baseTable").new(Props)
    return M

    this baseTable fires “load xxx” with a selected entry in xxxTable when user clicks it

    baseTable.lua

      tree.backboard = {
        show = true,
        class = target.class
      }
    
      tree.backboard[self.name] = target[self.name],
    
      tree:setConditionStatus("select component", bt.SUCCESS, true)
      tree:setActionStatus("load "..self.name, bt.RUNNING, true)
      tree:setConditionStatus("select "..self.name, bt.SUCCESS)

    then next, this tree action (load xxx) is called back. It is linked to selectXXX command by editor/index.lua. commands/selectors/selectXXX to load a json of a selected entry

    • TBI - setAction should be placed in an actionH handler. with setActionStatus SUCESS or RUNNING. SUCESS will proceed the bt path to the next node.

      see layerTableCommands.lua showClassProps.

      • true to skip ticking

      • bt.FAILED proceeds the next condition node of Or grouped nodes.

        in vs code bt extesion’s prview, click with holding shift key to change the status to fail

      tree.backboard = {
        layer = target.layer,
        class = target.class,
        path = path
      }
      tree:setConditionStatus("select layer", bt.SUCCESS, true)
      tree:setActionStatus("load layer", bt.RUNNING) -- need tick to process load layer with tree.backboard
      tree:setConditionStatus("select props", bt.FAILED, true)
      
      -- For editor compoent. this fires selectTool event with backboard params
      tree.backboard = {
        class = target.class,
        isNew = false,
        layer = target.layer,
        path = path
      }
      tree:setConditionStatus("modify component", bt.SUCCESS)
      tree:setActionStatus("editor component", bt.RUNNING, true)
  • assetTable does not use the bt. See assetTableListener:touchHandler()

BT will be better if add key-event conditions, and then handler fucntions could remove ‘if’. All the props of handlers should be put in backboard, if all the conditions are defined in the tree, BT handler aggrigates all conditions with bt.SUCESS and actionStatus with bt.Running to rertive a final action node. Then action node is processed in a command function by eventDispatch

BT will be useful for an async event. Until a setCondition with true of an async event, BT won’t fire an action.

event input from buttons or any functions, handler just use setCondition, BT will retrive an action node.