mirror of
https://github.com/TangentFoxy/Behave.git
synced 2024-11-15 11:04:21 +00:00
replaced w better implementation
This commit is contained in:
parent
b34b6c8bc5
commit
6455230334
152
ReadMe.md
152
ReadMe.md
@ -1,105 +1,87 @@
|
||||
# Behave
|
||||
|
||||
A simple implementation of behavior trees in MoonScript / Lua.
|
||||
A simple implementation of behavior trees in MoonScript / Lua. Define behaviors
|
||||
as functions or small tables, then call `behave.make` on them to get a function
|
||||
you can call repeatedly to execute behaviors.
|
||||
|
||||
A node should return a truthy or falsy value to indicate success or failure, or
|
||||
`behave.running` to indicate that the node needs to be called again to continue
|
||||
running.
|
||||
|
||||
Examples are in MoonScript, but shouldn't be too difficult to understand even if
|
||||
you are unfamiliar with its syntax.
|
||||
|
||||
## Example
|
||||
|
||||
(Note: The top example and last example work. The others are from experimenting
|
||||
with ideas about how to make it easier to write code interfacing with this
|
||||
library.)
|
||||
```
|
||||
TODO
|
||||
```
|
||||
|
||||
## Leaf Nodes
|
||||
|
||||
The easiest node is just a function that will be passed all arguments sent to a
|
||||
behavior tree it is part of. There is a slightly more complex leaf node for
|
||||
maintaining an internal state, and optional `start`/`finish` functions only
|
||||
called at the beginning and end of processing.
|
||||
|
||||
```
|
||||
bt = require "behave"
|
||||
|
||||
tree = bt.Sequence({
|
||||
bt.Node({
|
||||
run = function(self, obj, ...)
|
||||
-- do stuff
|
||||
end,
|
||||
finish = function(self, obj, ...)
|
||||
-- finish up
|
||||
end
|
||||
}),
|
||||
bt.Random({
|
||||
bt.Node({
|
||||
-- add some functions
|
||||
}),
|
||||
bt.Node({
|
||||
-- even more functionality!
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
tree:addObject(obj)
|
||||
tree:update(obj)
|
||||
|
||||
node1 = {
|
||||
-- pretend this has run/finish functions or whatever
|
||||
WalkPath = {
|
||||
start: (state, entity) ->
|
||||
state.path = findPath(entity, entity.target)
|
||||
return state.path
|
||||
run: (state, entity) ->
|
||||
-- this will not run if start fails
|
||||
state.path.step!
|
||||
finish: (state, entity) ->
|
||||
-- this will run only if run returns a truthy value besides behave.running
|
||||
state.path = nil
|
||||
}
|
||||
node2 = {} -- same
|
||||
bt.Make ({
|
||||
"Sequence",
|
||||
node1, node2, {
|
||||
"Random",
|
||||
node3, node4 -- these are in 'Random'
|
||||
}
|
||||
})
|
||||
|
||||
tree = bt.Factory({
|
||||
"Sequence",
|
||||
{
|
||||
"Node",
|
||||
{
|
||||
run = function(self) end,
|
||||
finish = function(self) end
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
node1 = bt.Node()
|
||||
function node1:run()
|
||||
-- do stuff!
|
||||
end
|
||||
```
|
||||
|
||||
## The Leaf Node
|
||||
## The Decorator Node
|
||||
|
||||
`Node` accepts a table of values to be set on it. It expects a `run` function,
|
||||
and optionally a `start` and a `finish` function, which will only be run at the
|
||||
beginning and end of a node being run (whereas `run` can be called multiple
|
||||
times).
|
||||
A very basic extension to the result of a leaf node, allowing you to alter the
|
||||
result it returns. Note: You cannot alter a `behave.running` return.
|
||||
|
||||
To run a behavior tree, call `update` on itself, with optional arguments (which
|
||||
will be passed to their children as they are called).
|
||||
```
|
||||
InvertSomeNode = {
|
||||
decorator: (result) ->
|
||||
return not result
|
||||
SomeNode
|
||||
}
|
||||
```
|
||||
|
||||
## Composite Nodes
|
||||
|
||||
Pass a table of nodes to these to set their contents. All composite nodes repeat
|
||||
after the entire tree has been processed.
|
||||
Selector skips any failures and returns on the first node that returns a truthy
|
||||
value (or returns `false` if nothing succeeds). Sequence continues until there
|
||||
is a failure or returns success. Random executes a random node underneath it.
|
||||
|
||||
- Composite: Super class of the other composite nodes.
|
||||
- Sequence: Runs children until a failure or success of all.
|
||||
- Selector: Runs children until a success or failure of all.
|
||||
- Random: Runs a random child and returns its result.
|
||||
- RandomSequence: Randomizes the order of its children, then acts like a
|
||||
Sequence.
|
||||
- RandomSelector: Randomizes the order of its children, then acts like a
|
||||
Selector.
|
||||
```
|
||||
Behaviors = {
|
||||
type: behave.Random
|
||||
WalkRandomly, LookAtPhone, LeaveArea
|
||||
}
|
||||
```
|
||||
|
||||
## Decorator Nodes
|
||||
## Custom Nodes
|
||||
|
||||
Pass a single node to these, except for `Repeat`, which needs a number followed
|
||||
by a node. All decorator nodes (except `RunOnce`) repeat after the entire tree
|
||||
has been processed.
|
||||
You can create custom nodes and easily use them. Rather than explaining how to,
|
||||
here's an example:
|
||||
|
||||
- Decorator: Superclass. Just returns the result of its child node.
|
||||
- Repeat: Repeats a node a specified number of times, fails if the node fails.
|
||||
- Succeed: Runs a node and returns success.
|
||||
- Fail: Runs a node and returns failure.
|
||||
- Invert: Runs a node, reporting a success on fail, and failure on success.
|
||||
- RunOnce: Runs a node, reporting its results, and fail after that.
|
||||
```
|
||||
-- defining the node type:
|
||||
Invert = (tab) -> -- your fn will be passed a table describing the node
|
||||
node = behave.make tab[1] -- call make on any sub-nodes that you will be using, save the result
|
||||
return (...) -> -- use variable arguments, so sub-nodes can
|
||||
result = node(...) -- get what they need
|
||||
unless result == behave.running -- running nodes should not be interrupted
|
||||
result = not result -- and finally we invert the result before
|
||||
return result -- returning it
|
||||
|
||||
## Return Values
|
||||
|
||||
Within the module, `success`, `running`, and `fail` are defined. They are also
|
||||
present on all nodes (so you can use `self.success` and such).
|
||||
-- using the node type:
|
||||
SomeInvertedNode = {
|
||||
type: Invert -- this is how the library knows what function to call
|
||||
SomeNode -- this is the node that will be inverted
|
||||
}
|
||||
```
|
||||
|
904
behave.lua
904
behave.lua
@ -1,845 +1,129 @@
|
||||
local success = setmetatable({ }, {
|
||||
__tostring = function()
|
||||
return "success"
|
||||
end
|
||||
})
|
||||
local make, Node, Decorate
|
||||
local running = setmetatable({ }, {
|
||||
__tostring = function()
|
||||
return "running"
|
||||
end
|
||||
})
|
||||
local fail = setmetatable({ }, {
|
||||
__tostring = function()
|
||||
return "fail"
|
||||
local get_nodes
|
||||
get_nodes = function(tab)
|
||||
local nodes = { }
|
||||
for _index_0 = 1, #tab do
|
||||
local node = tab[_index_0]
|
||||
table.insert(nodes, make(node))
|
||||
end
|
||||
})
|
||||
local Node
|
||||
do
|
||||
local _class_0
|
||||
local _base_0 = {
|
||||
addObject = function(self, obj)
|
||||
obj[self.u] = {
|
||||
started = false
|
||||
}
|
||||
end,
|
||||
run = function(self)
|
||||
return success
|
||||
end,
|
||||
update = function(self, obj, ...)
|
||||
local result = success
|
||||
if not obj[self.u].started and self.start then
|
||||
result = self:start(obj, ...)
|
||||
obj[self.u].started = true
|
||||
end
|
||||
if result == success then
|
||||
result = self:run(obj, ...)
|
||||
end
|
||||
if result == success then
|
||||
if self.finish then
|
||||
result = self:finish(obj, ...)
|
||||
end
|
||||
obj[self.u].started = false
|
||||
end
|
||||
return result
|
||||
end
|
||||
}
|
||||
_base_0.__index = _base_0
|
||||
_class_0 = setmetatable({
|
||||
__init = function(self, fns)
|
||||
if fns == nil then
|
||||
fns = { }
|
||||
end
|
||||
for key, value in pairs(fns) do
|
||||
self[key] = value
|
||||
end
|
||||
self.success = success
|
||||
self.running = running
|
||||
self.fail = fail
|
||||
self.u = { }
|
||||
end,
|
||||
__base = _base_0,
|
||||
__name = "Node"
|
||||
}, {
|
||||
__index = _base_0,
|
||||
__call = function(cls, ...)
|
||||
local _self_0 = setmetatable({}, _base_0)
|
||||
cls.__init(_self_0, ...)
|
||||
return _self_0
|
||||
end
|
||||
})
|
||||
_base_0.__class = _class_0
|
||||
Node = _class_0
|
||||
return nodes
|
||||
end
|
||||
local Composite
|
||||
do
|
||||
local _class_0
|
||||
local _parent_0 = Node
|
||||
local _base_0 = {
|
||||
addObject = function(self, obj)
|
||||
local _list_0 = self.nodes
|
||||
for _index_0 = 1, #_list_0 do
|
||||
local node = _list_0[_index_0]
|
||||
node:addObject(obj)
|
||||
end
|
||||
end
|
||||
}
|
||||
_base_0.__index = _base_0
|
||||
setmetatable(_base_0, _parent_0.__base)
|
||||
_class_0 = setmetatable({
|
||||
__init = function(self, nodes)
|
||||
if nodes == nil then
|
||||
nodes = { }
|
||||
end
|
||||
self.nodes = nodes
|
||||
return _class_0.__parent.__init(self)
|
||||
end,
|
||||
__base = _base_0,
|
||||
__name = "Composite",
|
||||
__parent = _parent_0
|
||||
}, {
|
||||
__index = function(cls, name)
|
||||
local val = rawget(_base_0, name)
|
||||
if val == nil then
|
||||
local parent = rawget(cls, "__parent")
|
||||
if parent then
|
||||
return parent[name]
|
||||
end
|
||||
else
|
||||
return val
|
||||
end
|
||||
end,
|
||||
__call = function(cls, ...)
|
||||
local _self_0 = setmetatable({}, _base_0)
|
||||
cls.__init(_self_0, ...)
|
||||
return _self_0
|
||||
end
|
||||
})
|
||||
_base_0.__class = _class_0
|
||||
if _parent_0.__inherited then
|
||||
_parent_0.__inherited(_parent_0, _class_0)
|
||||
make = function(tab)
|
||||
if "function" == type(tab) then
|
||||
return tab
|
||||
elseif "function" == type(tab.type) then
|
||||
return tab.type(tab)
|
||||
elseif tab.decorate then
|
||||
return Decorate(tab)
|
||||
else
|
||||
return Node(tab)
|
||||
end
|
||||
Composite = _class_0
|
||||
end
|
||||
local Sequence
|
||||
do
|
||||
local _class_0
|
||||
local _parent_0 = Composite
|
||||
local _base_0 = {
|
||||
addObject = function(self, obj)
|
||||
_class_0.__parent.__base.addObject(self)
|
||||
obj[self.u] = {
|
||||
index = 0,
|
||||
running = 0
|
||||
}
|
||||
end,
|
||||
update = function(self, obj, ...)
|
||||
local result = success
|
||||
if obj[self.u].running then
|
||||
result = obj[self.u].running:update(obj, ...)
|
||||
if not (result == running) then
|
||||
obj[self.u].running = false
|
||||
end
|
||||
Node = function(tab)
|
||||
local state, started = { }, false
|
||||
return function(...)
|
||||
local result
|
||||
if not (started) then
|
||||
if tab.start then
|
||||
result = tab.start(state, ...)
|
||||
end
|
||||
while result == success and obj[self.u].index < #self.nodes do
|
||||
obj[self.u].index = obj[self.u].index + 1
|
||||
result = self.nodes[obj[self.u].index]:update(obj, ...)
|
||||
if not (result == false) then
|
||||
started = true
|
||||
end
|
||||
if result == running then
|
||||
obj[self.u].running = self.nodes[obj[self.u].index]
|
||||
else
|
||||
obj[self.u].index = 0
|
||||
end
|
||||
return result
|
||||
end
|
||||
}
|
||||
_base_0.__index = _base_0
|
||||
setmetatable(_base_0, _parent_0.__base)
|
||||
_class_0 = setmetatable({
|
||||
__init = function(self, ...)
|
||||
return _class_0.__parent.__init(self, ...)
|
||||
end,
|
||||
__base = _base_0,
|
||||
__name = "Sequence",
|
||||
__parent = _parent_0
|
||||
}, {
|
||||
__index = function(cls, name)
|
||||
local val = rawget(_base_0, name)
|
||||
if val == nil then
|
||||
local parent = rawget(cls, "__parent")
|
||||
if parent then
|
||||
return parent[name]
|
||||
end
|
||||
else
|
||||
return val
|
||||
end
|
||||
end,
|
||||
__call = function(cls, ...)
|
||||
local _self_0 = setmetatable({}, _base_0)
|
||||
cls.__init(_self_0, ...)
|
||||
return _self_0
|
||||
if not (result == false) then
|
||||
result = tab.run(state, ...)
|
||||
end
|
||||
})
|
||||
_base_0.__class = _class_0
|
||||
if _parent_0.__inherited then
|
||||
_parent_0.__inherited(_parent_0, _class_0)
|
||||
if result ~= running then
|
||||
started = false
|
||||
if result and tab.finish then
|
||||
result = tab.finish(state, ...)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
Sequence = _class_0
|
||||
end
|
||||
local Selector
|
||||
do
|
||||
local _class_0
|
||||
local _parent_0 = Composite
|
||||
local _base_0 = {
|
||||
addObject = function(self, obj)
|
||||
_class_0.__parent.__base.addObject(self)
|
||||
obj[self.u] = {
|
||||
index = 0,
|
||||
running = 0
|
||||
}
|
||||
end,
|
||||
update = function(self, obj, ...)
|
||||
local result = fail
|
||||
if obj[self.u].running then
|
||||
result = obj[self.u].running:update(obj, ...)
|
||||
if not (result == running) then
|
||||
obj[self.u].running = false
|
||||
end
|
||||
end
|
||||
while result == fail and obj[self.u].index < #self.nodes do
|
||||
obj[self.u].index = obj[self.u].index + 1
|
||||
result = self.nodes[obj[self.u].index]:update(obj, ...)
|
||||
end
|
||||
if result == running then
|
||||
obj[self.u].running = self.nodes[obj[self.u].index]
|
||||
else
|
||||
obj[self.u].index = 0
|
||||
end
|
||||
return result
|
||||
end
|
||||
}
|
||||
_base_0.__index = _base_0
|
||||
setmetatable(_base_0, _parent_0.__base)
|
||||
_class_0 = setmetatable({
|
||||
__init = function(self, ...)
|
||||
return _class_0.__parent.__init(self, ...)
|
||||
end,
|
||||
__base = _base_0,
|
||||
__name = "Selector",
|
||||
__parent = _parent_0
|
||||
}, {
|
||||
__index = function(cls, name)
|
||||
local val = rawget(_base_0, name)
|
||||
if val == nil then
|
||||
local parent = rawget(cls, "__parent")
|
||||
if parent then
|
||||
return parent[name]
|
||||
end
|
||||
else
|
||||
return val
|
||||
end
|
||||
end,
|
||||
__call = function(cls, ...)
|
||||
local _self_0 = setmetatable({}, _base_0)
|
||||
cls.__init(_self_0, ...)
|
||||
return _self_0
|
||||
end
|
||||
})
|
||||
_base_0.__class = _class_0
|
||||
if _parent_0.__inherited then
|
||||
_parent_0.__inherited(_parent_0, _class_0)
|
||||
end
|
||||
Selector = _class_0
|
||||
end
|
||||
local Random
|
||||
do
|
||||
local _class_0
|
||||
local _parent_0 = Composite
|
||||
local _base_0 = {
|
||||
update = function(self, obj, ...)
|
||||
local index = math.floor(math.random() * #self.nodes + 1)
|
||||
return self.nodes[index]:update(obj, ...)
|
||||
end
|
||||
}
|
||||
_base_0.__index = _base_0
|
||||
setmetatable(_base_0, _parent_0.__base)
|
||||
_class_0 = setmetatable({
|
||||
__init = function(self, ...)
|
||||
return _class_0.__parent.__init(self, ...)
|
||||
end,
|
||||
__base = _base_0,
|
||||
__name = "Random",
|
||||
__parent = _parent_0
|
||||
}, {
|
||||
__index = function(cls, name)
|
||||
local val = rawget(_base_0, name)
|
||||
if val == nil then
|
||||
local parent = rawget(cls, "__parent")
|
||||
if parent then
|
||||
return parent[name]
|
||||
end
|
||||
else
|
||||
return val
|
||||
end
|
||||
end,
|
||||
__call = function(cls, ...)
|
||||
local _self_0 = setmetatable({}, _base_0)
|
||||
cls.__init(_self_0, ...)
|
||||
return _self_0
|
||||
end
|
||||
})
|
||||
_base_0.__class = _class_0
|
||||
if _parent_0.__inherited then
|
||||
_parent_0.__inherited(_parent_0, _class_0)
|
||||
end
|
||||
Random = _class_0
|
||||
end
|
||||
local Randomizer
|
||||
do
|
||||
local _class_0
|
||||
local _parent_0 = Composite
|
||||
local _base_0 = {
|
||||
addObject = function(self, obj)
|
||||
_class_0.__parent.__base.addObject(self)
|
||||
obj[self.u] = {
|
||||
running = false
|
||||
}
|
||||
return self:shuffle(obj)
|
||||
end,
|
||||
shuffle = function(self, obj)
|
||||
obj[self.u].shuffledNodes = { }
|
||||
for i = 1, #self.nodes do
|
||||
local r = math.random(i)
|
||||
if not (r == i) then
|
||||
obj[self.u].shuffledNodes[i] = obj[self.u].shuffledNodes[r]
|
||||
end
|
||||
obj[self.u].shuffledNodes[r] = self.nodes[i]
|
||||
end
|
||||
end
|
||||
}
|
||||
_base_0.__index = _base_0
|
||||
setmetatable(_base_0, _parent_0.__base)
|
||||
_class_0 = setmetatable({
|
||||
__init = function(self, ...)
|
||||
return _class_0.__parent.__init(self, ...)
|
||||
end,
|
||||
__base = _base_0,
|
||||
__name = "Randomizer",
|
||||
__parent = _parent_0
|
||||
}, {
|
||||
__index = function(cls, name)
|
||||
local val = rawget(_base_0, name)
|
||||
if val == nil then
|
||||
local parent = rawget(cls, "__parent")
|
||||
if parent then
|
||||
return parent[name]
|
||||
end
|
||||
else
|
||||
return val
|
||||
end
|
||||
end,
|
||||
__call = function(cls, ...)
|
||||
local _self_0 = setmetatable({}, _base_0)
|
||||
cls.__init(_self_0, ...)
|
||||
return _self_0
|
||||
end
|
||||
})
|
||||
_base_0.__class = _class_0
|
||||
if _parent_0.__inherited then
|
||||
_parent_0.__inherited(_parent_0, _class_0)
|
||||
end
|
||||
Randomizer = _class_0
|
||||
end
|
||||
local RandomSequence
|
||||
do
|
||||
local _class_0
|
||||
local _parent_0 = Randomizer
|
||||
local _base_0 = {
|
||||
update = function(self, obj, ...)
|
||||
local result = success
|
||||
if obj[self.u].running then
|
||||
result = obj[self.u].running:update(obj, ...)
|
||||
if not (result == running) then
|
||||
obj[self.u].running = false
|
||||
end
|
||||
end
|
||||
local tmp
|
||||
while result == success and #obj[self.u].shuffledNodes > 0 do
|
||||
result = obj[self.u].shuffledNodes[1]:update(obj, ...)
|
||||
tmp = table.remove(obj[self.u].shuffledNodes, 1)
|
||||
end
|
||||
if result == running then
|
||||
obj[self.u].running = tmp
|
||||
else
|
||||
self:shuffle(obj)
|
||||
end
|
||||
return result
|
||||
end
|
||||
}
|
||||
_base_0.__index = _base_0
|
||||
setmetatable(_base_0, _parent_0.__base)
|
||||
_class_0 = setmetatable({
|
||||
__init = function(self, ...)
|
||||
return _class_0.__parent.__init(self, ...)
|
||||
end,
|
||||
__base = _base_0,
|
||||
__name = "RandomSequence",
|
||||
__parent = _parent_0
|
||||
}, {
|
||||
__index = function(cls, name)
|
||||
local val = rawget(_base_0, name)
|
||||
if val == nil then
|
||||
local parent = rawget(cls, "__parent")
|
||||
if parent then
|
||||
return parent[name]
|
||||
end
|
||||
else
|
||||
return val
|
||||
end
|
||||
end,
|
||||
__call = function(cls, ...)
|
||||
local _self_0 = setmetatable({}, _base_0)
|
||||
cls.__init(_self_0, ...)
|
||||
return _self_0
|
||||
end
|
||||
})
|
||||
_base_0.__class = _class_0
|
||||
if _parent_0.__inherited then
|
||||
_parent_0.__inherited(_parent_0, _class_0)
|
||||
end
|
||||
RandomSequence = _class_0
|
||||
end
|
||||
local RandomSelector
|
||||
do
|
||||
local _class_0
|
||||
local _parent_0 = Randomizer
|
||||
local _base_0 = {
|
||||
update = function(self, obj, ...)
|
||||
local result = fail
|
||||
if obj[self.u].running then
|
||||
result = obj[self.u].running:update(obj, ...)
|
||||
if not (result == running) then
|
||||
obj[self.u].running = false
|
||||
end
|
||||
end
|
||||
local tmp
|
||||
while result == fail and #obj[self.u].shuffledNodes > 0 do
|
||||
result = obj[self.u].shuffledNodes[1]:update(obj, ...)
|
||||
tmp = table.remove(obj[self.u].shuffledNodes, 1)
|
||||
end
|
||||
if result == running then
|
||||
obj[self.u].running = tmp
|
||||
else
|
||||
self:shuffle()
|
||||
end
|
||||
return result
|
||||
end
|
||||
}
|
||||
_base_0.__index = _base_0
|
||||
setmetatable(_base_0, _parent_0.__base)
|
||||
_class_0 = setmetatable({
|
||||
__init = function(self, ...)
|
||||
return _class_0.__parent.__init(self, ...)
|
||||
end,
|
||||
__base = _base_0,
|
||||
__name = "RandomSelector",
|
||||
__parent = _parent_0
|
||||
}, {
|
||||
__index = function(cls, name)
|
||||
local val = rawget(_base_0, name)
|
||||
if val == nil then
|
||||
local parent = rawget(cls, "__parent")
|
||||
if parent then
|
||||
return parent[name]
|
||||
end
|
||||
else
|
||||
return val
|
||||
end
|
||||
end,
|
||||
__call = function(cls, ...)
|
||||
local _self_0 = setmetatable({}, _base_0)
|
||||
cls.__init(_self_0, ...)
|
||||
return _self_0
|
||||
end
|
||||
})
|
||||
_base_0.__class = _class_0
|
||||
if _parent_0.__inherited then
|
||||
_parent_0.__inherited(_parent_0, _class_0)
|
||||
end
|
||||
RandomSelector = _class_0
|
||||
end
|
||||
local Decorator
|
||||
do
|
||||
local _class_0
|
||||
local _parent_0 = Node
|
||||
local _base_0 = {
|
||||
addObject = function(self, obj)
|
||||
return self.node:addObject(obj)
|
||||
end,
|
||||
update = function(self, obj, ...)
|
||||
return self.node:update(obj, ...)
|
||||
Decorator = function(tab)
|
||||
local node = make(tab[1])
|
||||
return function(...)
|
||||
local result = node(object, ...)
|
||||
if not (result == running) then
|
||||
result = tab.decorate(result, ...)
|
||||
end
|
||||
}
|
||||
_base_0.__index = _base_0
|
||||
setmetatable(_base_0, _parent_0.__base)
|
||||
_class_0 = setmetatable({
|
||||
__init = function(self, node)
|
||||
if node == nil then
|
||||
node = Node()
|
||||
end
|
||||
self.node = node
|
||||
return _class_0.__parent.__init(self)
|
||||
end,
|
||||
__base = _base_0,
|
||||
__name = "Decorator",
|
||||
__parent = _parent_0
|
||||
}, {
|
||||
__index = function(cls, name)
|
||||
local val = rawget(_base_0, name)
|
||||
if val == nil then
|
||||
local parent = rawget(cls, "__parent")
|
||||
if parent then
|
||||
return parent[name]
|
||||
end
|
||||
else
|
||||
return val
|
||||
end
|
||||
end,
|
||||
__call = function(cls, ...)
|
||||
local _self_0 = setmetatable({}, _base_0)
|
||||
cls.__init(_self_0, ...)
|
||||
return _self_0
|
||||
end
|
||||
})
|
||||
_base_0.__class = _class_0
|
||||
if _parent_0.__inherited then
|
||||
_parent_0.__inherited(_parent_0, _class_0)
|
||||
return result
|
||||
end
|
||||
Decorator = _class_0
|
||||
end
|
||||
local Repeat
|
||||
do
|
||||
local _class_0
|
||||
local _parent_0 = Decorator
|
||||
local _base_0 = {
|
||||
addObject = function(self, obj)
|
||||
_class_0.__parent.__base.addObject(self)
|
||||
obj[self.u] = {
|
||||
counter = 1,
|
||||
running = false
|
||||
}
|
||||
end,
|
||||
update = function(self, obj, ...)
|
||||
local result = success
|
||||
if obj[self.u].running then
|
||||
result = self.node:update(obj, ...)
|
||||
if not (result == running) then
|
||||
obj[self.u].running = false
|
||||
end
|
||||
local Selector
|
||||
Selector = function(tab)
|
||||
local nodes = get_nodes(tab)
|
||||
local length = #nodes
|
||||
local i = 1
|
||||
return function(...)
|
||||
local result = nodes[i](...)
|
||||
while not result do
|
||||
i = i + 1
|
||||
if i > length then
|
||||
i = 1
|
||||
return false
|
||||
end
|
||||
while result == success and obj[self.u].counter < self.cycles do
|
||||
obj[self.u].counter = obj[self.u].counter + 1
|
||||
result = self.node:update(obj, ...)
|
||||
end
|
||||
if result == running then
|
||||
obj[self.u].running = true
|
||||
else
|
||||
obj[self.u].counter = 1
|
||||
end
|
||||
return result
|
||||
result = nodes[i](...)
|
||||
end
|
||||
}
|
||||
_base_0.__index = _base_0
|
||||
setmetatable(_base_0, _parent_0.__base)
|
||||
_class_0 = setmetatable({
|
||||
__init = function(self, cycles, node)
|
||||
if cycles == nil then
|
||||
cycles = 2
|
||||
end
|
||||
if node == nil then
|
||||
node = Node()
|
||||
end
|
||||
self.cycles, self.node = cycles, node
|
||||
return _class_0.__parent.__init(self, self.node)
|
||||
end,
|
||||
__base = _base_0,
|
||||
__name = "Repeat",
|
||||
__parent = _parent_0
|
||||
}, {
|
||||
__index = function(cls, name)
|
||||
local val = rawget(_base_0, name)
|
||||
if val == nil then
|
||||
local parent = rawget(cls, "__parent")
|
||||
if parent then
|
||||
return parent[name]
|
||||
end
|
||||
else
|
||||
return val
|
||||
end
|
||||
end,
|
||||
__call = function(cls, ...)
|
||||
local _self_0 = setmetatable({}, _base_0)
|
||||
cls.__init(_self_0, ...)
|
||||
return _self_0
|
||||
if result ~= running then
|
||||
i = 1
|
||||
end
|
||||
})
|
||||
_base_0.__class = _class_0
|
||||
if _parent_0.__inherited then
|
||||
_parent_0.__inherited(_parent_0, _class_0)
|
||||
return result
|
||||
end
|
||||
Repeat = _class_0
|
||||
end
|
||||
local Succeed
|
||||
do
|
||||
local _class_0
|
||||
local _parent_0 = Decorator
|
||||
local _base_0 = {
|
||||
update = function(self, obj, ...)
|
||||
if running == self.node:update(obj, ...) then
|
||||
return running
|
||||
else
|
||||
return success
|
||||
end
|
||||
end
|
||||
}
|
||||
_base_0.__index = _base_0
|
||||
setmetatable(_base_0, _parent_0.__base)
|
||||
_class_0 = setmetatable({
|
||||
__init = function(self, ...)
|
||||
return _class_0.__parent.__init(self, ...)
|
||||
end,
|
||||
__base = _base_0,
|
||||
__name = "Succeed",
|
||||
__parent = _parent_0
|
||||
}, {
|
||||
__index = function(cls, name)
|
||||
local val = rawget(_base_0, name)
|
||||
if val == nil then
|
||||
local parent = rawget(cls, "__parent")
|
||||
if parent then
|
||||
return parent[name]
|
||||
end
|
||||
else
|
||||
return val
|
||||
end
|
||||
end,
|
||||
__call = function(cls, ...)
|
||||
local _self_0 = setmetatable({}, _base_0)
|
||||
cls.__init(_self_0, ...)
|
||||
return _self_0
|
||||
end
|
||||
})
|
||||
_base_0.__class = _class_0
|
||||
if _parent_0.__inherited then
|
||||
_parent_0.__inherited(_parent_0, _class_0)
|
||||
end
|
||||
Succeed = _class_0
|
||||
end
|
||||
local Fail
|
||||
do
|
||||
local _class_0
|
||||
local _parent_0 = Decorator
|
||||
local _base_0 = {
|
||||
update = function(self, obj, ...)
|
||||
if running == self.node:update(obj, ...) then
|
||||
return running
|
||||
else
|
||||
return fail
|
||||
end
|
||||
end
|
||||
}
|
||||
_base_0.__index = _base_0
|
||||
setmetatable(_base_0, _parent_0.__base)
|
||||
_class_0 = setmetatable({
|
||||
__init = function(self, ...)
|
||||
return _class_0.__parent.__init(self, ...)
|
||||
end,
|
||||
__base = _base_0,
|
||||
__name = "Fail",
|
||||
__parent = _parent_0
|
||||
}, {
|
||||
__index = function(cls, name)
|
||||
local val = rawget(_base_0, name)
|
||||
if val == nil then
|
||||
local parent = rawget(cls, "__parent")
|
||||
if parent then
|
||||
return parent[name]
|
||||
end
|
||||
else
|
||||
return val
|
||||
end
|
||||
end,
|
||||
__call = function(cls, ...)
|
||||
local _self_0 = setmetatable({}, _base_0)
|
||||
cls.__init(_self_0, ...)
|
||||
return _self_0
|
||||
end
|
||||
})
|
||||
_base_0.__class = _class_0
|
||||
if _parent_0.__inherited then
|
||||
_parent_0.__inherited(_parent_0, _class_0)
|
||||
end
|
||||
Fail = _class_0
|
||||
end
|
||||
local Invert
|
||||
do
|
||||
local _class_0
|
||||
local _parent_0 = Decorator
|
||||
local _base_0 = {
|
||||
update = function(self, obj, ...)
|
||||
local result = self.node:update(obj, ...)
|
||||
if result == running then
|
||||
return running
|
||||
elseif result == success then
|
||||
return fail
|
||||
else
|
||||
return success
|
||||
end
|
||||
end
|
||||
}
|
||||
_base_0.__index = _base_0
|
||||
setmetatable(_base_0, _parent_0.__base)
|
||||
_class_0 = setmetatable({
|
||||
__init = function(self, ...)
|
||||
return _class_0.__parent.__init(self, ...)
|
||||
end,
|
||||
__base = _base_0,
|
||||
__name = "Invert",
|
||||
__parent = _parent_0
|
||||
}, {
|
||||
__index = function(cls, name)
|
||||
local val = rawget(_base_0, name)
|
||||
if val == nil then
|
||||
local parent = rawget(cls, "__parent")
|
||||
if parent then
|
||||
return parent[name]
|
||||
end
|
||||
else
|
||||
return val
|
||||
end
|
||||
end,
|
||||
__call = function(cls, ...)
|
||||
local _self_0 = setmetatable({}, _base_0)
|
||||
cls.__init(_self_0, ...)
|
||||
return _self_0
|
||||
end
|
||||
})
|
||||
_base_0.__class = _class_0
|
||||
if _parent_0.__inherited then
|
||||
_parent_0.__inherited(_parent_0, _class_0)
|
||||
end
|
||||
Invert = _class_0
|
||||
end
|
||||
local RunOnce
|
||||
do
|
||||
local _class_0
|
||||
local _parent_0 = Decorator
|
||||
local _base_0 = {
|
||||
addObject = function(self, obj)
|
||||
obj[self.u] = {
|
||||
ran = false
|
||||
}
|
||||
end,
|
||||
update = function(self, obj, ...)
|
||||
if not (obj[self.u].ran) then
|
||||
local result = self.node:update(obj, ...)
|
||||
if not (result == running) then
|
||||
obj[self.u].ran = true
|
||||
end
|
||||
local Sequence
|
||||
Sequence = function(tab)
|
||||
local nodes = get_nodes(tab)
|
||||
local length = #nodes
|
||||
local i = 1
|
||||
return function(...)
|
||||
local result = nodes[i](...)
|
||||
while result and result ~= running do
|
||||
i = i + 1
|
||||
if i > length then
|
||||
i = 1
|
||||
return result
|
||||
else
|
||||
return fail
|
||||
end
|
||||
result = nodes[i](...)
|
||||
end
|
||||
}
|
||||
_base_0.__index = _base_0
|
||||
setmetatable(_base_0, _parent_0.__base)
|
||||
_class_0 = setmetatable({
|
||||
__init = function(self, ...)
|
||||
return _class_0.__parent.__init(self, ...)
|
||||
end,
|
||||
__base = _base_0,
|
||||
__name = "RunOnce",
|
||||
__parent = _parent_0
|
||||
}, {
|
||||
__index = function(cls, name)
|
||||
local val = rawget(_base_0, name)
|
||||
if val == nil then
|
||||
local parent = rawget(cls, "__parent")
|
||||
if parent then
|
||||
return parent[name]
|
||||
end
|
||||
else
|
||||
return val
|
||||
end
|
||||
end,
|
||||
__call = function(cls, ...)
|
||||
local _self_0 = setmetatable({}, _base_0)
|
||||
cls.__init(_self_0, ...)
|
||||
return _self_0
|
||||
if not (result) then
|
||||
i = 1
|
||||
end
|
||||
})
|
||||
_base_0.__class = _class_0
|
||||
if _parent_0.__inherited then
|
||||
_parent_0.__inherited(_parent_0, _class_0)
|
||||
return result
|
||||
end
|
||||
RunOnce = _class_0
|
||||
end
|
||||
local Class
|
||||
Class = function(name, parent)
|
||||
local newClass, base
|
||||
base = {
|
||||
__index = base,
|
||||
__class = newClass
|
||||
}
|
||||
newClass = setmetatable({
|
||||
__init = function() end,
|
||||
__base = base,
|
||||
__name = name
|
||||
}, {
|
||||
__call = function(cls, ...)
|
||||
local self = setmetatable({ }, base)
|
||||
cls.__init(self, ...)
|
||||
return self
|
||||
local Random
|
||||
Random = function(tab)
|
||||
local nodes = get_nodes(tab)
|
||||
local length = #nodes
|
||||
local r
|
||||
return function(...)
|
||||
if not (r) then
|
||||
r = 1 + math.random(length)
|
||||
end
|
||||
})
|
||||
if parent then
|
||||
setmetatable(base, {
|
||||
__parent = parent.__base
|
||||
})
|
||||
newClass.__parent = parent
|
||||
newClass.__index = function(cls, name)
|
||||
local val = rawget(base, name)
|
||||
if val == nil then
|
||||
return parent[name]
|
||||
else
|
||||
return val
|
||||
end
|
||||
end
|
||||
if parent.__inherited then
|
||||
parent:__inherited(newClass)
|
||||
local result = nodes[r](...)
|
||||
if not (result == running) then
|
||||
r = nil
|
||||
end
|
||||
return result
|
||||
end
|
||||
return newClass, base
|
||||
end
|
||||
return setmetatable({
|
||||
Node = Node,
|
||||
Sequence = Sequence,
|
||||
Selector = Selector,
|
||||
Random = Random,
|
||||
RandomSequence = RandomSequence,
|
||||
RandomSelector = RandomSelector,
|
||||
Decorator = Decorator,
|
||||
Repeat = Repeat,
|
||||
Succeed = Succeed,
|
||||
Fail = Fail,
|
||||
Invert = Invert,
|
||||
RunOnce = RunOnce,
|
||||
success = success,
|
||||
return {
|
||||
success = true,
|
||||
running = running,
|
||||
fail = fail,
|
||||
Class = Class
|
||||
}, {
|
||||
__call = function(bt, ...)
|
||||
return bt.Sequence(...)
|
||||
end
|
||||
})
|
||||
failure = false,
|
||||
Node = Node,
|
||||
Decorator = Decorator,
|
||||
Selector = Selector,
|
||||
Sequence = Sequence,
|
||||
Random = Random
|
||||
}
|
||||
|
382
behave.moon
382
behave.moon
@ -1,316 +1,100 @@
|
||||
success = setmetatable({}, {__tostring: -> return "success"})
|
||||
running = setmetatable({}, {__tostring: -> return "running"})
|
||||
fail = setmetatable({}, {__tostring: -> return "fail"})
|
||||
local make, Node, Decorate
|
||||
|
||||
class Node
|
||||
new: (fns={}) =>
|
||||
for key, value in pairs fns
|
||||
@[key] = value
|
||||
running = setmetatable {}, __tostring: -> return "running"
|
||||
|
||||
@success = success
|
||||
@running = running
|
||||
@fail = fail
|
||||
get_nodes = (tab) ->
|
||||
nodes = {}
|
||||
for node in *tab
|
||||
table.insert nodes, make node
|
||||
return nodes
|
||||
|
||||
@u = {}
|
||||
-- produces a callable function from a defined node or full behavior tree
|
||||
make = (tab) ->
|
||||
if "function" == type tab
|
||||
return tab
|
||||
elseif "function" == type tab.type
|
||||
return tab.type tab
|
||||
elseif tab.decorate
|
||||
return Decorate tab
|
||||
else
|
||||
return Node tab
|
||||
|
||||
addObject: (obj) =>
|
||||
obj[@u] = {
|
||||
started: false
|
||||
}
|
||||
|
||||
run: =>
|
||||
return success
|
||||
|
||||
update: (obj, ...) =>
|
||||
result = success
|
||||
if not obj[@u].started and @start
|
||||
result = @\start obj, ...
|
||||
obj[@u].started = true
|
||||
if result == success
|
||||
result = @\run obj, ...
|
||||
if result == success
|
||||
result = @\finish(obj, ...) if @finish
|
||||
obj[@u].started = false
|
||||
-- complex leaf node
|
||||
-- state is preserved through calls, optional start/finish functions
|
||||
Node = (tab) ->
|
||||
state, started = {}, false
|
||||
return (...) ->
|
||||
local result
|
||||
unless started
|
||||
result = tab.start state, ... if tab.start
|
||||
started = true unless result == false
|
||||
result = tab.run state, ... unless result == false
|
||||
if result != running
|
||||
started = false
|
||||
result = tab.finish state, ... if result and tab.finish
|
||||
return result
|
||||
|
||||
class Composite extends Node
|
||||
new: (@nodes={}) =>
|
||||
super!
|
||||
|
||||
addObject: (obj) =>
|
||||
for node in *@nodes
|
||||
node\addObject obj
|
||||
|
||||
-- Runs children in order until one returns fail, or all succeed.
|
||||
class Sequence extends Composite
|
||||
addObject: (obj) =>
|
||||
super!
|
||||
obj[@u] = {
|
||||
index: 0
|
||||
running: 0
|
||||
}
|
||||
|
||||
update: (obj, ...) =>
|
||||
result = success
|
||||
|
||||
if obj[@u].running
|
||||
result = obj[@u].running\update obj, ...
|
||||
unless result == running
|
||||
obj[@u].running = false
|
||||
|
||||
while result == success and obj[@u].index < #@nodes
|
||||
obj[@u].index += 1
|
||||
result = @nodes[obj[@u].index]\update obj, ...
|
||||
|
||||
if result == running
|
||||
obj[@u].running = @nodes[obj[@u].index]
|
||||
else
|
||||
obj[@u].index = 0
|
||||
|
||||
-- modifies the result of a node before returning it
|
||||
Decorator = (tab) ->
|
||||
node = make tab[1]
|
||||
return (...) ->
|
||||
result = node object, ...
|
||||
result = tab.decorate result, ... unless result == running
|
||||
return result
|
||||
|
||||
-- Runs children in order until one succeeds or all fail.
|
||||
class Selector extends Composite
|
||||
addObject: (obj) =>
|
||||
super!
|
||||
obj[@u] = {
|
||||
index: 0
|
||||
running: 0
|
||||
}
|
||||
|
||||
update: (obj, ...) =>
|
||||
result = fail
|
||||
if obj[@u].running
|
||||
result = obj[@u].running\update obj, ...
|
||||
unless result == running
|
||||
obj[@u].running = false
|
||||
|
||||
while result == fail and obj[@u].index < #@nodes
|
||||
obj[@u].index += 1
|
||||
result = @nodes[obj[@u].index]\update obj, ...
|
||||
|
||||
if result == running
|
||||
obj[@u].running = @nodes[obj[@u].index]
|
||||
else
|
||||
obj[@u].index = 0
|
||||
|
||||
-- returns first success/running, or failure
|
||||
Selector = (tab) ->
|
||||
nodes = get_nodes tab
|
||||
length = #nodes
|
||||
i = 1
|
||||
return (...) ->
|
||||
result = nodes[i](...)
|
||||
while not result
|
||||
i += 1
|
||||
if i > length
|
||||
i = 1
|
||||
return false
|
||||
result = nodes[i](...)
|
||||
i = 1 if result != running
|
||||
return result
|
||||
|
||||
-- Runs a random child.
|
||||
class Random extends Composite
|
||||
update: (obj, ...) =>
|
||||
index = math.floor math.random! * #@nodes + 1
|
||||
return @nodes[index]\update obj, ...
|
||||
|
||||
class Randomizer extends Composite
|
||||
addObject: (obj) =>
|
||||
super!
|
||||
obj[@u] = {
|
||||
running: false
|
||||
}
|
||||
@shuffle obj
|
||||
|
||||
shuffle: (obj) =>
|
||||
obj[@u].shuffledNodes = {}
|
||||
for i = 1, #@nodes
|
||||
r = math.random i
|
||||
unless r == i
|
||||
obj[@u].shuffledNodes[i] = obj[@u].shuffledNodes[r]
|
||||
obj[@u].shuffledNodes[r] = @nodes[i]
|
||||
|
||||
-- Randomizes order of nodes in between complete runs of them as a Sequence.
|
||||
class RandomSequence extends Randomizer
|
||||
update: (obj, ...) =>
|
||||
result = success
|
||||
|
||||
if obj[@u].running
|
||||
result = obj[@u].running\update obj, ...
|
||||
unless result == running
|
||||
obj[@u].running = false
|
||||
|
||||
local tmp
|
||||
while result == success and #obj[@u].shuffledNodes > 0
|
||||
result = obj[@u].shuffledNodes[1]\update obj, ...
|
||||
tmp = table.remove obj[@u].shuffledNodes, 1
|
||||
|
||||
if result == running
|
||||
obj[@u].running = tmp
|
||||
else
|
||||
@shuffle obj
|
||||
|
||||
-- returns first running/failure, or success
|
||||
Sequence = (tab) ->
|
||||
nodes = get_nodes tab
|
||||
length = #nodes
|
||||
i = 1
|
||||
return (...) ->
|
||||
result = nodes[i](...)
|
||||
while result and result != running
|
||||
i += 1
|
||||
if i > length
|
||||
i = 1
|
||||
return result
|
||||
result = nodes[i](...)
|
||||
i = 1 unless result
|
||||
return result
|
||||
|
||||
-- Randomizes order of nodes in between complete runs of them as a Selector.
|
||||
class RandomSelector extends Randomizer
|
||||
update: (obj, ...) =>
|
||||
result = fail
|
||||
|
||||
if obj[@u].running
|
||||
result = obj[@u].running\update obj, ...
|
||||
unless result == running
|
||||
obj[@u].running = false
|
||||
|
||||
local tmp
|
||||
while result == fail and #obj[@u].shuffledNodes > 0
|
||||
result = obj[@u].shuffledNodes[1]\update obj, ...
|
||||
tmp = table.remove obj[@u].shuffledNodes, 1
|
||||
|
||||
if result == running
|
||||
obj[@u].running = tmp
|
||||
else
|
||||
@shuffle!
|
||||
|
||||
-- returns success/running/failure from random child
|
||||
Random = (tab) ->
|
||||
nodes = get_nodes tab
|
||||
length = #nodes
|
||||
local r
|
||||
return (...) ->
|
||||
unless r
|
||||
r = 1 + math.random length
|
||||
result = nodes[r](...)
|
||||
unless result == running
|
||||
r = nil
|
||||
return result
|
||||
|
||||
class Decorator extends Node
|
||||
new: (@node=Node!) =>
|
||||
super!
|
||||
|
||||
addObject: (obj) =>
|
||||
@node\addObject obj
|
||||
|
||||
update: (obj, ...) =>
|
||||
return @node\update obj, ...
|
||||
|
||||
-- Repeats a node a specified number of times, unless it fails.
|
||||
class Repeat extends Decorator
|
||||
new: (@cycles=2, @node=Node!) =>
|
||||
super @node
|
||||
|
||||
addObject: (obj) =>
|
||||
super!
|
||||
obj[@u] = {
|
||||
counter: 1
|
||||
running: false
|
||||
}
|
||||
|
||||
update: (obj, ...) =>
|
||||
result = success
|
||||
|
||||
if obj[@u].running
|
||||
result = @node\update obj, ...
|
||||
unless result == running
|
||||
obj[@u].running = false
|
||||
|
||||
while result == success and obj[@u].counter < @cycles
|
||||
obj[@u].counter += 1
|
||||
result = @node\update obj, ...
|
||||
|
||||
if result == running
|
||||
obj[@u].running = true
|
||||
else
|
||||
obj[@u].counter = 1
|
||||
|
||||
return result
|
||||
|
||||
-- Returns success whether or not the node succeeds.
|
||||
class Succeed extends Decorator
|
||||
update: (obj, ...) =>
|
||||
if running == @node\update obj, ...
|
||||
return running
|
||||
else
|
||||
return success
|
||||
|
||||
-- Returns fail whether or not the node fails.
|
||||
class Fail extends Decorator
|
||||
update: (obj, ...) =>
|
||||
if running == @node\update obj, ...
|
||||
return running
|
||||
else
|
||||
return fail
|
||||
|
||||
-- Returns success when the node fails, and failure on success.
|
||||
class Invert extends Decorator
|
||||
update: (obj, ...) =>
|
||||
result = @node\update obj, ...
|
||||
if result == running
|
||||
return running
|
||||
elseif result == success
|
||||
return fail
|
||||
else
|
||||
return success
|
||||
|
||||
-- Only runs children once, and returns fail from then on.
|
||||
class RunOnce extends Decorator
|
||||
addObject: (obj) =>
|
||||
obj[@u] = {
|
||||
ran: false
|
||||
}
|
||||
|
||||
update: (obj, ...) =>
|
||||
unless obj[@u].ran
|
||||
result = @node\update obj, ...
|
||||
unless result == running
|
||||
obj[@u].ran = true
|
||||
return result
|
||||
else
|
||||
return fail
|
||||
|
||||
-- A MoonScript-compatible class implementation for creating your own classes.
|
||||
Class = (name, parent) ->
|
||||
local newClass, base
|
||||
base = {
|
||||
__index: base
|
||||
__class: newClass
|
||||
}
|
||||
|
||||
newClass = setmetatable {
|
||||
__init: ->
|
||||
__base: base
|
||||
__name: name
|
||||
}, {
|
||||
__call: (cls, ...) ->
|
||||
@ = setmetatable({}, base)
|
||||
cls.__init(@, ...)
|
||||
return @
|
||||
}
|
||||
|
||||
if parent
|
||||
setmetatable base, {
|
||||
__parent: parent.__base
|
||||
}
|
||||
|
||||
newClass.__parent = parent
|
||||
newClass.__index = (cls, name) ->
|
||||
val = rawget(base, name)
|
||||
if val == nil
|
||||
return parent[name]
|
||||
else
|
||||
return val
|
||||
|
||||
if parent.__inherited
|
||||
parent\__inherited newClass
|
||||
|
||||
return newClass, base
|
||||
|
||||
setmetatable {
|
||||
-- Leaf Node
|
||||
:Node
|
||||
|
||||
-- Composite Nodes
|
||||
:Composite
|
||||
:Sequence
|
||||
:Selector
|
||||
:Random
|
||||
:RandomSequence
|
||||
:RandomSelector
|
||||
|
||||
-- Decorator Nodes
|
||||
:Decorator
|
||||
:Repeat
|
||||
:Succeed
|
||||
:Fail
|
||||
:Invert
|
||||
:RunOnce
|
||||
|
||||
-- Return Values
|
||||
:success
|
||||
{
|
||||
success: true
|
||||
:running
|
||||
:fail
|
||||
failure: false
|
||||
|
||||
-- Utility Fns
|
||||
:Class
|
||||
}, {
|
||||
__call: (bt, ...) ->
|
||||
bt.Sequence ...
|
||||
:Node
|
||||
:Decorator
|
||||
:Selector
|
||||
:Sequence
|
||||
:Random
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user