 # Lua Utility Functions

Hi all,

What is this and how do I contribute?

This is a list of Lua utility functions created by the Defold community. Functions should be generalized for use in any Defold project. Include a brief description of your function and be mindful of naming clarity. Please only include one function per reply for easy linking. If you have an alternative implementation of an already submitted function, please feel free to post it! I will keep the below list updated as best I can.

Conversions

Bounds Checking

Other

External Libraries

Happy Defolding!

12 Likes

Clamp `value` between `min` and `max`:

``````local function clamp(value, min, max)
if value < min then
return min
end
if value > max then
return max
end
return value
end
``````

Change of base formula for `math.log()` expressions:

``````local function log_base(base, expression)
return math.log(expression) / math.log(base)
end
``````

Check if `value` is between `min` and `max`:

``````local function is_within_range(value, min, max)
return min <= value and value <= max
end``````

Calculate Manhattan distance between two points:

``````local function manhattan_distance(from, to)
return vmath.vector3(to.x - from.x, to.y - from.y, to.z - from.z)
end
``````

Get the sign of a number (1 for positive numbers, -1 for negative numbers, and 0 for zero):

``````local function sign(n)
return n > 0 and 1 or (n < 0 and -1 or 0)
end
``````

Converts a hex string to a vector4

``````function hex_to_color(hex)
local r, g, b = hex:match("#(%x%x)(%x%x)(%x%x)")
r, g, b = tonumber(r, 16), tonumber(g, 16), tonumber(b, 16)
return vmath.vector4(r / 255, g / 255, b / 255, 1)
end
``````
1 Like

Great idea!

This is a function which I find that I often need myself. I wonder if it should be part of vmath?

6 Likes

Check if `point` is within `rectangle`:

``````local function is_within_rectangle(point_x, point_y, rect_x, rect_y, rect_width, rect_height)
return rect_x <= point_x and point_x <= rect_x + rect_width and rect_y <= point_y and point_y <= rect_y + rect_height
end``````

I think that would be a good addition. Maybe better for the `math` module, but if I understand correctly, `math` is built into the Lua language.

Here’s a bunch of stuff I collected over the years:

Also, a good animation tool I’ve found useful are low-pass filters for creating snapping effects or smoothing out movements:

https://github.com/critique-gaming/crit/blob/master/crit/filters.lua

3 Likes

I wrote this function when I was trying to pprint some enormous tables full of subtables.

``````    --individually prints each line of a nested table
local function recursive_pprint(t, table_name)

if not t then
return
end

table_name = table_name or ""
local type_table = "table"
for key, value in pairs(t) do
if type(value) == type_table then
recursive_pprint(value, key)
else
print(table_name .. ": " .. key .. ": ", value)
end
end
``````
3 Likes

Awesome. I actually have something similar too. See `table_util.dump()` above. The cool part is that it outputs valid Lua most of the time

3 Likes

Accurate framerate-independent lerp with delta-time:

``````-- `rate` is the lerp coefficient per second. So rate=0.5 halves the difference every second.
local function lerpdt(from, to, rate, dt)
local diff = from - to           -- Target value is just an offset. Remove it and add it back.
return diff * (1 - rate)^dt + to -- Flip rate so it's the expected direction (0 = no change).
end
``````

Thanks to this site for the correct explanation.

Normally, the `rate` is the lerp coefficient per second. To adjust the time frame, divide `dt` by the desired time.

For example, if you want to halve a value every 1/60th of a second, do:

`lerpdt(from, to, 0.5, dt/(1/60))`

Has been unit tested. A basic test:

``````from, to, rate = 10, 0, 0.25

-- Lerp over 1 second all at once:
local result = lerpdt(from, to, rate, 1)

-- Lerp iteratively with times adding up to 1:
from = lerpdt(from, to, rate, 0.75)
from = lerpdt(from, to, rate, 0.01)
from = lerpdt(from, to, rate, 0.21)
from = lerpdt(from, to, rate, 0.01)
from = lerpdt(from, to, rate, 0.01)
from = lerpdt(from, to, rate, 0.01)
-- `from` and `result` should be equal (with some floating point error).
``````
3 Likes

Thanks everyone. I will change the list in the first post to include categories to improve organization.

I’m having some trouble seeing how this is different than `vmath.lerp()` example from the docs: API reference (vmath)

It looks to me like the new part is the `rate` parameter?

The function I posted is framerate-independent. It can be used continuously in update() (i.e. without having a start and end time to the interpolation).

Let’s say you have a value that you want to halve every frame. Maybe you’re remaking Nuclear Throne and you want to damp the velocity of a shotgun bullet. If you do:

``````function update(self, dt)
self.velocity = vmath.lerp(0.5, self.velocity, 0)
end
``````

That is wrong. It will vary quite a bit depending on your framerate.
This is also wrong:

``````self.velocity = vmath.lerp(0.5*dt, self.velocity, 0)
``````

Basically, you need this any time you want to continuously move one value towards another. Camera smoothing is another good example.

5 Likes

One of my favorite Lua function libs:

7 Likes

Hmm. That looks interesting. It’s definitely not a “LERP” since that’s a linear interpolation and the result here is not linear. More rather it’s sort-of like a low-pass filter, as in a function that always tends towards the target (if you take its limit), but “lags behind” a bit hence cutting off any abrupt movements (higher frequencies). I’m happy to see I’m not the only one using low pass filters for animation, yay!

I use this version lifted off the Wikipedia article on low pass filters:

``````-- @tparam number cutoff_frequency The cut-off frequency (in Hz) of the filter.
-- @treturn LowPassFilter The new filter function.
function M.low_pass(cutoff_frequency)
local RC = 1.0 / (cutoff_frequency * 2.0 * math.pi);
return function (previous_output, input, dt)
local alpha = dt / (dt + RC);
return previous_output + alpha * (input - previous_output);
end
end
``````
7 Likes

Yes, the clamp function is really useful. Is it part of vmath now?

1 Like