Small Useful Functions

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
foo0
Prole
Posts: 35
Joined: Sun Apr 27, 2014 10:25 am

Re: Small extra functions

Post by foo0 » Tue May 06, 2014 10:28 am

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

Post by WetDesertRock » Tue May 06, 2014 2:24 pm

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

Post by foo0 » Tue May 06, 2014 3:42 pm

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

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

Re: Small extra functions

Post by HugoBDesigner » Thu May 08, 2014 4:32 am

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 :awesome:

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 Twitter
HugoBDesigner - my Blog

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

Re: Small extra functions

Post by HugoBDesigner » Sun May 11, 2014 9:13 pm

Two more codes. One to load quads from an image:

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 horizontalquads = math.floor(image:getWidth()/width)
	local verticalquads = math.floor(image:getHeight()/height)
	
	local returner = {}
	
	for y = 1, verticalquads do
		for x = 1, horizontalquads do
			table.insert(returner, {image = image, quad = love.graphics.newQuad((x-1)*width, (y-1)*height, width, height)})
		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 Twitter
HugoBDesigner - my Blog

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

Re: Small extra functions

Post by foo0 » Sun May 11, 2014 10:28 pm

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

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

Re: Small extra functions

Post by HugoBDesigner » Sun May 11, 2014 10:45 pm

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 Twitter
HugoBDesigner - my Blog

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

Re: Small extra functions

Post by Robin » Mon May 12, 2014 11:37 am

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.
Help us help you: attach a .love.

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

Re: Small extra functions

Post by HugoBDesigner » Mon May 12, 2014 12:47 pm

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")
local quads = {}
table.merge(quads, love.loadQuads(img, quadWidth, quadHeight)
table.merge(quads, love.loadQuads(img2, quadWidth, quadHeight)
table.merge(quads, love.loadQuads(img3, quadWidth, quadHeight)
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 Twitter
HugoBDesigner - my Blog

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

Re: Small extra functions

Post by foo0 » Mon May 12, 2014 2:27 pm

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

Post Reply

Who is online

Users browsing this forum: No registered users and 2 guests