leaf (Love's Extensions And Facilities) is collection of libraries and classes for LÖVE. The structure of code and functions' names are entirely based on Pyxel.
leaf is open source and free to use.
-
Shorter functions' names
-
On Key Pressed Once function
-
Screen configurator
-
Object Platform and Multiple-State Machine Enemy classes
-
Physical and graphical tilemap composer
-
2D colision system
-
Sprite Animator class
-
Save-Load build-in system
-
NES-Like resources system
-
Simple debug function
-
New Table and strings functions
leaf is a lua module that can be loaded using require
.
require 'leaf'
leaf.skip('resources')
leaf.init({w = 480, h = 480, s = 3})
local x, y = 0, 0
function leaf.step(dt)
if leaf.btn('a') then x = x - 1
elseif leaf.btn('d') then x = x + 1 end
if leaf.btn('w') then y = y - 1
elseif leaf.btn('s') then y = y + 1 end
end
function leaf.draw()
leaf.rectb(x, y, 4)
end
Do not use love.load | update | draw, it would override the Leaf's functions. Instead, use leaf.load | step | draw.
-leaf.init(conf)
Sets the screen size (conf.w
x conf.h
), the drawing scale (conf.s
), if the screen is resizeable (conf.rz
), the min screen size (conf.mw
x conf.mh
) and if vsync is enabled (conf.vs
). Also the drawmode (conf.dm
) See Graphics for better understanding. Default values:
conf = {
w = 512, h = 512, s = 4,
mv = true, rz = true,
vs = true,
dm = "default"
}
-
leaf.load
Works likelove.load
. -
leaf.step
Works likelove.update
. -
leaf.late
Called afterleaf.step
. -
leaf.draw
Works likelove.draw
. -
leaf.fps
The current fps. -
leaf.s_wdth
The current game screen width (real size / scale). -
leaf.s_hght
The current game screen Height (real size / scale).
-
leaf.table_first(lst)
Returnsidx, itm
of the first item inlst
. -
leaf.table_last(lst)
Returnsidx, itm
of the last item inlst
. -
leaf.table_find(lst, itm)
Returns the index of theitm
if it is inlst
, otherwise returnsnil
. -
leaf.table_eq(lst, otr)
Returnstrue
iflst
has the same items in the same indexes ofotr
, otherwise returnsfalse
. -
leaf.table_copy(lst)
Returns an copy oflst
.
All these functions works with string objects
-
string.split(str, pat)
Returns a table of substrings splited bypat
fromstr
, returnsstr
if doesn't findpat
. -
string.startswith(str, sub)
Returnstrue
ifstr
starts withsub
, otherwise returnsfalse
. -
string.endswith(str, sub)
Returnstrue
ifstr
ends withsub
, otherwise returnsfalse
.
leaf.tobool(val)
Converts value to bool.true
if is"true"
,not 0
ornot nil
.
Simple print all function.
leaf.log(tag, [...])
printstag
followed by all subsequent values (...
). e.g.
leaf.log('debug', true, 4, 6 - 9)
>>> [debug][true, 4, -3]
leaf.drawmode = "default"
: draws game sprites and shapes normally.leaf.drawmode = "pixper"
: rounds the values before drawing, keeping all shapes on-grid.
-
leaf.popup(usr, msg)
Creates a pop-up window tousr
withmsg
as content. (Avaliable only on Windows and Linux). -
leaf.color([r, g, b, [a]])
Same oflove.graphics.setColor()
, but it uses 0 to 255 scale, anda
is optional. If empty, resset the color to default. -
leaf.rect(x, y, [w], [h])
Draws anw
xh
rectangle (line draw method) at {x
,y
}. Ifw
isnil
,w
andh
will be1
, if onlyh
isnil
,h
will bew
. -
leaf.rectb(x, y, [w], [h])
Draws anw
xh
rectangle (fill draw method) at {x
,y
}. Ifw
isnil
,w
andh
will be1
, if onlyh
isnil
,h
will bew
.
-
ESC key
Quits the application. -
leaf.btn(key)
Returnstrue
ifkey
is pressed, otherwise returnsfalse
. -
leaf.btnp(key)
Returnstrue
ifkey
was pressed at that frame, otherwise returnsfalse
. -
leaf.btnr(key)
Returnstrue
ifkey
was released at that frame, otherwise returnsfalse
.
-
leaf.txt_conf(font, size, speed)
Sets the default font asfont
, with sizesize
and the class will type 1 letter perspeed
(seconds). -
leaf.new_txt(tmsg, ypos, [effect], [trigger, tgrTime])
Adds a new text object, that will be drawed at heightypos
and alligned at center acording to the size (better with monospaced fonts). Iftrigger
is definided (atable
with the letter positions) the text will wait1/tgrTime
seconds before continue. If this text object already exists, nothing happens.effect = 'noises'
: will draw some red and blue shadows behind the text.effect = 'glitch'
: will render random red and blue glitches and change the showing text once in a whileeffect = 'wobbly'
: will draw the letters in a waveform, wobbling over the timeeffect = 'shaking'
: will shake the letters separately and randomly
-
leaf.type_txt(dt, [sound])
Updates all text objects, playing the tapesound
if given (See Gramophone). -
leaf.txt_exist(idxr)
Returnstrue
if an text object hasidxr
as content. -
leaf.txt_end(idxr)
Returnstrue
if the text object that hasidxr
as content has ended. -
leaf.del_txt(idxr)
Removes the text object that hasidxr
as content. -
leaf.pop_text()
Removes all text objects that has ended.
- Text Objects are automatically drawn.
-
leaf.vector([x[, y[, s]]])
Returns a new 2D vector at {x
,y
} with optional scale (s
). If empty, returns a {0
,0
} vector.-
vector:sum([x[, y]])
Sumsx
(or0
) andy
(or0
) to the vector. Returns itself. -
vector:sub([x[, y]])
Subtractsx
(or0
) andy
(or0
) from the vector. Returns itself. -
vector:mul([x[, y]])
Multipliesvector.x
byx
(or1
) andvector.y
byy
(or1
). Returns itself. -
vector:mul([x[, y]])
Dividesvector.x
byx
(or1
) andvector.y
byy
(or1
). Returns itself.
-
-
leaf.vect4D([lt[, rt[, up[, dn]]]])
Returns a 4dir vector with values left (lt
), right (rt
), up (up
) and down (dn
). If empty, returns all values as0
.
-
leaf.add_plat(type, pos, wdt, hgt, name)
Adds a new platform of the typetype
('solid'
or'jthru'
) of sizewdt
xhgt
atpos
(vector
), identified byname
. -
leaf.coll(pos, coll, [down])
Updatescoll
(vect4D
) with all solid walls nearpos
. Ignore the floor (coll.dn
) if the platform isjthru
anddown
istrue
. -
leaf.del_plat(name)
deletes thename
platform. -
leaf.draw_plat()
Draws all platforms.
-
leaf.add_itm(name, ipos, sprt, [wall])
Adds a collectable item atipos
, rendered withsprt
(vector
). Will be a solid tile ifwall
istrue
. -
leaf.catch(coll)
Destroys overlapped items bycall
(vector
) and returns item name if was caught.
-
leaf.tilemap(back, main, info, [obj])
Sets the tile map of the game.back
metatable with the layers at the background (not solid).
main
table with the tiles of the main layer (solid).
info
table with the definition of the tiles.
obj
optional arg. table with the definitions of enemies that will be spawned at every correponding tile. -
leaf.add_tile(name, spos, sprt, wall)
Adds an tile with the indexername
atspos
(vector
) rendered withsprt
(vector
). Ifwall
is true, the tile will be solid. -
leaf.del_tile(name)
Deletes thename
tile.
First you have to create a classtype for the tiles.
function char_to_tile(char, _x, _y)
local sx = char % 16
local sy = (char - sx) / 16
return {
p = leaf.vector(_y, _x, 8), -- the tile itself position
s = leaf.vector(sx, sy, 8), -- the sprite position at tilemap.png
c = char -- the byte that represents its sprite
}
end
The byte value is the sprite position converted into a single numeric value (0-255). You can do it using this formula: byte = y * 16 + x
.
Then you'll need to specify what each tile is:
local info = {
skipt = {[255] = true}, jthru = {[34] = true}, -- 255 is skiped because it's the empty tile | 34 is the platform tile (jump thru)
index = {spawn = 254} -- this value tells to the tilemapper to return the position of the last occurrence of 254
}
After this you can create a table containing all your tiles in your tilemap.
local map = {
char_to_tile(255, 0, 0), char_to_tile(055, 1, 0), char_to_tile(255, 2, 0),
char_to_tile(255, 0, 1), char_to_tile(034, 1, 1), char_to_tile(255, 2, 1),
char_to_tile(233, 0, 2), char_to_tile(013, 1, 2), char_to_tile(112, 2, 2),
}
Also, you can specify an item that can be caught.
local item = {
wall = false, -- the item isn't solid
tile = {45, 61}, -- both 45 and 61 are items
name = {[45] = 'star_', [61] = 'coin_'}, -- to you be able of accessing it later, name the items with a prefix
}
Finally, if you want, you can instantiate enemies to prow in a certain area (between every two chars).
local enemy = { -- the arg must be a table of every enemy, in this case just one
[66] = { -- the char that represents the bounds of the enemy habbitation
name = 'pm-ghost', -- name given to leaf.create()
clip = {
-- same source name to --
-- change only sprites --
-- and not the current --
-- frame --
idle = leaf.asrc('idle', 2, 0, 04),
angry = leaf.asrc('idle', 2, 5, 10),
}
}
}
```
Then just give everything to the tilemapper:
leaf.tilemap(map, _, info, item, enemy)
It's highly recomended that you use the Ethereal tilemap editor instead of tiling by hand. In this case, do something like this:
local main, back = leaf.decoder('map.txt')
leaf.tilemap(main, back, info, item, enemy)
leaf.create(otype, ...)
Returns a platform object of the otype
.
- Functions common to all platform types.
-
platform:step(dt, [cpos])
Updatesplatform
object (moviment, collision, animaiton). Ifplatform
is anpm-ghost
, the object will haunt thecpos
position (vector
). -
platform:draw()
Drawsplatform
object. If object has no animator, a rectangle will be drawn instead. -
platform:get_pos([scale])
Returns avector
with the current position ofplatform
. Thes
parameter will be used as scale, if given. -
platform:set_pos(npos)
Sets theplatform
position tonpos
(vector
). -
platform:get_stt()
Returns the current animation state ofplatform
(idle
ormoving
). -
platform:get_yac()
Returns currentY
axis acceleration. -
platform:can_jmp()
Returns count of remained jumps of object or if it can jump (boolean). -
platform:jumped()
Returnstrue
ifplatform
has jumped at that frame. -
platform:on_wall()
Returnstrue
if theplatform
is leaning against a horizontal wall. -
platform:landed()
Returnstrue
if theplatform
is landed. -
platform:onland()
Returnstrue
whenplatform
lands. -
platform:get_mrr()
Returns the mirror state ofplatform
.-1
if sprite is flipped,1
if it's not.
(ipos, ctrl, [def])
Returns a playable object, instantiated at ipos
, using ctrl
as key definition. def
is used do give an animator object and physics parameters. e.g.
local ctrl = {
lft = 'left' , -- move to left
rgt = 'right', -- move to right
dwn = 'down' , -- climb down
int = 'up', -- interact
ups = 'x' , -- jump
atk = 'c' , -- atack
}
local def = {
speed = 1.5, -- moviment speed
anim = leaf.anim(), -- animator object
clip = {
jump = leaf.asrc('def-jump', 0, 6), -- jumping animation clip
fall = leaf.asrc('def-fall', 0, 7), -- falling animation clip
idle = leaf.asrc('def-idle', 0, 0, 4), -- idle animation clip
walk = leaf.asrc('stp-walk', 0, 4, 0, 5), -- walking animation clip
size = 8, -- object size (value x value)
mass = 8, -- the object weight
jump_count = 2, -- Count of jumps
jump_strength = -200, -- Jump strength
coytote_time = 4, -- how may frames after falling off from a platform are still able to jump
}
}
local char = leaf.create('platform', leaf.vector(0, 0), ctrl, def)
If ctrl
be a table of booleans, you can control indirectly the object, e.g.
local ctrl = {
lft = false,
rgt = false,
ups = false,
dwn = false,
}
local char = leaf.create('platform', leaf.vector(0, 0), ctrl, def)
function leaf.step(dt)
-- updating this table updates the character's one --
-- when true, char moves, when false, char stops --
ctrl.lft = leaf.btn('left')
ctrl.rgt = leaf.btn('right')
ctrl.ups = leaf.btn('up')
char:step(dt)
end
(min, max, pos, [clip])
Platform Packman-like enemy. Runs the area from min
to max
, but is instantiated at pos
. If defined, the clip
will be used as an animator object, containing the idle and angry animation clips. e.g.
clip = {
-- Same name to change only sprites --
idle = leaf.asrc('idle', 2, 0, 4),
angry = leaf.asrc('idle', 2, 5, 9),
}
ghost = leaf.create('pm-ghost', 0, 32, leaf.vector(0, 0), clip)
Leaf uses two png files ("tilemap.png" to the tilemap class and "sprites.png" to animator objects) in resources/
as graphic sources and all files in tracks/
as audio souces. The graphic files will be automaticly loaded, except if you use leaf.skip('resources')
.
Animation class, responsible for controlling and animating sprites.
-
leaf.anim([frame])
Returns an animator object. Ifframe
(vector
) is specified, the animator will be initialized in this frame. -
leaf.asrc(name, ...)
Returns an animation source, taged withname
, that can hold a prefix that specify the animation type.-
('def-name', rw, fx, lx, [opt])
Default type, the same without a prefix. Returns a sprite sheet animation source, in therw
row, from thefx
tolx
columns. Ifopt
({spr, cnt}
) is specified, optional frames (spr
) will be appended at the end of the animationcnt
times. -
('stp-name', rw, fx, mx, lx)
Stepped type. Returns a sprite sheet animation source, interleaved animation of fx and lx separated by mx ({fx, mx, lx, mx}
).
-
-
anim:play(dt, anim, speed, loop)
Causes objectanim
to play animationanim
at speedspeed
(frames per second). Ifloop
is specified, the animation will be looping. -
anim:loop()
Causes objectanim
to loop the current animation. -
anim:draw(pos, side)
Draws the current animation ofanim
atpos
(vector
). Ifside
is smaller than 0, the sprite will be flipped, if it's greater, will not.
-
leaf.playlist(main, back, ...)
Sets the playlist of audio souce.main
(tracks/<main>
) is the main music layer,back
is the background environment....
is all other play-once sounds of the game (sfx), like soundsteps, hits, etc. * Max 8 tracks (0 to 7). -
leaf.gramo.theme()
Starts playing the main and background musics. -
leaf.gramo.set(thm, stt)
Sets playing status ofthm
('main'
or'back'
) tostt
(boolean). -
leaf.gramo.play(tape, track, loop)
Playstape
(indexed inleaf.playlist
) at sound layertrack
. Ifloop
is true,tape
will play in looping. The volume will be set totrack / 7
. -
leaf.gramo.pause(track)
Pausestrack
if it exists. -
leaf.gramo.resume(track)
Resumestrack
if it exists. -
leaf.gramo.fade_in(track, speed)
Increases the volume oftrack
from 0 to 1 inspeed
(percent per second). -
leaf.gramo.fadeout(track, speed)
Decreases the volume oftrack
from 1 to 0 inspeed
(percent per second).
-
leaf.save_data(file, data, [method, msg])
Saves a file namedfile
containing the data ofdata
(string, number or table) in the standard LÖVE directory, using an optional method.-
method = nil
Standart method. Save all data inside a .lua file. -
method = 'safe'
Magic method. Saves the file asfile
and store the data in a slightly difficult way to change it. It usually causes errors of nullity if done (not sure why). It also addsmsg
as a message at the top of the file.
-
-
leaf.load_data(file, method)
Returns the content offile
. If an method was used to save the file, it must be specified withmethod
.