Tag Archives: LÖVE

Some tries with LÖVE game engine in Lua

* Ce billet est également disponible en français.

Drawn with Pencil2D and MyPaint, animated using meshes in LÖVE (Lua language), I also made some tests in C with libSDL, but it is probably faster to prototype in Lua with LÖVE, and then add FFI libs for compute intensive part (in these cases light computations, GL is used for rendering), or port it to c+SDL at second time, when algorithms are validated. All used software are 100% FOSS used on a GNU/Linux system.

This one use simply a mesh on a picture, and deform them using circular motions, as I done in TIC-80 in July 2021.

The picture used for the mesh:

A modified version, with fixed hard skull, I keep both version, this one is interesting for anthropomorphic head, the other for more realistic invertebrate.

This test gather different tests with shaders. I apply a threeshold, above is one colour under, is another, this allow to have interesting clean 2 colours effects Source code of these shaders for LÖVE is available on Framagit (demo01.love file on this site).

This other one also use a mesh on a picture with 2 steps, swapping from one to each other moving the drawing shape, but instead, of deforming it by sin(), it curve the mesh, by adding curvature at each step, and a little sinus wave to simulate something that goes through the body.

the liquid the the monster reject, is a texture, that is copied to a Canvas, to wrap it and loop it, This part was inspired by the game “Conan Chop Chop”. But I fine tuned a bit: A shader is then applied on the canvas when drawing on screen surface, it scale the pixels along the path of the liquid, and add a light waving motion. the splash at the end is a cycle between 3 pictures.

The quickly drawn 2 steps monster, it could be optimized on disk by creating the duplication of the body after loading, LÖVE is not convenient as libSDL for textures mesh:
bidule spritesheet

The picture used as texture for for the shader:
flux de vomit intense

The splash at the end, each part are displayed sequentially in loop, this was animated with Pencil2D (MyPaint branch):
Eclaboussure de vomit

The animation is first made with Pencil2D, then saved with one picture (PNG with transparency) by frame, and then ImageMagick package, “montage” is used to build the spritesheet the following wy:

montage sprite0001.png sprite0006.png sprite0010.png -tile 3x1 -geometry 64x128 spritesheet.png

Using about the same methods, I then improved my code to manage a more generic way, hand drawn animation made with Pencil2d as mesh. Here is an animated sketch of flower opening, as proof of concept.

Blooming flower

Update of march 19:

It uses 8 frames, with various framerates, managed in a table, is here the frame number table:

table = {1,1,2,2,2,3,3,4,4,4,5,5,6,6,7,8,8,8,8,8}

I can then cycle easily in the table using math.floor( (time()*fps) % #table), or just parse it one time for exemple here for a flower that just open one time.

I then used it as decoration element. Now it work, I can refine animation, still make it more generic to have only to add minimum information, and be able to add quickly new animations.

After the good result of the first test of the animation with program, I cleaned a little the flower and added some colours. I then noticed than the last frame, where the flower move is stabilized missed. The picture before the last was duplicated as 2 last frames in my spritesheet. Anyway, I need to remove some useless space around the flower, separate stem and flower itself to reduce memory usage; It already take, reduced in 128×128 pixels 180~200 Ko (150 Ko compressed better with zopflipng). This is too fat, if you multiply this by the number of objects/characters you can quickly reach tens of MB (png compressed) on disk, and far more on Graphics RAM, saturating ram, cache and bandwidth, and so slowing down rendering. I believe that separate flower and keeping in a something like 64×64 pixels animation could be fine the stem could be a flat texture, blended by procedural means.

Fleur qui s'ouvre améliorée

”’Update may 2022 ”’
* You can test all of this, from the sources available at https://framagit.org/popolon/reforest.
* Ready last version LÖVE files and archives are available at the address https://framagit.org/popolon/reforest/-/releases (version 0.2 from this site).

Reforest 0.2 Screenshot

Lua, TIC-80, LÖVE,etc: Introduction to particles systems and games

Version en français ici
default code in TIC-80

A good language for easily developing games, interactive content and procedural art is Lua scripting language. This is a simple functional language with some limited oriented object language features. It is, due to its simplicity and bytecode compiling at start by default, one of the lightest and fastest script language. Some integrations like LÖVE media/games engine and API (very powerful), and TIC-80, that is more limited fantasy-computer inspired first by PICO-8 (also use Lua). They allow quick prototyping, for a final product in the same language or a later port in another language. Lua is also used as plug-in systems language, in lot of games, and tools, including desktop applications (like Blender), web application (like MediaWiki behind Wikimedia) or embedded world. In this domain, popular and open-source drone board control BetaFlight or Open-TX open source radio-command for commands like Taranis one. There is a complete online documentation of Lua on the official website. It is possible to embbed C libs/function in Lua programs with libffi. It as been created first for Python, CFFI, and there is FFI support for PHP too now. It also possible to embed Lua scripts in C program. I also just discovered when I wrote this article (thanks to the author of TIC-80, that there is also PicoC, a simple C language interpreter that so allow to control more finely/low level data structures. The binary size is about the same than Lua interpreter.

An interactive demo of how trigonometric functions workSo, after few years of looking time to time this language and tools, I started to play a bit more in end of 2020, and in few month I can said I made lot of progress in real-time programming. Doing and even finishing light games. I Needed to study again basic trigonometry (follow link for a simple interactive explanation), basic vector algebra and few other mathematics fun things, that I personally consider like puzzles games.

Banner of Falacy Gorx, pseudo 3d game, using lot of tables
I also wrote a short making-off article on itch.io in march, 2021, during a game jam competition (instead of coding ^^). All of this motive me to write more articles tutorials about real-time/vector and procedural generation programming. I will try to write a series explaining methods I used. I will try to keep it as simple as possible to everyone, but some basic knowledge in general programming and mathematics could help a lot in this field as in life in general.

So I start with a short introduction about what I use the most in my development, arrays of elements and some randomness:
* Tables and their common basic management related to animation logic
* Creating a table
* Procedural generation of the content of a table
* A simple example for cleaning a table
* Variation and cleaning of table depending on tests
* Compacting code a bit
* Procedural generation of the content of a table
* Simple graphic particle system example

Tables and their common basic management related to animation logic

Some general table usage in interactive applications

Most things are managed, for scalability, in tables, main actors (like players characters), objects, particles, active agents, etc. Object themselves, also often contains tables of sub-elements, thing as example about the parts of a caterpillar body.

So, most structures have generally 4 vital logic functions that can be managed different ways:
* Cleaning of the table, used when tables elements are no more used, but it is also wise to use it to initialise new general state, like changing from main menu to game for example.
* Initialisation of table (generally including cleaning if needed) and adding 1 to n elements
* Update of the table, states of elements, including their mechanical & physical relationship, positions, their state of drawable, interacting with other objects, and finally removing or creating a new element in the table if needed. All these parameters depend on lot of various critters.
* Output of the content of the tables (display, sound, etc).

You can test these examples in Lua command line interpreter by typing lua in a shell, and then copy-paste them, or by putting them in a file.lua, and calling it by:

lua file.lua

The last examples use TIC-80, that can be used in web browser and natively on several systems, including, Linux, Mac, Windows, Android, Rpi, etc. There is a Pro version, but I never used its functionalities, it’s good to help the developer that is very nice and worked a lot of it. The examples can also easily be ported to other environments.

Creating a table

We will use here an objs[] table (a table with name objs, short of objects). In Lua, by default, table start at 1 when you fill it by objs={elt1,elt2}, but it is still possible to have a 0 indexed element by using objs[0]=elt0. The table can be (re-)initialized empty with objs={}. If it wasn’t empty, Lua garbage collector will clean it. As I coded a lot in low level languages, such as C/C++ and assembly, I’m not a big fan of garbage collectors, but that’s really convenient for quick prototyping.

Content of the table can be simply printed with a classical for loop. For the table called obs, #objs allow to know the number elements currently availablee in the table.

objs={"ball","cube","player"}
for i=1,#objs do
 print(objs[i])
end

Procedural generation of the content of a table

particules systems for clouds, mountains, characters, table of elemets for dragonIn procedural generation, the best friend of Chaos also called Nature, is random function, that generate randomly numbers. In Lua core, math.random is dedicated to this. it accept a range as parameters, limited to integer and with crescent values only. We can as example, decide to generate a number between 1 to 6 included, as the total number of elements we want. If you try several times this function, it will display random value included between 1 and 6 each time. Like if you launched a classical 6 faces cubic dice.

print(math.random(1,6))

In an interactive or animated program, we generally want to create random object, and then varying a more managed way during a period of time. So we fill a table with random values, that can be reused later. We need to first (re-)initialize objs to an empty array, so it can be filled by the for loop.

objs={}
for i=1,math.random(1,6) do
 objs[i]={lt=math.random(1,50)}
end

We so generated a 1 to 6 random number of random 1 to 50 numbered assigned to a parameter we called lt parameter instead of the table directly. This kind of element can be accessed 2 ways in Lua, objs[i].lt or objs[i]["lt"], the second one can be useful in some situations, but we will see this later in another tutorial.
so now the table is filled, we can print values several times, they will be kept the same:

for i=1,#objs do
 print("objs["..i.."]="..objs[i].lt)
end

We use the Lua string concatenation here (symbol ..) to have more information about which element we see printed.

A simple example for cleaning a table

It is important for cleaning a table or removing elements from it to do the loop from last to first element index, as when an element is deleted, all following items in the table will have decremented index. We could then stride over some elements and remove elements we don’t want to.

for i=#objs,1,-1 do
 table.remove(objs,i)
end

In the table.remove() standard Lua function, arguments are the name of the table and the index of the element to remove.

Variation and cleaning of table depending on tests

It can be a good habit to use a short local pointer variable to the element parsed to have a shorter code inside the loop, as it will il most case be accessed a lot. We remove here an element when lt (short for lifetime) is gone to 0, else we decrement it.

for i=#objs,1,-1 do
 local o=objs[i]
 if o.lt<=0 then
  table.remove(objs,i)
 else
  o.lt=o.lt-1
 end
end

The o variable can’t be passed to table.remove(), as it is used as a pointer to an element of the table, not as the name of the table, and the second argument is an index of the table, not either a pointer to the element as o is.

We have now the general base of a particles system.

All particle systems work with generation, often using at least a bit of randomness, and lifetime of each particles as a base, other criteria can changes depending on kind of particles.

Compacting code a bit

I generally add the local variable on the for...do line to have a more readable/compact code and changes behind if...then or else keywords to have a more compact and still readable code:

for i=#objs,1,-1 do local o=objs[i]
 if o.lt<=0 then table.remove(objs,i)
 else o.lt=o.lt-1 end
end

And Lua allow to assign a function pointer to a variable, so I generally use the following trick to have a more compact and clear code :

m=math rnd=m.random

So m is assigned to math and then rnd to m(ath).random.

Warning: on constraint is to not use m variable in the same variable scope than m.* assignation. It’s so better to made this assignation at the beginning, so m can be used freely after.

Simple graphic particle system example

In this example we will simply add random x (horizontal axis) and y (vertical axis) position around a starting central point 120,70 we choose a variation of -15 to +15 pixels in each direction:

objs[i]={lt=rnd(10,30),x=120+rnd(-15,15),y=70+rnd(-15,15)}

Basic particle systemand made them randomly move of a length from 0 to 1 pixel and in direction left/right and up/down. So, we have:
For x-axis
* -1 = left
* 0 don’t move
* +1 = right
For y-axis
* -1 = up
* 0 don’t move
* +1 down

o.x = o.x+rnd(-1,1) o.y = o.y+rnd(-1,1)

In Lua functions are defined by function function_name(arg1,arg2,...) and finish by end.
In the case of TIC-80 for example, that has the advantage to have all embedded in one executable, the function TIC() is a function called periodically, at each new frame, allowing to made time related content (so animation) easily. The function cls(color) is used to clean the screen with color at index “color” as TIC-80 use a 16 colors palettes.

The place of the particles are drawn by circ() (circle) function.

The definition of the function is:

circ(X center, Y center, radius, colour)

We place the center of the circle at the coordinates of the object, it has here a radius of 1 and use the colour index 0, that is black by default with TIC-80.

circ((o.x, o.y, 1, 0)

The current lifetime that the particle stille have is printed just at the right of the particle here for the demonstration. In TIC-80 print(), is used to place screen on graphic screen, and trace() on console.

The part of the print arguments we use are defined the following way:

print(text, X start, Y start, color, fixed font, scale, small font)

So we place as text, the current lifetime of the particle, at the center position of the object (o.x, o.y) with an horizontal variation of +2 pixel (so right) and horizontal of -2 pixel (so top). We choose a fixed size (true), scale of 1, and use small font (true):

print(o.lt, o.x+2, o.y-2, 2, true, 1, true)

In lua we can define several variables in one line, by crossing names of variables and assignations. For example, here, x=5 y=4 can be wrote x,y=5,4.

m=math rnd=m.random
t=0
objs={}
for i=1,rnd(5,8) do
 objs[i]={lt=rnd(10,30),x=120+rnd(-15,15),y=70+rnd(-15,15)}
end
function TIC()
 cls(12)
 for i=#objs,1,-1 do local o=objs[i]
  if o.lt<=0 then table.remove(objs,i)
  else o.lt,o.x,o.y=o.lt-1,o.x+rnd(-1,1),o.y+rnd(-1,1)
   circ(o.x,o.y,1,0)
   print(o.lt,o.x+2,o.y-2,2,true,1,true)
  end
 end
 t=t+1
end

In the Exemple to download we put the generation in a function generate() and call it when table content is null (#objs==0) as a simple loop generation.

function generate()
 for i=1,rnd(5,8) do
  objs[i]={lt=rnd(10,30),x=120+rnd(-15,15),y=70+rnd(-15,15)}
 end
end

function TIC()
 ...
 if #objs==0 then generate()end
 t=t+1
end

If you want to see the particles without their numbers, you can simply comment the print line. To comment code in Lua, simply add two dash at the beginning of the comment.

   -- print(o.lt,o.x+2,o.y-2,2,true,1,true)