 # Lua Utility Functions

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