Lua 行为树实现

 1 BehaviorTreeNode = {}
 2
 3 BehaviorTreeNode.Type = {
 4     ACTION = "ACTION",
 5     CONDITION = "CONDITION",
 6     SELECTOR = "SELECTOR",
 7     SEQUENCE = "SEQUENCE"
 8 }
 9
10 function BehaviorTreeNode.new(name,type)
11     local node = {}
12
13     node.action_ = nil
14     node.children_ = {}
15     node.evaluator_ = nil
16     node.name_ = name or ""
17     node.parent_ = nil
18     node.type_ = type or BehaviorTreeNode.Type.ACTION
19
20     node.AddChild = BehaviorTreeNode.AddChild
21     node.ChildIndex = BehaviorTreeNode.ChildIndex
22     node.GetChild = BehaviorTreeNode.GetChild
23     node.GetNumberOfChildren = BehaviorTreeNode.GetNumberOfChildren
24
25     node.GetParent = BehaviorTreeNode.GetParent
26     node.SetAction = BehaviorTreeNode.SetAction
27     node.SetEvaluator = BehaviorTreeNode.SetEvaluator
28     node.SetType = BehaviorTreeNode.SetType
29
30     return node
31 end
32
33 function BehaviorTreeNode.AddChild(self,child,index)
34     index = index or (#self.children_ + 1)
35     table.insert(self.children_,index,child)
36     child.parent_ = self
37 end
38
39 function BehaviorTreeNode.ChildIndex(self,child)
40     for index = 1, #self.children_ do
41         if self.children_[index] == child then
42             return index
43         end
44     end
45
46     return -1
47 end
48
49 function BehaviorTreeNode.GetChild(self,childIndex)
50     return self.children_[childIndex]
51 end
52
53 function BehaviorTreeNode.GetNumberOfChildren(self)
54     return #self.children_
55 end
56
57 function BehaviorTreeNode.GetParent(self)
58     return self.parent_
59 end
60
61 function BehaviorTreeNode.SetAction(self,action)
62     self.action_ = action
63 end
64
65 function BehaviorTreeNode.SetEvaluator(self,evaluator)
66     self.evaluator_ = evaluator
67 end
68
69 function BehaviorTreeNode.SetType(self,type)
70     self.type_ = type
71 end

BehaviorTreeNode

  1 require "BehaviorTreeNode"
  2 require "Action"
  3
  4 BehaviorTree = {}
  5
  6 local _EvaluateSelector
  7 local _EvaluateSequence
  8
  9 function BehaviorTree.SetNode(self,node)
 10     self.node_ = node
 11 end
 12
 13 function BehaviorTree.new(userData)
 14     local tree = {}
 15
 16     tree.currentNode_ = nil
 17     tree.node_ = nil
 18     tree.userData_ = userData
 19
 20     tree.SetNode = BehaviorTree.SetNode
 21     tree.Update = BehaviorTree.Update
 22
 23     return tree
 24 end
 25
 26 _EvaluateSelector = function(self,node,deltaTimeInMillis)
 27     for index = 1,#node.children_ do
 28         local child = node:GetChild(index)
 29
 30         if child.type_ == BehaviorTreeNode.Type.ACTION then
 31             return {node = child,result = true}
 32         elseif child.type_ == BehaviorTreeNode.Type.CONDITION then
 33             assert(false)
 34             return {result = false}
 35         elseif child.type_ == BehaviorTreeNode.Type.SELECTOR then
 36             local result = _EvaluateSelector(self,child,deltaTimeInMillis)
 37
 38             if result.result then
 39                 return result
 40             end
 41         elseif child.type_ == BehaviorTreeNode.Type.SEQUENCE then
 42             local result = _EvaluateSequence(self,child,deltaTimeInMillis)
 43
 44             if result.result then
 45                 return result
 46             end
 47         end
 48
 49     end
 50
 51     return {result = false}
 52 end
 53
 54 _EvaluateSequence = function(self,node,deltaTimeInMillis,index)
 55
 56     index = index or 1
 57
 58     for count = index,#node.children_ do
 59         local child = node:GetChild(count)
 60
 61         if child.type_ == BehaviorTreeNode.Type.ACTION then
 62             return  { node = child,result = true }
 63         elseif child.type_ == BehaviorTreeNode.Type.CONDITION then
 64             local result = child.evaluator_(self.userData_)
 65
 66             if not result then
 67                 return {result = false}
 68             end
 69
 70         elseif child.type_ == BehaviorTreeNode.Type.SELECTOR then
 71             local result = _EvaluateSelector(self,child,deltaTimeInMillis)
 72
 73             if not result.result then
 74                 return {result = false}
 75             elseif result.result and result.node ~= nil then
 76                 return result
 77             end
 78         elseif child.type_ == BehaviorTreeNode.Type.SEQUENCE then
 79             local result = _EvaluateSequence(self,child,deltaTimeInMillis)
 80
 81             if not result.result then
 82                 return {result = false}
 83             elseif result.result and result.node ~= nil then
 84                 return result
 85             end
 86
 87         end
 88
 89         count = count + 1
 90
 91     end
 92
 93     return {result = true}
 94 end
 95
 96 local function _EvaluateNode(self,node,deltaTimeInMillis)
 97     if node.type_ == BehaviorTreeNode.Type.ACTION then
 98         return node
 99     elseif node.type_ == BehaviorTreeNode.Type.CONDITION then
100         assert(false)
101     elseif node.type_ == BehaviorTreeNode.Type.SELECTOR then
102         local result = _EvaluateSelector(self,node,deltaTimeInMillis)
103
104         if result.result then
105             return result.node
106         end
107     elseif node.type_ == BehaviorTreeNode.Type.SEQUENCE then
108         local result = _EvaluateSequence(self,node,deltaTimeInMillis)
109
110         if result.result then
111             return result.node
112         end
113     end
114 end
115
116 local function _ContinueEvaluation(self,node,deltaTimeInMillis)
117     local parentNode = node:GetParent()
118     local childNode = node
119     while parentNode ~= nil do
120         if parentNode.type_ == BehaviorTreeNode.Type.SEQUENCE then
121             local childIndex = parentNode:ChildIndex(childNode)
122
123             if childIndex < parentNode:GetNumberOfChildren() then
124                 local result = _EvaluateSequence(self,parentNode,deltaTimeInMillis,childIndex + 1)
125
126                 if result.result then
127                     return result.node
128                 end
129             end
130         end
131
132         childNode = parentNode
133         parentNode = childNode:GetParent()
134     end
135 end
136
137 function BehaviorTree.Update(self,deltaTimeInMillis)
138     if self.currentNode_ == nil then
139         self.currentNode_ = _EvaluateNode(self,self.node_,deltaTimeInMillis)
140     end
141
142     if self.currentNode_ ~= nil then
143         local status = self.currentNode_.action_.status_
144         if status == Action.Status.UNINIIALIZED then
145             self.currentNode_.action_:Initialize()
146         elseif status == Action.Status.TERMINATED then
147             self.currentNode_.action_:CleanUp()
148
149             self.currentNode_ = _ContinueEvaluation(self,self.currentNode_,deltaTimeInMillis)
150
151         elseif status == Action.Status.RUNNING then
152             self.currentNode_.action_:Update(deltaTimeInMillis)
153         end
154     end
155 end

BehaviorTree

 1 Action = {}
 2
 3 Action.Status = {
 4     RUNNING = "RUNNING",
 5     TERMINATED = "TERMINATED",
 6     UNINIIALIZED = "UNINIIALIZED"
 7 }
 8
 9 Action.Type = "Action"
10
11
12 function Action.new(name,initializeFunction,updateFunction,cleanUpFunction,userData)
13
14     local action = {}
15
16     action.cleanUpFunction_ = cleanUpFunction
17     action.initializeFunction_ = initializeFunction
18     action.updateFunction_  = updateFunction
19     action.name_ = name or ""
20     action.status_ = Action.Status.UNINIIALIZED
21     action.type_ = Action.Type
22     action.userData_ = userData
23
24     action.CleanUp = Action.CleanUp
25     action.Initialize = Action.Initialize
26     action.Update = Action.Update
27
28     return action
29 end
30
31 function Action.Initialize(self)
32     if self.status_ == Action.Status.UNINIIALIZED then
33         if self.initializeFunction_ then
34             self.initializeFunction_(self.userData_)
35         end
36     end
37
38     self.status_ = Action.Status.RUNNING
39 end
40
41
42 function Action.Update(self,deltaTimeInMillis)
43     if self.status_ == Action.Status.TERMINATED then
44         return Action.Status.TERMINATED
45     elseif self.status_ == Action.Status.RUNNING then
46         if self.updateFunction_ then
47             self.status_ = self.updateFunction_(deltaTimeInMillis,self.userData_)
48
49             assert(self.status_)
50         else
51             self.status_ = Action.Status.TERMINATED
52         end
53     end
54
55     return self.status_
56
57 end
58 function Action.CleanUp(self)
59     if self.status_ == Action.Status.TERMINATED then
60         if self.cleanUpFunction_ then
61             self.cleanUpFunction_(self.userData_)
62         end
63     end
64
65     self.status_ = Action.Status.UNINIIALIZED
66 end

Action

时间: 2024-10-27 11:08:29

Lua 行为树实现的相关文章

[Unity插件]Lua行为树(四):条件节点和行为节点

条件节点和行为节点,这两种节点本身的设计比较简单,项目中编写行为树节点一般就是扩展这两种节点,而Decorator和Composite节点只需要使用内置的就足够了. 它们的继承关系如下: Conditional->Task Action->Task 代码如下: BTAction.lua 1 BTAction = BTTask:New(); 2 3 local this = BTAction; 4 5 function this:New() 6 local o = {}; 7 setmetata

lua行为树设计与实现

项目需要,之前行为树用的是behaviorDesigner,要改成纯lua的 我先做了一版用递归实现,代码可读性高但是中断机制实现起来比较复杂,而且创建自定义action重写方法时需要调用父类的方法, 如果忘了调用就会出现问题, 所以改成了用栈模拟递归. 用栈模拟递归好处在于效率高,并且容易控制,用非递归实现后自定义一个行为树节点,那么该节点不用知道父亲的方法,只要做好自己的事情就OK了 完整测试工程已上传到了github:https://github.com/MCxYY/LuaBT 行为树整体

[Unity插件]Lua行为树(十):通用行为和通用条件节点

在行为树中,需要扩展的主要是行为节点和条件节点.一般来说,每当要创建一个节点时,就要新建一个节点文件.而对于一些简单的行为节点和条件节点,为了去掉新建文件的过程,可以写一个通用版本的行为节点和条件节点,以传入方法的方式来避免新建文件. BTActionUniversal.lua 1 --[[ 2 通用Action节点 3 --]] 4 BTActionUniversal = BTAction:New(); 5 6 local this = BTActionUniversal; 7 this.na

【Lua】Lua + LWT + ExtJS构建目录树

Lua处理后台逻辑,Lua lwt搭建后台程序,ExtJS根据后台传来的json数据构建目录树. 前台html和ExtJS代码不用多讲,直接上代码: treePanel.html 1 <html> 2 <head> 3 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 4 5 <title>ExtJS TreePanel</

lua 如何输出树状结构的table?

为了让游戏前端数据输出更加条理,做了一个简单树状结构来打印数据. ccmlog.lua local function __tostring(value, indent, vmap) local str = '' indent = indent or '' vmap = vmap or {} --递归结束条件 if (type(value) ~= 'table') then if (type(value) == 'string') then --字符串 str = string.format("[

lua 怎样输出树状结构的table?

为了让游戏前端数据输出更加条理,做了一个简单树状结构来打印数据. ccmlog.lua local function __tostring(value, indent, vmap) local str = '' indent = indent or '' vmap = vmap or {} --递归结束条件 if (type(value) ~= 'table') then if (type(value) == 'string') then --字符串 str = string.format("[

Behavior Tree 用 Lua 实现一个最简行为树

1 local SELECTOR = 1 2 local SEQUENCE = 2 3 local CONDITION = 3 4 local ACTION = 4 5 6 local function Traverse(node, ...) 7 local t = node.type 8 if t == SELECTOR then 9 for i=1, #node do 10 if Traverse(node[i], ...) then 11 return true 12 end 13 end

Lua总结一

值和类型(Values and Types) Lua是一门动态类型语言,这意味着变量没有类型,只有值有类型.语言没有类型定义,所有值携带自己的类型. Lua中所有的值都是一等公民,这意味着所有的值都可以存储在变量中,作为参数传递给其他函数,作为函数的结果返回. 值得注意的是这点对函数也成立,在Java中函数是没这个待遇的.比如对一个列表排序,需要一个比较函数,Lua可以直接传递比较函数,而Java需要为这个比较函数创建一个类型,然后传递这个类型的实例. 来看一个例子,将一个列表从大到小排列: L

【Lua】LWT后台用JSON与 ExtJS传递数据

要完成目录树的构建,需要前台ExtJS构筑页面,后台处理逻辑,中间由JSON传递数据. 首先搭建后台环境: 1 require "httpd" 2 require "lfs" 3 4 request, args = ... 5 6 local s = {root = { 7 text = "rootNode", 8 expanded = true, 9 children = { 10 { 11 text = 'book1', 12 leaf =