class BehaviorTree::Builder

DSL for building a tree.

Public Class Methods

build(&block) click to toggle source
# File lib/behavior_tree/builder.rb, line 20
def build(&block)
  # Stack of lists. When a method like 'sequence' is executed, the resulting
  # sequence object will be stored in the last list. Then, the whole list will
  # be retrieved as the node children.
  @stack = []

  stack_children_from_block(block)
  tree_main_nodes = @stack.pop

  raise DSLStandardError, 'Tree main node should be a single node' if tree_main_nodes.count > 1

  raise 'Tree structure is incorrect. Probably a problem with the library.' unless @stack.empty?

  BehaviorTree::Tree.new tree_main_nodes.first
end

Private Class Methods

chain(node) click to toggle source
# File lib/behavior_tree/builder.rb, line 49
def chain(node)
  unless node.is_a?(NodeBase)
    raise DSLStandardError, "The 'chain' keyword must be used to chain a node or subtree, not a #{node.class}"
  end

  stack node
end
exec_leaf(node_class, args, block) click to toggle source
# File lib/behavior_tree/builder.rb, line 71
def exec_leaf(node_class, args, block)
  stack node_class.new(*args, &block)
end
exec_with_children(node_class, children_type, args, block) click to toggle source
# File lib/behavior_tree/builder.rb, line 61
def exec_with_children(node_class, children_type, args, block)
  stack_children_from_block(block)
  children_nodes = @stack.pop
  raise DSLStandardError, "Node #{node_class} has no children." if children_nodes.empty?

  final_args = [children_nodes] + args # @stack.pop is already an Array
  final_args.flatten! unless children_type == :multiple
  stack node_class.new(*final_args)
end
method_missing(name, *args, &block) click to toggle source
# File lib/behavior_tree/builder.rb, line 75
def method_missing(name, *args, &block)
  # Find by name or alias.
  node_class_name = @node_type_mapping.dig name, :class

  node_class = constantize(node_class_name)

  raise_node_type_not_exists name if node_class.nil?

  children = @node_type_mapping.dig(name.to_sym, :children)

  # Nodes that have children are executed differently from leaf nodes.
  if children == :none
    exec_leaf(node_class, args, block)
  else
    exec_with_children(node_class, children, args, block)
  end
end
respond_to_missing?(method_name, _include_private) click to toggle source
# File lib/behavior_tree/builder.rb, line 57
def respond_to_missing?(method_name, _include_private)
  @node_type_mapping.key? method_name
end
stack(obj) click to toggle source
# File lib/behavior_tree/builder.rb, line 38
def stack(obj)
  @stack.last << obj
end
stack_children_from_block(block) click to toggle source

Execute @stack.pop after executing this method to extract what was pushed.

# File lib/behavior_tree/builder.rb, line 44
def stack_children_from_block(block)
  @stack << []
  instance_eval(&block)
end