## Small Useful Functions

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
foo0
Prole
Posts: 35
Joined: Sun Apr 27, 2014 10:25 am

### Re: Small extra functions

Code: Select all

function round(n, r)
local r = r or 0
return math.floor(n*10^r)/10^r
end
More appropriate name for that function would be roundDown, because it returns values like this:
1.5 -> 1
-1.5 -> -2

The "classic round" rounds values away from zero when the decimal part is greater than or equal to 0.5, and towards zero when less than 0.5. That's how C++'s std::round does this. It returns values like this:
1.5 -> 2
-1.5 -> -2

Here's a snippet of most common round variations:

Code: Select all

-- "Classic round", rounds away from zero in halfway cases.
function round(num, idp)
local shift = idp and 10 ^ idp or 1

if num < 0 then
return math.ceil(num * shift - 0.5) / shift
end

return math.floor(num * shift + 0.5) / shift
end

function roundDown(num, idp)
local shift = idp and 10 ^ idp or 1

return math.floor(num * shift) / shift
end

function roundUp(num, idp)
local shift = idp and 10 ^ idp or 1

return math.ceil(num * shift) / shift
end

-- Truncates decimal part, leaving the rest of the number unchanged.
function trunc(num, idp)
local shift = idp and 10 ^ idp or 1

if num > 0 then
return math.floor(num * shift) / shift
end

return math.ceil(num * shift) / shift
end

function roundAwayFromZero(num, idp)
local shift = idp and 10 ^ idp or 1

if num > 0 then
return math.ceil(num * shift) / shift
end

return math.floor(num * shift) / shift
end

WetDesertRock
Citizen
Posts: 67
Joined: Fri Mar 07, 2014 8:16 pm

### Re: Small extra functions

Forgive me, but why can't 'trunc' be replaced by math.floor?

foo0
Prole
Posts: 35
Joined: Sun Apr 27, 2014 10:25 am

### Re: Small extra functions

Because they're not equal. They return the same values if x >= 0, but different when x < 0. Know how each function work and choose one that fits the purpose. If you know that x will always be >= 0, it doesn't matter if you use math.floor or trunc, but for negative x they work differently, e.g.:

Code: Select all

trunc(4.2)       == 4
math.floor(4.2)  == 4

trunc(-4.2)      == -4
math.floor(-4.2) == -5

HugoBDesigner
Party member
Posts: 403
Joined: Mon Feb 24, 2014 6:54 pm
Location: Somewhere in Brazil
Contact:

### Re: Small extra functions

A code I wrote to convert frames to quads (a new image in quad format)! It saves me infinite minutes of doing it by hand

Code: Select all

	local folder = "glow"
local newfile = "glow"

local files = love.filesystem.enumerate(folder)

local newwidth = 0
local newheight = 0
local imagestable = {}

local n = 0
for i, v in pairs(files) do
if string.sub(files[i], -4, -1) == ".png" then
n = n + 1
table.insert(imagestable, love.image.newImageData(folder .. "/" .. files[i]))
newwidth = newwidth + imagestable[n]:getWidth()
if imagestable[n]:getHeight() > newheight then
newheight = imagestable[n]:getHeight()
end
end
end

local newimage = love.image.newImageData(newwidth, newheight)

for i = 1, #imagestable do
for x = 1, imagestable[i]:getWidth() do
for y = 1, imagestable[i]:getHeight() do
local pixeltoset = {(i-1)*imagestable[i]:getWidth()+(x-1), y-1}
local r, g, b, a = imagestable[i]:getPixel(x-1, y-1)
newimage:setPixel(pixeltoset[1], pixeltoset[2], r, g, b, a)
end
end
end

newimage:encode(newfile .. ".png")

For LÖVE 0.8.0. To use in LÖVE 0.9.0, just replace the "love.filesystem.enumerate" by "love.filesystem.getDirectoryItems"
HugoBDesigner - my Blog

HugoBDesigner
Party member
Posts: 403
Joined: Mon Feb 24, 2014 6:54 pm
Location: Somewhere in Brazil
Contact:

### Re: Small extra functions

The mode can be "size" (you specify the quads' size - the default mode) or "amount" (number of quads horizontally and vertically)

Code: Select all

function love.getQuads(image, width, height, mode)
local width = width
local height = height
local mode = mode or "size"
if mode == "amount" then
width = math.floor(image:getWidth()/width)
height = math.floor(image:getHeight()/height)
end

local returner = {}

for y = 1, verticalquads do
for x = 1, horizontalquads do
end
end
return returner
end

It returns a table. Each item of the table is a table too, with the image (table["image"]) and the quad (table["quad"]). To draw, you can just do love.graphics.draw(table["image"], table["quad"], ...)

Also a function to merge two tables. Not the most practical function, but saves time and keeps your code clean:

Code: Select all

function table.merge(t1, t2)
local ret = {}
for i, v in pairs(t1) do
table.insert(ret, v)
end
for i, v in pairs(t2) do
table.insert(ret, v)
end
return ret
end

Last edited by HugoBDesigner on Mon May 12, 2014 2:51 am, edited 1 time in total.
HugoBDesigner - my Blog

foo0
Prole
Posts: 35
Joined: Sun Apr 27, 2014 10:25 am

### Re: Small extra functions

Merge t1 and t2 into t1:

Code: Select all

function table.merge(t1, t2)
for k, v in pairs(t2) do
t1[k] = v
end
return t1
end

HugoBDesigner
Party member
Posts: 403
Joined: Mon Feb 24, 2014 6:54 pm
Location: Somewhere in Brazil
Contact:

### Re: Small extra functions

At first I was going to do this, but then came the question: does it automatically changes the original table?
Because if yes, then I'd still prefer mine, because you can make a completely different table with the data of both merged functions...
HugoBDesigner - my Blog

Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

### Re: Small extra functions

HugoBDesigner wrote:At first I was going to do this, but then came the question: does it automatically changes the original table?
Yes.

Your version probably doesn't do what you want, though, because it merges {x = 1} and {y = 2} into {1, 2}.

What you'd probably want is closer to foo0's version:

Code: Select all

function mergetables(...)
local ret = {}
for i, tbl in ipairs {...} do
for k, v in pairs(tbl) do
ret[k] = v
end
end
return ret
end
Notes:
1. I renamed it to mergetables. Modifying the standard library is bad, don't do it.
2. This one handles an arbitrary number of tables, not just two. Passing one makes a shallow copy of it.
3. In the case of conflicting keys, the last one wins, like in foo0's version.

HugoBDesigner
Party member
Posts: 403
Joined: Mon Feb 24, 2014 6:54 pm
Location: Somewhere in Brazil
Contact:

### Re: Small extra functions

Your version is WAAAAY better, thank you! But won't it replace values? Like:

Code: Select all

t1 = {"first value", a = 2}
t2 = {"another first value", b = 3}
mergetables(t1, t2)
--returns {"another first value", a = 2, b = 3}

EDIT: Nevermind. It's written in your post this...

Also, for what I needed my function worked. It was something like this (about the love.loadQuads function):

Code: Select all

local img = love.graphics.newImage("something.png")
local img2 = love.graphics.newImage("something2.png")
local img3 = love.graphics.newImage("something3.png")

It was for a game with an image with quads that didn't fit the 512x512 size. We had to split it in 2 images, and to make things easier I made this function to load and draw both with a single draw:

Code: Select all

love.graphics.draw(quads[frame]["image"], quads[frame]["quad"], ...)


EDIT 2: Can't we make this to solve the problem:

Code: Select all

function mergetables(...)
local ret = {}
local val = 0
for i, tbl in ipairs {...} do
for k, v in pairs(tbl) do
if type(k) == "number" then
val = val + 1
ret[val] = v
else
ret[k] = v
end
end
end
return ret
end
HugoBDesigner - my Blog

foo0
Prole
Posts: 35
Joined: Sun Apr 27, 2014 10:25 am

### Re: Small extra functions

You can use table.insert like in your first version:

Code: Select all

function mergetables(...)
local ret = {}
for i, tbl in ipairs {...} do
for k, v in pairs(tbl) do
if type(k) == "number" then
table.insert(ret, v)
else
ret[k] = v
end
end
end
return ret
end

### Who is online

Users browsing this forum: No registered users and 2 guests