Rework sequence and selector nodes to run every child, instead of one per update

This commit is contained in:
shylie 2024-07-27 11:56:55 -04:00
parent 28a181e2d4
commit 22932dce05

View File

@ -1,6 +1,11 @@
local Tactree = {} local Tactree = {}
local Nodes = {} local Nodes = {}
local function NodeReset(node)
node:_finish()
node._started = false
end
local function NodeStart(node, args) local function NodeStart(node, args)
-- don't start again if started -- don't start again if started
if node._started then return end if node._started then return end
@ -14,14 +19,27 @@ end
local function NodeUpdate(node, ...) local function NodeUpdate(node, ...)
-- automatically start if not started -- automatically start if not started
if not node._started then NodeStart(node) end if not node._started then
NodeStart(node)
end
-- mark node as run and unmark children
node._ran = true
for _, child in ipairs(node.children) do
child._ran = false
end
local result = node:_tick(...) local result = node:_tick(...)
if type(result) == 'boolean' then if result ~= nil then
node:_finish() NodeReset(node)
end
node._started = false -- reset unrun children
for _, child in ipairs(node.children) do
if not child._ran and child._started then
NodeReset(child)
end
end end
return result return result
@ -85,8 +103,8 @@ local function tree_by_name(name, depth)
node.update = NodeUpdate node.update = NodeUpdate
node.private = NodePrivateData node.private = NodePrivateData
-- this will crash if there is a recursive structure -- this will crash if there is a recursive structure; find a way to prevent this?
-- find a way to prevent this? -- does my API even allow declaring recursive structures?
if Nodes[name].children then if Nodes[name].children then
for _, child in ipairs(Nodes[name].children) do for _, child in ipairs(Nodes[name].children) do
local cn = tree_by_name(child, depth + 1) local cn = tree_by_name(child, depth + 1)
@ -137,6 +155,20 @@ function Tactree.Tree(name)
end end
Tactree.Leaf 'Sequence' Tactree.Leaf 'Sequence'
{
function(node, ...)
local child = 1
local result
repeat
result = node.children[child]:update(...)
child = child + 1
until (not result) or (child > #node.children)
return result
end
}
Tactree.Leaf 'StepSequence'
{ {
start = function(node) start = function(node)
node:private().current_child = 1 node:private().current_child = 1
@ -145,9 +177,7 @@ Tactree.Leaf 'Sequence'
local result local result
repeat repeat
result = node.children[node:private().current_child]:update(...) result = node.children[node:private().current_child]:update(...)
if result then if result ~= nil then node:private().current_child = node:private().current_child + 1 end
node:private().current_child = node:private().current_child + 1
end
until (not result) or (node:private().current_child > #node.children) until (not result) or (node:private().current_child > #node.children)
return result return result
@ -155,6 +185,20 @@ Tactree.Leaf 'Sequence'
} }
Tactree.Leaf 'Selector' Tactree.Leaf 'Selector'
{
function(node, ...)
local child = 1
local result
repeat
result = node.children[child]:update(...)
child = child + 1
until (result ~= false) or (child > #node.children)
return result
end
}
Tactree.Leaf 'StepSelector'
{ {
start = function(node) start = function(node)
node:private().current_child = 1 node:private().current_child = 1
@ -163,9 +207,7 @@ Tactree.Leaf 'Selector'
local result local result
repeat repeat
result = node.children[node:private().current_child]:update(...) result = node.children[node:private().current_child]:update(...)
if result == false then if result ~= nil then node:private().current_child = node:private().current_child + 1 end
node:private().current_child = node:private().current_child + 1
end
until (result ~= false) or (node:private().current_child > #node.children) until (result ~= false) or (node:private().current_child > #node.children)
return result return result
@ -174,30 +216,11 @@ Tactree.Leaf 'Selector'
Tactree.Leaf 'Inverter' Tactree.Leaf 'Inverter'
{ {
start = function(node) function(node, ...)
node.children[1]:start()
end,
tick = function(node, ...)
local result = node.children[1]:update(...) local result = node.children[1]:update(...)
if type(result) == 'boolean' then return not result end if result ~= nil then return not result end
end end
} }
--[[
Example usage
-------------
Tactree.Leaf 'Find nearest object' { function (node) ... end }
Tactree.Leaf 'Pick up object' { function (node) ... end}
Tactree.Leaf 'Move' { function (node) return node.data.creature:move(node.data.tx, node.data.ty, dt) end }
Tactree.Composite 'Pick up nearest object' 'Sequence' { 'Find nearest object', 'Move', 'Pick up object' }
local tr = Tactree.Tree 'Pick up nearest object'
tr:start{ ... } ( or, if you already have a table, tr:start(existing_table) )
t:update()
]]--
return Tactree return Tactree