rewrite to use objects for data storage

This commit is contained in:
Paul Liverman III 2017-12-09 09:31:35 -08:00
parent 43e8048341
commit 6a61891ade
3 changed files with 347 additions and 298 deletions

View File

@ -84,11 +84,12 @@ after the entire tree has been processed.
## Decorator Nodes ## Decorator Nodes
Pass a single node to these, except for `Repeat`, which needs a number & a node. Pass a single node to these, except for `Repeat`, which needs a number followed
All decorator nodes (except `RunOnce`) repeat after the entire tree has been by a node. All decorator nodes (except `RunOnce`) repeat after the entire tree
processed. has been processed.
- Repeat: Repeats a node a specified number of times, fails if the node fails. - Repeat: Repeats a node a specified number of times, fails if the node fails.
- Decorator: Does nothing except return the result of its child node.
- Succeed: Runs a node and returns success. - Succeed: Runs a node and returns success.
- Fail: Runs a node and returns failure. - Fail: Runs a node and returns failure.
- Invert: Runs a node, reporting a success on fail, and failure on success. - Invert: Runs a node, reporting a success on fail, and failure on success.

View File

@ -17,23 +17,28 @@ local Node
do do
local _class_0 local _class_0
local _base_0 = { local _base_0 = {
addObject = function(self, obj)
obj[self.u] = {
started = false
}
end,
run = function(self) run = function(self)
return success return success
end, end,
update = function(self, ...) update = function(self, obj, ...)
local result = success local result = success
if not self.started and self.start then if not obj[self.u].started and self.start then
result = self:start(...) result = self:start(obj, ...)
self.started = true obj[self.u].started = true
end end
if result == success then if result == success then
result = self:run(...) result = self:run(obj, ...)
end end
if result == success then if result == success then
if self.finish then if self.finish then
result = self:finish(...) result = self:finish(obj, ...)
end end
self.started = false obj[self.u].started = false
end end
return result return result
end end
@ -50,7 +55,7 @@ do
self.success = success self.success = success
self.running = running self.running = running
self.fail = fail self.fail = fail
self.started = false self.u = { }
end, end,
__base = _base_0, __base = _base_0,
__name = "Node" __name = "Node"
@ -70,22 +75,28 @@ do
local _class_0 local _class_0
local _parent_0 = Node local _parent_0 = Node
local _base_0 = { local _base_0 = {
update = function(self, ...) addObject = function(self, obj)
obj[self.u] = {
index = 0,
running = 0
}
end,
update = function(self, obj, ...)
local result = success local result = success
if self._running then if obj[self.u].running then
result = self._running:update(...) result = obj[self.u].running:update(obj, ...)
if not (result == running) then if not (result == running) then
self._running = false obj[self.u].running = false
end end
end end
while result == success and self.index < #self.nodes do while result == success and obj[self.u].index < #self.nodes do
self.index = self.index + 1 obj[self.u].index = obj[self.u].index + 1
result = self.nodes[self.index]:update(...) result = self.nodes[obj[self.u].index]:update(obj, ...)
end end
if result == running then if result == running then
self._running = self.nodes[self.index] obj[self.u].running = self.nodes[obj[self.u].index]
else else
self.index = 0 obj[self.u].index = 0
end end
return result return result
end end
@ -98,9 +109,7 @@ do
nodes = { } nodes = { }
end end
self.nodes = nodes self.nodes = nodes
_class_0.__parent.__init(self) return _class_0.__parent.__init(self)
self.index = 0
self._running = false
end, end,
__base = _base_0, __base = _base_0,
__name = "Sequence", __name = "Sequence",
@ -134,22 +143,28 @@ do
local _class_0 local _class_0
local _parent_0 = Node local _parent_0 = Node
local _base_0 = { local _base_0 = {
update = function(self, ...) addObject = function(self, obj)
obj[self.u] = {
index = 0,
running = 0
}
end,
update = function(self, obj, ...)
local result = fail local result = fail
if self._running then if obj[self.u].running then
result = self._running:update(...) result = obj[self.u].running:update(obj, ...)
if not (result == running) then if not (result == running) then
self._running = false obj[self.u].running = false
end end
end end
while result == fail and self.index < #self.nodes do while result == fail and obj[self.u].index < #self.nodes do
self.index = self.index + 1 obj[self.u].index = obj[self.u].index + 1
result = self.nodes[self.index]:update(...) result = self.nodes[obj[self.u].index]:update(obj, ...)
end end
if result == running then if result == running then
self._running = self.nodes[self.index] obj[self.u].running = self.nodes[obj[self.u].index]
else else
self.index = 0 obj[self.u].index = 0
end end
return result return result
end end
@ -162,9 +177,7 @@ do
nodes = { } nodes = { }
end end
self.nodes = nodes self.nodes = nodes
_class_0.__parent.__init(self) return _class_0.__parent.__init(self)
self.index = 0
self._running = false
end, end,
__base = _base_0, __base = _base_0,
__name = "Selector", __name = "Selector",
@ -198,9 +211,9 @@ do
local _class_0 local _class_0
local _parent_0 = Node local _parent_0 = Node
local _base_0 = { local _base_0 = {
update = function(self, ...) update = function(self, obj, ...)
local index = math.floor(math.random() * #self.nodes + 1) local index = math.floor(math.random() * #self.nodes + 1)
return self.nodes[index]:update(...) return self.nodes[index]:update(obj, ...)
end end
} }
_base_0.__index = _base_0 _base_0.__index = _base_0
@ -240,40 +253,26 @@ do
end end
Random = _class_0 Random = _class_0
end end
local RandomSequence local Randomizer
do do
local _class_0 local _class_0
local _parent_0 = Node local _parent_0 = Node
local _base_0 = { local _base_0 = {
shuffle = function(self) addObject = function(self, obj)
self._shuffled = { } obj[self.u] = {
running = false
}
return self:shuffle(obj)
end,
shuffle = function(self, obj)
obj[self.u].shuffledNodes = { }
for i = 1, #self.nodes do for i = 1, #self.nodes do
local r = math.random(i) local r = math.random(i)
if not (r == i) then if not (r == i) then
self._shuffled[i] = self._shuffled[r] obj[self.u].shuffledNodes[i] = obj[self.u].shuffledNodes[r]
end end
self._shuffled[r] = self.nodes[i] obj[self.u].shuffledNodes[r] = self.nodes[i]
end end
end,
update = function(self, ...)
local result = success
if self._running then
result = self._running:update(...)
if not (result == running) then
self._running = false
end
end
local tmp
while result == success and #self._shuffled > 0 do
result = self._shuffled[1]:update(...)
tmp = table.remove(self._shuffled, 1)
end
if result == running then
self._running = tmp
else
self:shuffle()
end
return result
end end
} }
_base_0.__index = _base_0 _base_0.__index = _base_0
@ -284,9 +283,66 @@ do
nodes = { } nodes = { }
end end
self.nodes = nodes self.nodes = nodes
_class_0.__parent.__init(self) return _class_0.__parent.__init(self)
self._running = false end,
return self:shuffle() __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, end,
__base = _base_0, __base = _base_0,
__name = "RandomSequence", __name = "RandomSequence",
@ -318,33 +374,23 @@ end
local RandomSelector local RandomSelector
do do
local _class_0 local _class_0
local _parent_0 = Node local _parent_0 = Randomizer
local _base_0 = { local _base_0 = {
shuffle = function(self) update = function(self, obj, ...)
self._shuffled = { }
for i = 1, #self.nodes do
local r = math.random(i)
if not (r == i) then
self._shuffled[i] = self._shuffled[r]
end
self._shuffled[r] = self.nodes[i]
end
end,
update = function(self, ...)
local result = fail local result = fail
if self._running then if obj[self.u].running then
result = self._running:update(...) result = obj[self.u].running:update(obj, ...)
if not (result == running) then if not (result == running) then
self._running = false obj[self.u].running = false
end end
end end
local tmp local tmp
while result == fail and #self._shuffled > 0 do while result == fail and #obj[self.u].shuffledNodes > 0 do
result = self._shuffled[1]:update(...) result = obj[self.u].shuffledNodes[1]:update(obj, ...)
tmp = table.remove(self._shuffled, 1) tmp = table.remove(obj[self.u].shuffledNodes, 1)
end end
if result == running then if result == running then
self._running = tmp obj[self.u].running = tmp
else else
self:shuffle() self:shuffle()
end end
@ -354,14 +400,8 @@ do
_base_0.__index = _base_0 _base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base) setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({ _class_0 = setmetatable({
__init = function(self, nodes) __init = function(self, ...)
if nodes == nil then return _class_0.__parent.__init(self, ...)
nodes = { }
end
self.nodes = nodes
_class_0.__parent.__init(self)
self._running = false
return self:shuffle()
end, end,
__base = _base_0, __base = _base_0,
__name = "RandomSelector", __name = "RandomSelector",
@ -395,22 +435,28 @@ do
local _class_0 local _class_0
local _parent_0 = Node local _parent_0 = Node
local _base_0 = { local _base_0 = {
update = function(self, ...) addObject = function(self, obj)
obj[self.u] = {
counter = 1,
running = false
}
end,
update = function(self, obj, ...)
local result = success local result = success
if self._running then if obj[self.u].running then
result = self.node:update(...) result = self.node:update(obj, ...)
if not (result == running) then if not (result == running) then
self._running = false obj[self.u].running = false
end end
end end
while result == success and self.counter < self.cycles do while result == success and obj[self.u].counter < self.cycles do
self.counter = self.counter + 1 obj[self.u].counter = obj[self.u].counter + 1
result = self.node:update(...) result = self.node:update(obj, ...)
end end
if result == running then if result == running then
self._running = true obj[self.u].running = true
else else
self.counter = 1 obj[self.u].counter = 1
end end
return result return result
end end
@ -426,9 +472,7 @@ do
node = Node() node = Node()
end end
self.cycles, self.node = cycles, node self.cycles, self.node = cycles, node
_class_0.__parent.__init(self) return _class_0.__parent.__init(self)
self.counter = 1
self._running = false
end, end,
__base = _base_0, __base = _base_0,
__name = "Repeat", __name = "Repeat",
@ -457,17 +501,13 @@ do
end end
Repeat = _class_0 Repeat = _class_0
end end
local Succeed local Decorator
do do
local _class_0 local _class_0
local _parent_0 = Node local _parent_0 = Node
local _base_0 = { local _base_0 = {
update = function(self, ...) update = function(self, obj, ...)
if running == self.node:update(...) then return self.node:update(obj, ...)
return running
else
return success
end
end end
} }
_base_0.__index = _base_0 _base_0.__index = _base_0
@ -481,6 +521,52 @@ do
return _class_0.__parent.__init(self) return _class_0.__parent.__init(self)
end, end,
__base = _base_0, __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)
end
Decorator = _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", __name = "Succeed",
__parent = _parent_0 __parent = _parent_0
}, { }, {
@ -510,10 +596,10 @@ end
local Fail local Fail
do do
local _class_0 local _class_0
local _parent_0 = Node local _parent_0 = Decorator
local _base_0 = { local _base_0 = {
update = function(self, ...) update = function(self, obj, ...)
if running == self.node:update(...) then if running == self.node:update(obj, ...) then
return running return running
else else
return fail return fail
@ -523,12 +609,8 @@ do
_base_0.__index = _base_0 _base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base) setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({ _class_0 = setmetatable({
__init = function(self, node) __init = function(self, ...)
if node == nil then return _class_0.__parent.__init(self, ...)
node = Node()
end
self.node = node
return _class_0.__parent.__init(self)
end, end,
__base = _base_0, __base = _base_0,
__name = "Fail", __name = "Fail",
@ -560,10 +642,10 @@ end
local Invert local Invert
do do
local _class_0 local _class_0
local _parent_0 = Node local _parent_0 = Decorator
local _base_0 = { local _base_0 = {
update = function(self, ...) update = function(self, obj, ...)
local result = self.node:update(...) local result = self.node:update(obj, ...)
if result == running then if result == running then
return running return running
elseif result == success then elseif result == success then
@ -576,12 +658,8 @@ do
_base_0.__index = _base_0 _base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base) setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({ _class_0 = setmetatable({
__init = function(self, node) __init = function(self, ...)
if node == nil then return _class_0.__parent.__init(self, ...)
node = Node()
end
self.node = node
return _class_0.__parent.__init(self)
end, end,
__base = _base_0, __base = _base_0,
__name = "Invert", __name = "Invert",
@ -613,13 +691,18 @@ end
local RunOnce local RunOnce
do do
local _class_0 local _class_0
local _parent_0 = Node local _parent_0 = Decorator
local _base_0 = { local _base_0 = {
update = function(self, ...) addObject = function(self, obj)
if not (self.ran) then obj[self.u] = {
local result = self.node:update(...) 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 if not (result == running) then
self.run = true obj[self.u].ran = true
end end
return result return result
else else
@ -630,13 +713,8 @@ do
_base_0.__index = _base_0 _base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base) setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({ _class_0 = setmetatable({
__init = function(self, node) __init = function(self, ...)
if node == nil then return _class_0.__parent.__init(self, ...)
node = Node()
end
self.node = node
_class_0.__parent.__init(self)
self.ran = false
end, end,
__base = _base_0, __base = _base_0,
__name = "RunOnce", __name = "RunOnce",
@ -672,19 +750,19 @@ Class = function(name, parent)
__index = base, __index = base,
__class = newClass __class = newClass
} }
newClass = setmetable({ newClass = setmetatable({
__init = function() end, __init = function() end,
__base = base, __base = base,
__name = name __name = name
}, { }, {
__call = function(cls, ...) __call = function(cls, ...)
local self = setmetable({ }, base) local self = setmetatable({ }, base)
cls.__init(self, ...) cls.__init(self, ...)
return self return self
end end
}) })
if parent then if parent then
setmetable(base, { setmetatable(base, {
__parent = parent.__base __parent = parent.__base
}) })
newClass.__parent = parent newClass.__parent = parent
@ -702,13 +780,14 @@ Class = function(name, parent)
end end
return newClass, base return newClass, base
end end
local behave = { return setmetatable({
Node = Node, Node = Node,
Sequence = Sequence, Sequence = Sequence,
Selector = Selector, Selector = Selector,
Random = Random, Random = Random,
RandomSequence = RandomSequence, RandomSequence = RandomSequence,
RandomSelector = RandomSelector, RandomSelector = RandomSelector,
Decorator = Decorator,
Repeat = Repeat, Repeat = Repeat,
Succeed = Succeed, Succeed = Succeed,
Fail = Fail, Fail = Fail,
@ -718,24 +797,8 @@ local behave = {
running = running, running = running,
fail = fail, fail = fail,
Class = Class Class = Class
} }, {
behave.clone = function(object) __call = function(bt, ...)
local new return bt.Sequence(...)
local cls = getmetatable(object).__class.__name
if cls == "Repeat" then
new = behave[cls](object.cycles, object)
else
new = behave[cls](object)
end end
if object.nodes then })
local nodes = { }
for k, v in pairs(object.nodes) do
nodes[k] = behave.clone(v)
end
new.nodes = nodes
elseif object.node then
new.node = behave.clone(object.node)
end
return new
end
return behave

View File

@ -11,21 +11,26 @@ class Node
@running = running @running = running
@fail = fail @fail = fail
@started = false @u = {}
addObject: (obj) =>
obj[@u] = {
started: false
}
run: => run: =>
return success return success
update: (...) => update: (obj, ...) =>
result = success result = success
if not @started and @start if not obj[@u].started and @start
result = @\start ... result = @\start obj, ...
@started = true obj[@u].started = true
if result == success if result == success
result = @\run ... result = @\run obj, ...
if result == success if result == success
result = @\finish(...) if @finish result = @\finish(obj, ...) if @finish
@started = false obj[@u].started = false
return result return result
-- Runs children in order until one returns fail, or all succeed. -- Runs children in order until one returns fail, or all succeed.
@ -33,25 +38,28 @@ class Sequence extends Node
new: (@nodes={}) => new: (@nodes={}) =>
super! super!
@index = 0 addObject: (obj) =>
@_running = false obj[@u] = {
index: 0
running: 0
}
update: (...) => update: (obj, ...) =>
result = success result = success
if @_running if obj[@u].running
result = @_running\update ... result = obj[@u].running\update obj, ...
unless result == running unless result == running
@_running = false obj[@u].running = false
while result == success and @index < #@nodes while result == success and obj[@u].index < #@nodes
@index += 1 obj[@u].index += 1
result = @nodes[@index]\update ... result = @nodes[obj[@u].index]\update obj, ...
if result == running if result == running
@_running = @nodes[@index] obj[@u].running = @nodes[obj[@u].index]
else else
@index = 0 obj[@u].index = 0
return result return result
@ -60,24 +68,27 @@ class Selector extends Node
new: (@nodes={}) => new: (@nodes={}) =>
super! super!
@index = 0 addObject: (obj) =>
@_running = false obj[@u] = {
index: 0
running: 0
}
update: (...) => update: (obj, ...) =>
result = fail result = fail
if @_running if obj[@u].running
result = @_running\update ... result = obj[@u].running\update obj, ...
unless result == running unless result == running
@_running = false obj[@u].running = false
while result == fail and @index < #@nodes while result == fail and obj[@u].index < #@nodes
@index += 1 obj[@u].index += 1
result = @nodes[@index]\update ... result = @nodes[obj[@u].index]\update obj, ...
if result == running if result == running
@_running = @nodes[@index] obj[@u].running = @nodes[obj[@u].index]
else else
@index = 0 obj[@u].index = 0
return result return result
@ -86,77 +97,67 @@ class Random extends Node
new: (@nodes={}) => new: (@nodes={}) =>
super! super!
update: (...) => update: (obj, ...) =>
index = math.floor math.random! * #@nodes + 1 index = math.floor math.random! * #@nodes + 1
return @nodes[index]\update ... return @nodes[index]\update obj, ...
-- Randomizes order of nodes in between complete runs of them as a Sequence. class Randomizer extends Node
class RandomSequence extends Node
new: (@nodes={}) => new: (@nodes={}) =>
super! super!
@_running = false addObject: (obj) =>
@shuffle! obj[@u] = {
running: false
}
@shuffle obj
shuffle: => shuffle: (obj) =>
@_shuffled = {} obj[@u].shuffledNodes = {}
for i = 1, #@nodes for i = 1, #@nodes
r = math.random i r = math.random i
unless r == i unless r == i
@_shuffled[i] = @_shuffled[r] obj[@u].shuffledNodes[i] = obj[@u].shuffledNodes[r]
@_shuffled[r] = @nodes[i] obj[@u].shuffledNodes[r] = @nodes[i]
update: (...) => -- Randomizes order of nodes in between complete runs of them as a Sequence.
class RandomSequence extends Randomizer
update: (obj, ...) =>
result = success result = success
if @_running if obj[@u].running
result = @_running\update ... result = obj[@u].running\update obj, ...
unless result == running unless result == running
@_running = false obj[@u].running = false
local tmp local tmp
while result == success and #@_shuffled > 0 while result == success and #obj[@u].shuffledNodes > 0
result = @_shuffled[1]\update ... result = obj[@u].shuffledNodes[1]\update obj, ...
tmp = table.remove @_shuffled, 1 tmp = table.remove obj[@u].shuffledNodes, 1
if result == running if result == running
@_running = tmp obj[@u].running = tmp
else else
@shuffle! @shuffle obj
return result return result
-- Randomizes order of nodes in between complete runs of them as a Selector. -- Randomizes order of nodes in between complete runs of them as a Selector.
class RandomSelector extends Node class RandomSelector extends Randomizer
new: (@nodes={}) => update: (obj, ...) =>
super!
@_running = false
@shuffle!
shuffle: =>
@_shuffled = {}
for i = 1, #@nodes
r = math.random i
unless r == i
@_shuffled[i] = @_shuffled[r]
@_shuffled[r] = @nodes[i]
update: (...) =>
result = fail result = fail
if @_running if obj[@u].running
result = @_running\update ... result = obj[@u].running\update obj, ...
unless result == running unless result == running
@_running = false obj[@u].running = false
local tmp local tmp
while result == fail and #@_shuffled > 0 while result == fail and #obj[@u].shuffledNodes > 0
result = @_shuffled[1]\update ... result = obj[@u].shuffledNodes[1]\update obj, ...
tmp = table.remove @_shuffled, 1 tmp = table.remove obj[@u].shuffledNodes, 1
if result == running if result == running
@_running = tmp obj[@u].running = tmp
else else
@shuffle! @shuffle!
@ -167,57 +168,58 @@ class Repeat extends Node
new: (@cycles=2, @node=Node!) => new: (@cycles=2, @node=Node!) =>
super! super!
@counter = 1 addObject: (obj) =>
@_running = false obj[@u] = {
counter: 1
running: false
}
update: (...) => update: (obj, ...) =>
result = success result = success
if @_running if obj[@u].running
result = @node\update ... result = @node\update obj, ...
unless result == running unless result == running
@_running = false obj[@u].running = false
while result == success and @counter < @cycles while result == success and obj[@u].counter < @cycles
@counter += 1 obj[@u].counter += 1
result = @node\update ... result = @node\update obj, ...
if result == running if result == running
@_running = true obj[@u].running = true
else else
@counter = 1 obj[@u].counter = 1
return result return result
-- Returns success whether or not the node succeeds. class Decorator extends Node
class Succeed extends Node
new: (@node=Node!) => new: (@node=Node!) =>
super! super!
update: (...) => update: (obj, ...) =>
if running == @node\update ... return @node\update obj, ...
-- Returns success whether or not the node succeeds.
class Succeed extends Decorator
update: (obj, ...) =>
if running == @node\update obj, ...
return running return running
else else
return success return success
-- Returns fail whether or not the node fails. -- Returns fail whether or not the node fails.
class Fail extends Node class Fail extends Decorator
new: (@node=Node!) => update: (obj, ...) =>
super! if running == @node\update obj, ...
update: (...) =>
if running == @node\update ...
return running return running
else else
return fail return fail
-- Returns success when the node fails, and failure on success. -- Returns success when the node fails, and failure on success.
class Invert extends Node class Invert extends Decorator
new: (@node=Node!) => update: (obj, ...) =>
super! result = @node\update obj, ...
update: (...) =>
result = @node\update ...
if result == running if result == running
return running return running
elseif result == success elseif result == success
@ -226,17 +228,17 @@ class Invert extends Node
return success return success
-- Only runs children once, and returns fail from then on. -- Only runs children once, and returns fail from then on.
class RunOnce extends Node class RunOnce extends Decorator
new: (@node=Node!) => addObject: (obj) =>
super! obj[@u] = {
ran: false
}
@ran = false update: (obj, ...) =>
unless obj[@u].ran
update: (...) => result = @node\update obj, ...
unless @ran
result = @node\update ...
unless result == running unless result == running
@run = true obj[@u].ran = true
return result return result
else else
return fail return fail
@ -249,19 +251,19 @@ Class = (name, parent) ->
__class: newClass __class: newClass
} }
newClass = setmetable { newClass = setmetatable {
__init: -> __init: ->
__base: base __base: base
__name: name __name: name
}, { }, {
__call: (cls, ...) -> __call: (cls, ...) ->
@ = setmetable({}, base) @ = setmetatable({}, base)
cls.__init(@, ...) cls.__init(@, ...)
return @ return @
} }
if parent if parent
setmetable base, { setmetatable base, {
__parent: parent.__base __parent: parent.__base
} }
@ -278,7 +280,7 @@ Class = (name, parent) ->
return newClass, base return newClass, base
behave = { setmetatable {
-- Leaf Node -- Leaf Node
:Node :Node
@ -290,6 +292,7 @@ behave = {
:RandomSelector :RandomSelector
-- Decorator Nodes -- Decorator Nodes
:Decorator
:Repeat :Repeat
:Succeed :Succeed
:Fail :Fail
@ -303,25 +306,7 @@ behave = {
-- Utility Fns -- Utility Fns
:Class :Class
}, {
__call: (bt, ...) ->
bt.Sequence ...
} }
behave.clone = (object) ->
local new
cls = getmetatable(object).__class.__name
if cls == "Repeat"
new = behave[cls] object.cycles, object
else
new = behave[cls] object
if object.nodes
nodes = {}
for k,v in pairs object.nodes
nodes[k] = behave.clone v
new.nodes = nodes
elseif object.node
new.node = behave.clone object.node
return new
return behave