Calling a function from a variable as an argument

Greetings!

I’ve been searching Lua and Defold manuals and have tried experimenting, but I haven’t found a solution to my problem. Here’s what I’m trying to do: I’ve created a loop that skips a few calls so that I’m not running a function and checking it every billionth of a millisecond. With this loop I’ve added an argument so that I can call whatever function is in that argument every time the loop succeeds. The problem I’m having is that I’m trying to run a function from a variable, and every time I do that the engine asks me to give that variable a value or that I need to name the function I’m trying to call (On the different experiments I made).

function init(self)
    fire = printme()

function printme()
	if printme >= 1200 then
		loop("end")
	else
		printOne = printOne + 1
		print(printOne)
	end
end

function loop(fire)
	for i=100,0,-1 do
		if i == 0 and fire ~= "end" then
			function(fire)
			loop()
		elseif i % 10 == 0 and fire ~= "end" then
			function(fire)
		else print ("loop closed")
		end
	end
end

You have incorrect syntax as the first problem. function is a keyword, you can’t use it for anything other than defining functions. When you want to call the passed function fire, you just write fire(). And when you want to assign a variable to a function value, you don’t use parenthesis, because that would be function execution.
As for the loop, it’s much better idea to use timer to skip frames, you can’t skip frames with simple loops, as they would halt game execution.

What you want might look something like that

function init(self)
    local printOne = 0

	local function printme()
		if printme >= 1200 then
			-- Stop loop
			self.loop_end = true
		else
			printOne = printOne + 1
			print(printOne)
		end
	end

	-- Assign function to be called
	self.loop_function = printme
	self.loop_end = false
end

-- Skippping frames, loop executes only once in 10 frames
local SKIP_FRAMES = 10
local skipped_frames = SKIP_FRAMES

local function loop(self)
	-- Skipping frames if greater than 0
	if skipped_frames > 0 then
		skipped_frames = skipped_frames - 1
		return -- Exit funciton
	else
		-- Reset skipping value, continue function
		skipped_frames = SKIP_FRAMES
	end
	-- Proceed only if we have a function to call
	if self.loop_function then
		if not self.loop_end then
			-- Call the function until the end
			self.loop_function()
		else
			-- Stop and clear the function variable
			print("loop closed")
			self.loop_function = nil
		end
	end
end

function update(self)
	-- Call the loop each frame
	loop(self)
end
1 Like

Thank you. The main reason for this loop was so that processing speeds would be dramatically better. This loop would help to that effect right, or would the checks in the loop still slow the CPU down? I’ll write this in when I get time. Thanks again.

No, running a for loop will stop your whole game until the loop finishes. There is no delay between iterations.

1 Like

Sigh, there is so much I don’t know. I’ve never gotten schooling for programming; everything I’ve learned has been through trail and error. I’ve learned a lot and I adapt easily to things I don’t know, but that’s the problem. Would a while loop work then?

No. All loops, be they for loops, while loops or repeat-until loops, will block until they are done. You could however solve it using what is called a coroutine. A coroutine is a chunk of Lua code where the execution can be paused and resumed. It’s a kind of collaborative multitasking. Lua is still single threaded, but you can have coroutines running some code for a while, then yielding control back to the main thread and at a later point become resumed again, perhaps the next frame or when some other condition is met. An example:

local function loop(self, fn)
	self.co = coroutine.create(function()
		-- this code will be run within the coroutine
		for i=100,0,-1 do
			if i % 10 == 0 then
				-- call the function
				fn(self, false)
			end
			-- give back control to the main thread
			-- ie when run one iteration of the loop every time the coroutine
			-- is resumed
			coroutine.yield()
		end
		fn(self, true)
		print("loop and coroutine ended")
	end)
end

local function fire(self, ended)
	print("fire")
end

local function reload(self, ended)
	print("reloading")
	if ended then
		loop(self, fire)
	end
end

function init(self)
	loop(self, reload)
end

function update(self, dt)
	-- resume the coroutine if it exists and is suspended (ie paused/yielded)
	if self.co and coroutine.status(self.co) == "suspended" then
		coroutine.resume(self.co)
	end
end
4 Likes