Passing function as an argument

I have a function, that returns 2 locals, and I wanted to use it as an argument in another function. However, the function that has argument function does not work. I was wondering how it works. I have something like this:

First function, that will later be used as an argument:
image
image
The second function that utilizes first:

And here is how it looks in the end:

The GetNeighbors and the GetBest functions work just fine, but SpawnNextRoot does not seem to work.

I could try to post entire code later, if anybody needs more detail.

1 Like

Since you mention its probably something weird to do with roblox Lua tuples (when you return multiple variables).

You could try to use table.pack or table.unpack to handle them. Maybe its confusing 1 parameter as 2 or something I experienced it before.

1 Like

When a function returns >1 value, they can all be passed as arguments to another function…
UNTIL! There’s another argument coming after the function call, so like:

local function a(num1, num2)
    print(num1, num2)
end

local function b()
    return 100, 20
end

a( b() ) -- prints 100, 20
a( b(), 10 ) -- prints 100, 10

In this case, only the first value will be passed & the rest is overridden by the arguments that come after.

To resolve this, you could reorder the arguments so nothing is lost, store them as variables before the next function call & pass the variables instead, or send a table, as mentioned beforehand.

1 Like

Yah, but in my case the GetBest function does not have any new arguments after itself?

image
I did try to combine them, but that did not work either. Its acting really strange, not even print works in the SpawnNextRoot function.

And the 2nd function seems to work just fine. ( Print(PositionsAndConnections) ):
image

Here is a full code BTW:

local TweenService = game:GetService("TweenService")

local RootList = {}

local heart = workspace.Overgrowth.OverGrowthHeart

table.insert(RootList, heart)

local function GetNeighbors(previousRoot)
	
	local availableSpots = {}
	
	local overlapParams = OverlapParams.new()
	overlapParams.FilterDescendantsInstances = {workspace.Overgrowth:GetChildren(), workspace:GetChildren()}
	overlapParams.FilterType = Enum.RaycastFilterType.Include
	
	local UpCheckBoxResult = workspace:GetPartBoundsInBox(previousRoot.CFrame * CFrame.new(0, 1, 0), Vector3.new(0.8, 0.8, 0.8), overlapParams)
	local DownCheckBoxResult = workspace:GetPartBoundsInBox(previousRoot.CFrame * CFrame.new(0, -1, 0), Vector3.new(0.8, 0.8, 0.8), overlapParams)
	local LeftCheckBoxResult = workspace:GetPartBoundsInBox(previousRoot.CFrame * CFrame.new(-1, 0, 0), Vector3.new(0.8, 0.8, 0.8), overlapParams)
	local RightCheckBoxResult = workspace:GetPartBoundsInBox(previousRoot.CFrame * CFrame.new(1, 0, 0), Vector3.new(0.8, 0.8, 0.8), overlapParams)
	local FrontCheckBoxResult = workspace:GetPartBoundsInBox(previousRoot.CFrame * CFrame.new(0, 0, -1), Vector3.new(0.8, 0.8, 0.8), overlapParams)
	local BackCheckBoxResult = workspace:GetPartBoundsInBox(previousRoot.CFrame * CFrame.new(0, 0, 1), Vector3.new(0.8, 0.8, 0.8), overlapParams)
	
	if #UpCheckBoxResult == 0 then
		table.insert(availableSpots, previousRoot.Position + Vector3.new(0, 1, 0))
	end

	if #DownCheckBoxResult == 0 then
		table.insert(availableSpots, previousRoot.Position + Vector3.new(0, -1, 0))
	end

	if #LeftCheckBoxResult == 0 then
		table.insert(availableSpots, previousRoot.Position + Vector3.new(-1, 0, 0))
	end

	if #RightCheckBoxResult == 0 then
		table.insert(availableSpots, previousRoot.Position + Vector3.new(1, 0, 0))
	end

	if #FrontCheckBoxResult == 0 then
		table.insert(availableSpots, previousRoot.Position + Vector3.new(0, 0, -1))
	end

	if #BackCheckBoxResult == 0 then
		table.insert(availableSpots, previousRoot.Position * Vector3.new(0, 0, 1))
	end
	
	return availableSpots
	
end

local function GetBest(previousRoot, positionsArray)
	
	local overlapParams = OverlapParams.new()
	overlapParams.FilterType = Enum.RaycastFilterType.Include
	overlapParams.FilterDescendantsInstances = {workspace.Structures:GetChildren(), workspace.Overgrowth:GetChildren()}
	
	local valueList = {}
	local connectionsList = {}
	
	for i, pos in pairs(positionsArray) do
		
		local connections = {}
		
		local rightCheckBoxResult = workspace:GetPartBoundsInBox(previousRoot.CFrame * CFrame.new(1.5, 0, 0), Vector3.new(0.2, 0.8, 0.8), overlapParams)
		local leftCheckBoxResult = workspace:GetPartBoundsInBox(previousRoot.CFrame * CFrame.new(-1.5, 0, 0), Vector3.new(0.2, 0.8, 0.8), overlapParams)
		local upCheckBoxResult = workspace:GetPartBoundsInBox(previousRoot.CFrame * CFrame.new(0, 1.5, 0), Vector3.new(0.8, 0.2, 0.8), overlapParams)
		local downCheckBoxResult = workspace:GetPartBoundsInBox(previousRoot.CFrame * CFrame.new(0, -1.5, 0), Vector3.new(0.8, 0.2, 0.8), overlapParams)
		local backCheckBoxResult = workspace:GetPartBoundsInBox(previousRoot.CFrame * CFrame.new(0, 0, 1.5), Vector3.new(0.8, 0.8, 0.2), overlapParams)
		local frontCheckBoxResult = workspace:GetPartBoundsInBox(previousRoot.CFrame * CFrame.new(0, 0, -1.5), Vector3.new(0.8, 0.8, 0.2), overlapParams)
		
		local connectionValue = 0
		
		if #rightCheckBoxResult > 0 then
			connectionValue = connectionValue + 1
			table.insert(connections, rightCheckBoxResult)
		end
		if #leftCheckBoxResult > 0 then
			connectionValue = connectionValue
			table.insert(connections, leftCheckBoxResult)
		end
		if #upCheckBoxResult > 0 then
			connectionValue += 1
			table.insert(connections, upCheckBoxResult)
		end
		if #downCheckBoxResult > 0 then
			connectionValue += 1
			table.insert(connections, downCheckBoxResult)
		end
		if #backCheckBoxResult > 0 then
			connectionValue += 1
			table.insert(connections, backCheckBoxResult)
		end
		if #frontCheckBoxResult > 0 then
			connectionValue += 1
			table.insert(connections, frontCheckBoxResult)
		end
		
		table.insert(valueList, connectionValue)
		connectionsList[i] = connections
		
	end
	
	local bestValue = math.max(unpack(valueList))
	local bestValueIndex = table.find(valueList, bestValue)
	
	local bestOfTheBestValues = {}
	local bestOfTheBestPositions = {}
	local bestOfTheBestConnections = {}
	
	for i, v in pairs(valueList) do
		if v == bestValue then
			table.insert(bestOfTheBestValues, v)
			table.insert(bestOfTheBestPositions, positionsArray[bestValueIndex])
			table.insert(bestOfTheBestConnections, connectionsList[bestValueIndex])
		end
	end
	
	local nextPositionIndex = math.random(1, #bestOfTheBestValues)
	
	local nextPosition = bestOfTheBestPositions[nextPositionIndex]
	local nextConnection = bestOfTheBestConnections[nextPositionIndex]
	
	local positionsAndConnections = {
		[1] = nextPosition;
		[2] = nextConnection
	}
	
	print(positionsAndConnections)
	
	return positionsAndConnections
	
end


local function SpawnNextRoot(previousRoot, parameters)
	
	local nextRootPosition = parameters[1]
		
		local spawnPosition
		
		if nextRootPosition == previousRoot.Position + Vector3.new(0, 1, 0) then
			spawnPosition = nextRootPosition + Vector3.new(0, -0.5, 0)
		elseif nextRootPosition == previousRoot.Position + Vector3.new(0, -1, 0) then
			spawnPosition = nextRootPosition + Vector3.new(0, 0.5, 0)
		elseif nextRootPosition == previousRoot.Position + Vector3.new(-1, 0, 0) then
			spawnPosition = nextRootPosition + Vector3.new(0.5, 0, 0)
		elseif nextRootPosition == previousRoot.Position + Vector3.new(1, 0, 0) then
			spawnPosition = nextRootPosition + Vector3.new(-0.5, 0, 0)
		elseif nextRootPosition == previousRoot.Position + Vector3.new(0, 0, -1) then
			spawnPosition = nextRootPosition + Vector3.new(0, 0, 0.5)
		elseif nextRootPosition == previousRoot.Position + Vector3.new(0, 0, 1) then
			spawnPosition = nextRootPosition + Vector3.new(0, 0, -0.5)
		
		local newRoot = Instance.new("Part")
		newRoot.Anchored = false
		newRoot.Size = Vector3.new(0.002, 0.002, 0.002)
		newRoot.Position = spawnPosition
		newRoot.Color = Color3.fromRGB(80, 109, 84)
		newRoot.Parent = workspace.Overgrowth
		newRoot.Name = tostring("root".. tostring(#RootList + 1))
		
		for i, c in pairs(parameters[2][1]) do
			local weld = Instance.new("WeldConstraint")
			weld.Part0 = newRoot
			weld.Part1 = c
			weld.Parent = newRoot
		end
		
		local growthTweenGoals = {}
		growthTweenGoals.Position = nextRootPosition
		growthTweenGoals.Size = Vector3.new(1, 1, 1)
		
		local growthTweenInfo = TweenInfo.new(1, Enum.EasingStyle.Exponential, Enum.EasingDirection.Out, 0, false, 0)

		local growthTween = TweenService:Create(newRoot, growthTweenInfo, growthTweenGoals)

		growthTween:Play()
		
		print(RootList)
		
	else
		print("smth went wrong")
	end
end

script.Parent.MouseClick:Connect(function()
	repeat
		SpawnNextRoot((RootList[#RootList]), GetBest(RootList[#RootList], GetNeighbors(RootList[#RootList])))
		task.wait(2)
	until	
	#RootList == 25
end)

Still no solution, sadly. I even looked up other topics about that, but could not find a really close situation to mine.

You’re trying to achieve this?

local function x()
    return 2, 3
end

local function y(a, b, c)
    print(a, b, c)
end

y(1, x())
-- As y(1, 2, 3)

The above code works just fine

Almost, except that the returned values in function x are 2 tables.

That doesn’t change the outcome

Yeah, but for me it does not work for some reason. There should be an explanation why

Have you confirmed the arguments you receive are unexpected? Maybe it’s a design flaw in the receiving function rather than an issue of argument delivery

I will check this tomorrow, but I am pretty sure there are no problems with the function.

The concerning thong is that print(list1, list2) in said function does not show up at all. This is the only sign function does not work at all, but I cant see the reason why

So I had a little play around with the code and the results of the functions appear to be passing as parameters correctly.
The new roots being created weren’t being added to the rootlist table meaning when getting the length of the rootlist to use as an index, a nil value was returned. I also found a couple of formatting errors in the code sample provided.
The code below worked for me, generating new root parts and attempting to bypass obstacles (although the growth pattern seemed predictable)

Code

I also added a bit of typechecking to help me understand it all.

--!strict

local TweenService = game:GetService("TweenService")

local RootList = {}

local heart = workspace.Overgrowth.OvergrowthHeart

table.insert(RootList, heart)

local function GetNeighbors(previousRoot:Part):{Vector3}

	local availableSpots = {}

	local overlapParams = OverlapParams.new()
	overlapParams.FilterDescendantsInstances = {workspace.Overgrowth:GetChildren(), workspace:GetChildren()}
	overlapParams.FilterType = Enum.RaycastFilterType.Include

	local UpCheckBoxResult = workspace:GetPartBoundsInBox(previousRoot.CFrame * CFrame.new(0, 1, 0), Vector3.new(0.8, 0.8, 0.8), overlapParams)
	local DownCheckBoxResult = workspace:GetPartBoundsInBox(previousRoot.CFrame * CFrame.new(0, -1, 0), Vector3.new(0.8, 0.8, 0.8), overlapParams)
	local LeftCheckBoxResult = workspace:GetPartBoundsInBox(previousRoot.CFrame * CFrame.new(-1, 0, 0), Vector3.new(0.8, 0.8, 0.8), overlapParams)
	local RightCheckBoxResult = workspace:GetPartBoundsInBox(previousRoot.CFrame * CFrame.new(1, 0, 0), Vector3.new(0.8, 0.8, 0.8), overlapParams)
	local FrontCheckBoxResult = workspace:GetPartBoundsInBox(previousRoot.CFrame * CFrame.new(0, 0, -1), Vector3.new(0.8, 0.8, 0.8), overlapParams)
	local BackCheckBoxResult = workspace:GetPartBoundsInBox(previousRoot.CFrame * CFrame.new(0, 0, 1), Vector3.new(0.8, 0.8, 0.8), overlapParams)

	if #UpCheckBoxResult == 0 then
		table.insert(availableSpots, previousRoot.Position + Vector3.new(0, 1, 0))
	end

	if #DownCheckBoxResult == 0 then
		table.insert(availableSpots, previousRoot.Position + Vector3.new(0, -1, 0))
	end

	if #LeftCheckBoxResult == 0 then
		table.insert(availableSpots, previousRoot.Position + Vector3.new(-1, 0, 0))
	end

	if #RightCheckBoxResult == 0 then
		table.insert(availableSpots, previousRoot.Position + Vector3.new(1, 0, 0))
	end

	if #FrontCheckBoxResult == 0 then
		table.insert(availableSpots, previousRoot.Position + Vector3.new(0, 0, -1))
	end

	if #BackCheckBoxResult == 0 then
		table.insert(availableSpots, previousRoot.Position * Vector3.new(0, 0, 1))
	end

	return availableSpots

end

local function GetBest(previousRoot:Part, positionsArray:{Vector3}):{Part|Vector3}
	if #positionsArray == 0 then warn("No positions in array") return {} end

	local overlapParams = OverlapParams.new()
	overlapParams.FilterType = Enum.RaycastFilterType.Include
	overlapParams.FilterDescendantsInstances = {workspace.Structures:GetChildren(), workspace.Overgrowth:GetChildren()}

	local valueList = {}	::{number}
	local connectionsList = {}	::{[number]:{number}}

	for i, pos in pairs(positionsArray) do

		local connections = {} ::{number}

		local rightCheckBoxResult = workspace:GetPartBoundsInBox(previousRoot.CFrame * CFrame.new(1.5, 0, 0), Vector3.new(0.2, 0.8, 0.8), overlapParams)
		local leftCheckBoxResult = workspace:GetPartBoundsInBox(previousRoot.CFrame * CFrame.new(-1.5, 0, 0), Vector3.new(0.2, 0.8, 0.8), overlapParams)
		local upCheckBoxResult = workspace:GetPartBoundsInBox(previousRoot.CFrame * CFrame.new(0, 1.5, 0), Vector3.new(0.8, 0.2, 0.8), overlapParams)
		local downCheckBoxResult = workspace:GetPartBoundsInBox(previousRoot.CFrame * CFrame.new(0, -1.5, 0), Vector3.new(0.8, 0.2, 0.8), overlapParams)
		local backCheckBoxResult = workspace:GetPartBoundsInBox(previousRoot.CFrame * CFrame.new(0, 0, 1.5), Vector3.new(0.8, 0.8, 0.2), overlapParams)
		local frontCheckBoxResult = workspace:GetPartBoundsInBox(previousRoot.CFrame * CFrame.new(0, 0, -1.5), Vector3.new(0.8, 0.8, 0.2), overlapParams)

		local connectionValue = 0

		if #rightCheckBoxResult > 0 then
			connectionValue += 1
			table.insert(connections, rightCheckBoxResult)
		end
		if #leftCheckBoxResult > 0 then
			connectionValue += 1
			table.insert(connections, leftCheckBoxResult)
		end
		if #upCheckBoxResult > 0 then
			connectionValue += 1
			table.insert(connections, upCheckBoxResult)
		end
		if #downCheckBoxResult > 0 then
			connectionValue += 1
			table.insert(connections, downCheckBoxResult)
		end
		if #backCheckBoxResult > 0 then
			connectionValue += 1
			table.insert(connections, backCheckBoxResult)
		end
		if #frontCheckBoxResult > 0 then
			connectionValue += 1
			table.insert(connections, frontCheckBoxResult)
		end

		table.insert(valueList, connectionValue)
		connectionsList[i] = connections

	end

	local bestValue = math.max(unpack(valueList)) or 1	::number
	local bestValueIndex = table.find(valueList, bestValue)	::number

	local bestOfTheBestValues = {}
	local bestOfTheBestPositions = {}
	local bestOfTheBestConnections = {}

	for i, v in pairs(valueList) do
		if v == bestValue then
			table.insert(bestOfTheBestValues, v)
			table.insert(bestOfTheBestPositions, positionsArray[bestValueIndex])
			table.insert(bestOfTheBestConnections, connectionsList[bestValueIndex])
		end
	end

	local nextPositionIndex = math.random(1, #bestOfTheBestValues)

	local nextPosition = bestOfTheBestPositions[nextPositionIndex]
	local nextConnection = bestOfTheBestConnections[nextPositionIndex]

	local positionsAndConnections = {
		[1] = nextPosition;
		[2] = nextConnection
	}

	print(positionsAndConnections)

	return positionsAndConnections

end


local function SpawnNextRoot(previousRoot:Part, parameters:{[number]:Vector3|{Part}})

	local nextRootPosition = parameters[1] ::Vector3

	local spawnPosition

	if nextRootPosition == previousRoot.Position + Vector3.new(0, 1, 0) then
		spawnPosition = nextRootPosition + Vector3.new(0, -0.5, 0)
	elseif nextRootPosition == previousRoot.Position + Vector3.new(0, -1, 0) then
		spawnPosition = nextRootPosition + Vector3.new(0, 0.5, 0)
	elseif nextRootPosition == previousRoot.Position + Vector3.new(-1, 0, 0) then
		spawnPosition = nextRootPosition + Vector3.new(0.5, 0, 0)
	elseif nextRootPosition == previousRoot.Position + Vector3.new(1, 0, 0) then
		spawnPosition = nextRootPosition + Vector3.new(-0.5, 0, 0)
	elseif nextRootPosition == previousRoot.Position + Vector3.new(0, 0, -1) then
		spawnPosition = nextRootPosition + Vector3.new(0, 0, 0.5)
	elseif nextRootPosition == previousRoot.Position + Vector3.new(0, 0, 1) then
		spawnPosition = nextRootPosition + Vector3.new(0, 0, -0.5)
	end
	local newRoot = Instance.new("Part")
	newRoot.Anchored = false
	newRoot.Size = Vector3.new(0.002, 0.002, 0.002)
	newRoot.Position = spawnPosition
	newRoot.Color = Color3.fromRGB(80, 109, 84)
	newRoot.Parent = workspace.Overgrowth
	newRoot.Name = tostring("root".. tostring(#RootList + 1))
	
	table.insert(RootList, newRoot)
	if #parameters[2] == 0 then
		local weld = Instance.new("WeldConstraint")
		weld.Part0 = newRoot
		weld.Part1 = heart
		weld.Parent = newRoot
	else
		for i, c in pairs(parameters[2][1]) do
			local weld = Instance.new("WeldConstraint")
			weld.Part0 = newRoot
			weld.Part1 = c
			weld.Parent = newRoot
		end
	end
	

	local growthTweenGoals = {}
	growthTweenGoals.Position = nextRootPosition
	growthTweenGoals.Size = Vector3.new(1, 1, 1)

	local growthTweenInfo = TweenInfo.new(1, Enum.EasingStyle.Exponential, Enum.EasingDirection.Out, 0, false, 0)

	local growthTween = TweenService:Create(newRoot, growthTweenInfo, growthTweenGoals)

	growthTween:Play()

	print(RootList)

end

script.Parent.MouseClick:Connect(function()
	repeat
		SpawnNextRoot((RootList[#RootList]), GetBest(RootList[#RootList], GetNeighbors(RootList[#RootList])))
		task.wait(2)
	until #RootList == 25
end)

Hi, thanks for actually trying my code. I hope you had at least a little bit of fun with it. I am not quite sure what are formatting errors, but will take your code as an example to see what I have done wrong. I am also wondering what you mean by “attempting to bypass obstacles” as in my idea the code should just make sure root does not spawn in obstacles, but instead uses them as support for the root, using weld constraints.

Yeah, I guessed it’s supposed to anchor to things in the structures folder/model, but just to test I just placed an anchored part above it and the root tried to then grow around it by growing to the side then down to the side and back up again until it came out from under it. (It seems to have a definite preferred growth direction)
I was mainly concerned with getting it working, and I didn’t really change much, just a missed end statement on an else if chain, and that it wasn’t adding to the root list.
I prefer writing code in strict, so the whole code block turned blue as soon as I added that, and so added a bit of logic to check the parameter types. Which made it easier to spot that one of the passed parameters was nil, and could trace that back to figure out why.

But yeah I did have a little fun with it :grin:

Yeah, my code is kind of unfinished. In my idea, root should go to a random direction, but if there is a possible connection to a part, he would choose to grow towards that part. The only issue? The previous root is considered a part too. So, I am planning to adding additional “check” where I will use a loop to go through “connections” to see if there are any connections that are actually a root, and if there is, the value of position with these connections would go down.