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
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
Great idea!
This is a function which I find that I often need myself. I wonder if it should be part of vmath?
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
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
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
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).
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.
One of my favorite Lua function libs:
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
Yes, the clamp function is really useful. Is it part of vmath now?
No, we haven’t made any additions to vmath.