Libraries

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.
Neon
Prole
Posts: 16
Joined: Sun Apr 01, 2012 3:46 pm

Libraries

Post by Neon » Sun Apr 01, 2012 3:50 pm

I'm very new to Love2D, I've only been experimenting with it for a couple days. My questions are about libraries. How do I make one? Why should I make one? Where do I start? What else should I know? Just all the information you can give me about libraries and making them will be useful. I'm planning on making a GUI library but have no clue where to start. I am rather fluent with most of Lua and have been programming with it for a while, so I should be able to comprehend your replies. Thanks.

User avatar
rokit boy
Party member
Posts: 198
Joined: Wed Jan 18, 2012 7:40 pm

Re: Libraries

Post by rokit boy » Sun Apr 01, 2012 4:05 pm

A library is something that takes what you can do in lua and simplifying it for you or other users.

In the library you are making, you need some functions.

Here is something that you could do:

Code: Select all

-- NOTE: THIS IS AN EXAMPLE

function printHi()
print("hi")
end
You can save it as "MyLib.lua".

Then in your main.lua:

Code: Select all

require "MyLib"

function love.load()
printHi()
end
There are better ways for keeping your lib tidy:

1,

Code: Select all

-- NOTE: THIS IS AN EXAMPLE

function printHi()
print("hi")
end
You can save it as "MyLib.lua".

Then in your main.lua:

Code: Select all

mylib = require "MyLib"

function love.load()
mylib.printHi()
end
2 (my favourite),

Code: Select all

-- NOTE: THIS IS AN EXAMPLE

mylib = {} -- Table for all functions

function mylib.printHi()
print("hi")
end
You can save it as "MyLib.lua".

Then in your main.lua:

Code: Select all

require "MyLib"

function love.load()
mylib.printHi()
end
The choice is yours.

TIPS:

Make sure that in your functions EVERY variable is customizable.
u wot m8

User avatar
veethree
Inner party member
Posts: 814
Joined: Sat Dec 10, 2011 7:18 pm

Re: Libraries

Post by veethree » Sun Apr 01, 2012 4:15 pm

Neon wrote:I'm very new to Love2D, I've only been experimenting with it for a couple days. My questions are about libraries. How do I make one? Why should I make one? Where do I start? What else should I know? Just all the information you can give me about libraries and making them will be useful. I'm planning on making a GUI library but have no clue where to start. I am rather fluent with most of Lua and have been programming with it for a while, so I should be able to comprehend your replies. Thanks.
To my knowledge a library is just a .lua file which holds a bunch of functions that you can use in your projects to make your life simpler. So for example to make a GUI library you'd basically write a bunch of GUI related functions which you could call in your game's project to make the GUI. There are a few reasons as to why one would make a lib. I've made a few small libs for personal use, only reason for it is to make my life simpler, so i don't have to rewrite the whole thing if i need it in another project. About where to start, If you want to make a GUI lib, I think you should check out some other GUI libs out there to see what sort of functions they have so you get a basic idea of what functions a GUI lib needs.

Now i'm not the best person to be answering this since i have little experience with libraries, But i hope my answer helps at least a little. lol

User avatar
trubblegum
Party member
Posts: 192
Joined: Wed Feb 22, 2012 10:40 pm

Re: Libraries

Post by trubblegum » Sun Apr 01, 2012 5:06 pm

Please don't declare globals in my code.
Instead, return a variable which I can assign as I see fit.
Depending on what exactly your lib does, it may also be beneficial to return an instance.

mylib.lua :

Code: Select all

local mylib = {}
mylib.new = function(this, proto) return setmetatable(proto or {}, {__index = this, __call = this.new}) end
mylib.do = function() print('done') end

return mylib:new()
main.lua :

Code: Select all

ml = require('mylib')
ml.do()

-- or even
myobject = ml({})
myobject.do()

Neon
Prole
Posts: 16
Joined: Sun Apr 01, 2012 3:46 pm

Re: Libraries

Post by Neon » Sun Apr 01, 2012 6:07 pm

Thanks for all your contributions. I'll ask more questions as that come up. Trubblegum, I don't understand your post at all (I never understood metatables), could you explain it in more detail?

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

Re: Libraries

Post by Robin » Sun Apr 01, 2012 6:20 pm

In my opinion trubblegum is making things harder than they need to be. You should make your libraries just like you want them, and in a way you understand what you're doing (that is the most important part). Just don't expect anyone else to use your library. If you want that, it might be useful to learn a few things about making "proper" libraries.
Help us help you: attach a .love.

User avatar
rokit boy
Party member
Posts: 198
Joined: Wed Jan 18, 2012 7:40 pm

Re: Libraries

Post by rokit boy » Sun Apr 01, 2012 7:39 pm

So is my way helpful :D?
u wot m8

User avatar
trubblegum
Party member
Posts: 192
Joined: Wed Feb 22, 2012 10:40 pm

Re: Libraries

Post by trubblegum » Sun Apr 01, 2012 7:56 pm

Let me just clarify that I'm not stating any kind of law, or even accepted practice, although considering how a fellow developer may want to use your lib should always be among your primary considerations. OP asked for suggestions, so I put forward my preferences as something that might be worth considering.

Metatables can be a very useful tool, so I think it's worth learning how to use them ..
Also, I have nothing better to do with my time .. lucky (or unlucky, depending on how you look at it) you :P

A metatable is a table attached to a table, which defines functions to be used as the table's behaviours under certain conditions.
A common usage is for class definitions.

I'll use my previous code as an example with some modification for clarity :

Code: Select all

local mylib = {}
mylib.new = function(this, params)
  return setmetatable(proto or {}, {__index = this, __call = this.new})
end
mylib.do = function() print('done') end

return mylib:new()
mylib is a class, which means you don't use it directly, except to create objects.
mylib.new is the class constructor, which accepts a reference to its containing table, and a prototype or nil/false.
It then assigns a metatable.

Code: Select all

table = setmetatable(table, metatable)
setmetatable() accepts table table, table metatable, assigns metatable as table's metatable, and returns a reference to table.

The way a metatable works is like thusly :
When a table operation (index, call, assignment, mathematical operators, etc) is requested, but table is unable to come up with the goods, Lua looks over table's metatable for a matching event handler.
If it finds one, it uses it.
The metatable fields defined in the example are :

__index = this : When an indexing event is triggered (table[index], table.index, etc) if rawget(table, index) does not find a field matching index in table, Lua looks for getmetatable(table).__index. If the value is a function, that function will be called, passing the requested table and index. If it's a table, the process will be repeated on that table, and so on.
So in this example, we're telling our new instance to look in its parent class (mylib, or the argument this) for any methods it doesn't contain.

__call = this.new : When a table is called as a function (as in table()), Lua calls getmetatable(table).__call() with table as the first argument passed to the function referenced in the metatable's __call field.
In the example, if the instance is called as a function, mylib.new() will be called, passing a reference to mylib, followed by an empty table, which in a practical example would have contained prototype parameters.

You will find a complete list of metatable events here : http://lua-users.org/wiki/MetatableEvents
More on metatables and their usages here : http://www.lua.org/pil/13.html

main.lua in my previous post simply assigns the return value from require() (remember that require acts like a function with the contents of the file as its code) so that the value returned by mylib:new() (a freshly meta'd instance of class mylib) is assigned to the global ml.

The second method shown in that example calls mylib.new({}) with the first argument (actually a reference to the mylib table) inserted by the __call metamethod, because that's where it was sent by the metatable's directions. But no-one has to call new() or init() or whatever you decided to call it.
My take is that if you're writing a lib, you're trying to make lives easier, so why go only halfway?

Hope that was helpful to someone anyway :)

Neon
Prole
Posts: 16
Joined: Sun Apr 01, 2012 3:46 pm

Re: Libraries

Post by Neon » Sun Apr 01, 2012 8:41 pm

All right, so to create a GUI library. I'll need a create function for each type of GUI, correct? I think I'm lost, but I thought if I took a stab at it you guys would be able to help me better. I made a simple newLabel function to create a text label, then store it in a table called stuff which I can use to edit the values. It's very basic (only has x, y and text). Please show me where I went wrong and what I should do to make it better. I don't usually work with tables inside tables and stuff like that, so I'm sure there are errors there.

GUILib

Code: Select all

stuff = {}

function newLabel(x, y, text , name)
table.insert(stuff, name = {x, y, text})
love.graphics.print(stuff[name][text], stuff[name][x], stuff[name][y])
end
Main

Code: Select all

require 'GUILib'

love.update()
newLabel(300, 400, "Hello World", "MyLabel") --Make te label
love.timer.sleep(4000) --A little wait.
stuff[MyLabel][x] = 500 --Move the label
end

User avatar
trubblegum
Party member
Posts: 192
Joined: Wed Feb 22, 2012 10:40 pm

Re: Libraries

Post by trubblegum » Sun Apr 01, 2012 9:54 pm

The first thing I would suggest is to have a look at some existing libs and see how they do it. There are quite a few of them (including mine) and I'm sure they all have something to offer.

Re ways to improve your code ..
Some of this may be considered subjective, but the majority is at least accepted practice.

Don't declare globals in the lib unless you're trying to make it impossible for others to use.

I don't think table.insert is doing what you expect it to.
What you want is stuff[name] = {}, but that's not what you want anyway. Return a reference to the new label inside the table instead.

Put draw functions in love.draw()
Make your object an object by giving it new() (or load()), update(), and draw() functions. This is why inheritance is good.
Give your GUI object the same, and have it call the objects' methods at the appropriate time.

Since you have some experience with Lua, you know why stuff[name][text] doesn't work.

Calling love.update() before defining it probably won't do anything meaningful. Neither will the end that follows.

Don't get in the habit of using love.timer.sleep()
You're not allowed to stop the world, unless that's what your lib is meant to do.

I don't see much point in going on.

I'm no expert on Lua and LÖVE, but with your existing level of ability, use an existing lib, or use a less demanding project to learn with.
I could show you how to do it, but what would be the point? You would gain nothing from it, but a copy of an existing lib, because those who know how have already done it so you don't have to.
Try some of these : https://love2d.org/wiki/Category:Tutorials

Post Reply

Who is online

Users browsing this forum: No registered users and 11 guests