Local variable in function

Hi,

I’m new to defold and .lua scripting. I want to know if it is a good idea to set a local variable in a function like in my example below:

function rotate()
	local colorwheel = msg.url("colorwheel")
	local spinner = msg.url("spinner")
	go.animate(colorwheel, "euler.z", go.PLAYBACK_LOOP_BACKWARD, 360,go.EASING_LINEAR, 2.0)
	go.animate(spinner, "euler.z", go.PLAYBACK_LOOP_FORWARD, 360,go.EASING_LINEAR, 2.0)
end

Everytime I execute the rotate function will it create a local variable and is it a good practice to set my go.animate’s url = to my local variable?

Thank you.

This does not affect the performance in any noticable way at all. Local variables in Lua are really, really quick. While you don’t necessarily need it, and while readability is not really improved nor made worse in my eyes, at least, it is completely up to you. If you can read the code faster with it - go ahead.

2 Likes

Thats good to know.
Will it make any difference if you use a string or the local variable as the go.animate’s url?

My concern is the use of strings, because I know the trouble of strings in Unity3D.

The strings are hashed by the engine. I assume every frame though so if you pre-hash it’s faster. (What is the actual source of the builtin hash function?)

You can use a hash instead of a string, and then hash your strings once to get their hashes.

This version of a kind of helper function for this is the easiest to use IMO https://github.com/subsoap/ahash

For urls you would use it like ahash[“url”]

Anyone with access to the Defold source could give a definitive answer on what’s best to use. A string may be just as fast.

3 Likes

There is a cost associated with creating new url objects, and a slight difference if you reuse hashes. In tight loops this may matter. On my machine i get the following results on 1 million iterations. The difference may be bigger or smaller on a handheld.

for i=1,1000000 do
	test(msg.url("hello"))
end
-- 0.78450298309326 seconds
local h = hash("/hello")
for i=1,1000000 do
	test(msg.url(h))
end
-- 0.61077499389648 seconds
local url = msg.url("hello")
for i=1,1000000 do
	test(url)
end
-- 0.10395789146423 seconds
7 Likes

If you reference these objects elsewhere in the script you can make them local to the script file instead:

-- objects
local colorwheel = msg.url("colorwheel")
local spinner = msg.url("spinner")

...

function rotate()
	go.animate(colorwheel, "euler.z", go.PLAYBACK_LOOP_BACKWARD, 360,go.EASING_LINEAR, 2.0)
	go.animate(spinner, "euler.z", go.PLAYBACK_LOOP_FORWARD, 360,go.EASING_LINEAR, 2.0)
end
4 Likes

I’ve made a similar convenience all in one place storage / generation helper for URLs now.

1 Like

Do you place the following line in every script that use urls?

local aurl = require("aurl.aurl")

Yes.

Or you can require it globally if you want all scripts to be able to use it.

1 Like

Should I create a script with all my urls in it and then set it globally so that I can use it in my entire project or how should the urls be created?

You can make a Lua module and list all of your urls there if you would like. AURL does this kind of thing automatically for you. A manual version would look like

urlmodule.lua

local M = {}

M.my_url = msg.url("my_url")

return M

A script using urlmodule.lua

local urls = require("urlmodule")

print(urls.my_url)

1 Like

Whenever I try to use a manual version I get an error saying:

:exclamation:go.set can only access instances within the same collection.

urls.lua

local URLS = {}

URLS.colorwheel = msg.url("colorwheel")
URLS.spinner = msg.url("spinner")

return URLS

object.script

local urls = require("assets.scripts.modules.urls")

function rotate()
	go.set(urls.colorwheel, "euler.z", 0)
	go.set(urls.spinner, "euler.z", 0)
end

I think your reference of url is in another collection, then you should write it in complete reference, ex: “main:/go_colorspinner”

go.set() and go.get() can’t be used to reference components in other “root” collections, or game worlds. That is, collections that has been loaded via proxy. To communicate between collections loaded by proxy, use message passing.

The error message is unclear. Any suggestions for how to make it better?

I just copied the error log message directly from the console. I just want to reuse the urls that I have created previously instead of creating new ones everytime.

On second thought this is more intricate than I first realized. The following example illustrates the problem:

local url1 = msg.url("test")

function init(self)
	local url2 = msg.url("test")
	print(url1)
	print(url2)
end
--> DEBUG:SCRIPT: url: [:test]
--> DEBUG:SCRIPT: url: [default:/test]

If you are using msg.url() in the top level context the engine cannot infer the socket (since it runs outside of the lifecycle functions of the script component). You end up with a faulty url object. There are two ways to fix this:

  1. Specify the socket in the urls (local url1 = msg.url("default:/test")). Using a relative address is generally a better idea so I would advice against this.
  2. Use hash paths instead of complete urls:
local IDS = {}

IDS.colorwheel = hash("colorwheel")
IDS.spinner = hash("spinner")

return IDS

(Edit: the reason for using relative paths is that it allows you to build objects with script that will work regardless of where in the collection hierarchy you place the objects)

3 Likes