Category Archives: programmation

Art du Pixel 64×64×16 couleurs (Sweetie16) PixelArt avec Pixelorama « β-karoten – Nous savons qui sera mangé »

→ English version here

β-karoten - Nous savons qui sera mangé

J’ai participé à la demoparty LoveByte Battleground qui s’est déroulé ce week-end, en postant la semaine dernière un dessin en pixel art. Malheureusement mais amusent, il y a eu quelques petites erreurs :
* J’ai fait une image de 64×64 pixels au lieu de 128×128 pixels. Une palette de 16 couleurs était imposée, Sweetie16 (la palette par défaut sur le console fantaisie TIC-80 (Code source, FOSS).
* Ma seconde erreur est d’avoir téléchargé une première version de mon image, ainsi que la mise à jour quelques heures après avec la version finale via le navigateur web NetSurf (code source, FOSS), sur Debian, sur l’émulateur RISC-V (Specifications, FOSH, il existes différentes implémentations libres ou non) de Qemu (FOSS, Code source, instance Git). Peut être parce que mon installation de NetSurf ne supporte pas le JavaScript^^. J’ai également participé à un livecoding (256 octets de code maximum en 25 minutes). Le résultat. La vidéo commentée de l’enregistrement de programmation en live.

Ce dessin est est fait avec Pixelorama (FOSS (Code source), lui même fait sur le moteur de jeu Godot (FOSS? code sourcce). J’utilise le système d’exploitation libre Arch Linux. J’ai également fait un paquet ArchLinux AUR pixelorama-git d’après le paquet pixelorama (Je voulais utiliser la version v0.9rc, seul la 0.8 était disponible). Il y a des paquets pixelorama (dernière stable, compilant depuis les sources), et pixelorama-bin (depuis les binaires des développeurs). Pixelorama est un éditeur d’image et animation en Pixel art. Je crois que je l’ai découvert grâce au blog Librearts.org.

Le nom est « β-karoten – « Nous savons qui sera mangé »

Capture d'écran de Pixelorama
Capture d’écran de Pixelorama

Telegram, autocollants animés Lottie, Python et Glaxnimate

Sommaire

* Introduction
* Un bon flux de travail
* Publication sur le web (SVG)
* Bot Telegram

Introduction


Je suis un grand fan de l’interface de l’application de chat Telegram. Si le serveur est fermé, l’application bureau et Android est ouverte, l’interface est bien pensée, intuitive, relativement légère et plein de fonctionnalités intéressantes par rapport aux autres applications de ce type. Il serait d’ailleurs sans doute intéressant de la patcher pour une compatibilité Jabber/XMPP. Il a été le premier à ma connaissance, à utiliser Lottie, dès juillet 2019 (et l’API pour bot qui va avec) un format d’animation vectoriel dont je rêvait depuis des décennies, devenu un standard de fait et ouvert. Les animations de cette page ont été crées avec Glaxnimate, un outil pour réaliser des animations au format Lottie, que l’on peut également exporter au format SVG animation. Les auteurs de Lottie fournissent des JavaScript pour le web, la bibliothèque libre, rlottie de Samsung (en C++, avec version WASM) permet de les jouer et comporte des adaptations pour différents langage de programmation. Qt intègre sa lecture par défaut et il existe différents outils pour en créer.


Le logiciel libre multiplate-forme d’animation Glaxnimate permet d’en réaliser avec une interface graphique d’un type assez classique pour les logiciels d’animation. Son auteur à également fait une bibliothèque python, python-lottie (AUR : python-lottie-git, pip : Lottie), permettant d’en générer algorithmiquement et les 2 permettent de convertir différents formats (export SVG animé, Lottie JSON, page HTML toute prête, Telegram, mpeg4, PNG, wepb, gif, et je dois en oublier), et en entrée de vectoriser des gif animés, etc… Le logiciel d’animation vectoriel 2D Synfig à également un exportateur, ainsi que Blender3D, fait également par l’auteur de Glaxnimate. Les choix ne manquent donc pas pour en créer.


Glaxnimate permet de faire facilement des animations au format Lottie, dont le format .TGS, une version aux spécifications volontairement plus limitées et compressée en gzip de Telegram. Le format de ce dernier est plus compact mais comportes quelques contraintes, cela n’a pas empêché d’avoir quelques merveilles depuis plus de 2 ans :
* format 512×512 pixels
* 3 secondes
* 64 Kio par autocollant animé
* Le tout peut être mis dans un paquet d’animations (sticker pack) regroupant différentes expressions.

Pourquoi 512×512 pixels alors que c’est un format vectoriel ? L’application cliente Telegram rendra dans cette dimension l’animation et la compressera en local, pendant la première boucle, en animation WebP de 512×512 pixels pour la conservation en cache. Cette dimension est déjà grande pour les certains écrans mobiles. Cela permet d’économiser la bande passante (animation vectorielle compacte transférée), d’avoir la haute qualité du vectoriel (généralement calculé par GPU, des accélérateurs SVG étaient déjà présent sur les téléphones Symbian des années 2000), et d’avoir des boucles d’animation qui ne prennent pas trop de CPU/GPU après la première boucle, ni trop de mémoire (compression WebP). WeChat/微信 a choisit des GIF animés il y a une bonne décennie, les GIF sont probablement convertit en MPEG aujourd’hui ? La messagerie instantanée Discord, populaire en Extrême-Occident, utilise aussi le format Lottie depuis juillet 2021.


Pour référence, l’animation du haut fait :
* 1109 octets (1,1 Ko) en TGS (format Telegram compressé binaire)
* 4682 octets (4.5 Ko) en json uglifié (plus d’indentations ni re retours chariots)
* 508054 octets (500 Ko) en WebP
* 9710 octets (9.6 Ko) en SVG animé (il y avait un path inutile en trop, je sais pas pourquoi).
* 1804 octets (1.7 Ko) en SVGZ animé (SVG compressé via gzip), il peut être plus intéressant de laisser le serveur compresser via brotli (Nginx, Apache) ou de pré-compresser (.br) Il est bien supporté par les navigateurs
* 6114 octets (6.1 Ko) en SVG, sortie optimisée Inkscape, on peut encore gagner, aujourd’hui si l’option de précision du nombre de chiffres après la virgule est inférieure à 3, elle reste à 3. Dans les parties animation non gérées on se retrouve à six 0 (1.000000 ou 0.000000). On peut encore l’optimiser à la main en attendant de l’intégrer (voir les sed plus bas), soit :
* 5827 octets (5.8 Ko) en SVG, retravaillé un peu à la main.
* 5559 octets (5.5 Ko) en supprimant des groupes intermédiaires inutiles et en remplaçant 1.0 par 1


Un des principaux problèmes à la sortie optimisée de SVG depuis Glaxnimate est que Lottie est basés sur une forte utilisation des groupes, tandis-que SVG permet d’effectuer de nombreuses opérations équivalentes dur les objets eux-mêmes. Ainsi les matrices de transformation sont situées dans des groupes contenant les objets. Voir l’affichage XML d’Inkscape ci-contre. Cela demande donc aujourd’hui du travail manuel sur les fichiers. Il doit être possible d’automatiser ça.

Il semble que SVGO ai d’autres méthodes encore plus efficaces, mais basé sur du node.js, mais il casse complétement les animations. Je n’ai pas trop confiance, en raison de beaucoup de mauvaises habitudes autour de Node. Et le plugin Inkscape, inkscape-svgo ne déroge pas à ses nouvelles habitudes, si l’on essaie de le compiler avec le Makefile inclus, pas de test d’installation existante, récupération forcée de node 11 (x86_64, perd le multi-architecture), et recompilation de toutes les dépendances. On se retrouve une fois de plus avec une extension énorme de dizaines de méga-octets (75 Mo, contre 145 Mo pour Inkscape et 5 Mo pour la bibliothèque SVGO elle même), alors que ça devrait faire que quelques Ko grand maximum.

Un bon flux de travail

* Créer l’objet sous Inkscape
* L’animer avec Glaxnimate
* Exporter en SVG
* Ouvrir de nouveau avec Inkscape pour nettoyer (sortir des groupes ce qui n’en a pas besoin,
* Faire une sortie optimisée
* Retravailler à la main.

Pour la dernière partie, cela oriente vers deux solutions pour l’automatisation :
* Patcher la sortie d’Inkscape optimisée
* Faire un optimiseur couche 2

On peut déjà pas mal gagner avec :

sed s/1.00000/1/g <input.svg | sed s/0.00000/0/g | sed 's/0000;/;/g' >output.svg

Un ou 2 chiffre de précision (à la place de 3 ou 4 aujourd’hui de Scour), devraient également suffire.

SVGcleaner est meilleur que Scour dans différents cas, mais ne supporte pas et n’a pas l’intention de supporter les animations (complexe à gérer, peut facilement tourner à la catastrophe).

Publication sur le web (SVG)

Comme le SVG animé est infiniment plus simple à intégré pour le web je préfère cette option. Le mieux est de ne pas compresser en SVGZ, mais seulement d’optimiser le fichier SVG puis de le compresser en Brotli (.br) et éventuellement en gzip pour des très vieux navigateurs.

L’intégration dans une page est très simple, elle se fait comme pour toute image :

<img src="/chemin/du/fichier_animation.svg" align="right" width="200" height="250">

C’est ce que j’ai fait sur cette page, le navigateur la prend automatiquement en charge.

Pour la compression, j’utilise les max voici un moyen simple d’avoir tous les fichiers d’un dossier compressé à côté de la version non compressée :

ls --ignore=*.gz --ignore=*.br | while read file
do
 brotli -q 11 -c <"${file}" >"${file}".br
 gzip -9 -c <"${file}" >"${file}".gz
done

* 5559 murphy_anim0.animoptiv5.svg
* 1303 murphy_anim0.animoptiv5.svg.br
* 1543 murphy_anim0.animoptiv5.svg.gz
* 4682 murphy.json
* 976 murphy.json.br
* 1149 murphy.json.gz

Pour forcer le chargement d’un des 2, si le navigateur supporte (si il supporte les 2, Brotli (.br) sera utilisé, sous Nginx (après avoir compilé le patch Brotli, les règles dans le fichier de configuration sont simples :

brotli_static on;
gzip_static on;

Sous Apache, Brotli est présent par défaut dans les versions 2.4, mais c’est un peu plus compliqué.

Pour tester, le mieux est d’utiliser la commande curl:

curl -I -H 'Accept-Encoding: gzip, deflate, br' https://host.net/fichier.svg

Si le brotli est bien activé, dans la réponse, vous verrez :

content-encoding: br

Bot Telegram

La bibliothèque python-lottie tombe bien, je voulais me mettre à Python, notamment pour micropython dans l’embarqué et pour du travail d’admin sys & réseau, où il est de plus en plus utilisé, avec l’outil de déploiement de parc Ansible, et d’autres outils système de base. Environ une année d’expérience de génération procédurale en Lua me donnait envie d’en faire d’en d’autres langages (je réserve une surprise pour bientôt). Il existe plusieurs bibliothèques de bot pour Telegram en python, dont Python Telegram Bot, qui colle assez bien à l’API officielle de Telegram et Telethon (Documentation) qui permet de communiquer directement en MTproto, le protocole de Telegram, plutôt que de passer par la couche HTTP, cela réduit d’une couche et permet un contrôle plus poussé des échanges. Voir le comparatif Bot API (HTTP vs MT Proto).


On ne trouve pas encore beaucoup d’exemples avec Python Telegram bot avec lequel j’ai commencé, mais en fouillant un peu dans la documentation, on trouve ce qu’on veut. En mixant la bibliothèque et python-lottie pour la génération procédurale, Glaxnimate pour la génération affinée à la main et le bot on a de quoi s’amuser. J’ai donc fait un premier bot en python-telegram-bot, suites aux suggestions de Glax, l’auteur de Glaxnimate qui m’a fait connaître le module python, Telethon, qu’il utilise pour son bot similaire, Glaxcomm, générant des Lottie/TGS à la volée. Je vais refaire mon bot et l’emmener vers ce que je voulais faire. Mon but étant aussi de pouvoir l’utiliser avec d’autres protocoles que Telegram.

Glax à fait un bon ensemble d’exemples de génération procédurale de base pour comprendre l’utilisation, bonne documentation sur le format Lottie, exemples de scripts de stickers

J’ai fait un bot simple en partant des exemples de la bibliothèque python-telegram-bot, mais il manquait des explications complètes (et je n’ai pas trouvé sur le net) sur la façon d’utiliser le file_id, méthode recommandée par Telegram, plutôt que d’envoyer plusieurs fois le même fichier. En fait ce file_id est récupéré au premier envoie. Donc, l’idéal est de stocker dans une base ou fichier sur disque l’id des fichiers qui ont déjà été envoyés (et reçu) au premier envoie réussi). Cet exemple crée un fichier contenant l’id à côté de l’image, c’est sans doute un peu plus bourrin que de conserver tous les ID dans une base (sql ou TOML) :

if os.path.exists(idfile):
  fid = open(idfile)
  stickid = fid.read()
  fid.close()
  msg = update.message.reply_sticker(stickid)
else
  msg = update.message.reply_sticker(open(stickfile, 'rb'))
  fid = open(idfile, 'w')
  fid.write(msg['sticker']['file_id'])
  fid.close()

Lua, TIC-80, LÖVE, etc : Introduction aux systèmes de particles et jeux

English version here
Code par défaut de TIC-80 au lancement

Un langage intéressant pour déveloper des jeux, contenus interactifs et de l’art procédural est le langage de script Lua. C’est un langage fonctionnel simple avec quelques fonctionnalités limitées de langage orienté objet. C’est, en raison de sa simplicité et de la compilation en bytecode au démarrage par défaut, un des plus légers et rapides langages de scripts. Différentes intégrations comme le moteur de jeu/médias et (très puissante) API LÖVE, ainsi que TIC-80, qui est un ordinateur imaginaire virtuel inspiré par PICO-8 (qui utilise également Lua). Ils permettent des prototypages rapides, pour un produit fini dans le même langage ou bien porté plus tard dans l’avancement du projet dans un autre langage. Lua est également utilisé comme langage de systèmes de plug-in (greffons), dans de nombreux jeux, outils, dont des applications de bureau (comme Blender), des applications web (comme MediaWiki derrière Wikimedia), ou dans le mondede l’embarqué. Dans ce dernier domaine, les cartes de contrôle de drones populaires et open-source (logiciels libres à source ouvertes) BetaFlight ou le logiciel de commande-radio Open-TX notamment pour les commandes Taranis. Il y a une documentation en ligne complète de Lua (en anglais) sur le site web officiel. Il est possible d’inclure des fonctions ou bibliothèques en C dans les programmes en Lua programs avec libffi. Elle a été (je crois) crée à l’origine pour Python, avec CFFI, et il a également un support FFI for PHP à présent. Il est également possible d’intégrer des scripts Lua dans des programmes en C. J’ai également découvert en écrivant cet article (merci à l’auteur de TIC-80, qu’il existe également PicoC, un simple interpréteur du langage C, permettant donc un contrôle plus bas niveau/din des structures de données. La taille du binaire est similaire à celle de l’interpréteur de Lua.

Une demo interactive du fonctionnement et utilisation s fonctions trigonométriquesDonc, après plusieurs années à regarder de temps en temps ce langage et ces outils, J’ai commencé à jouer un peu plus avec, vers la fin de 2020, et en quelques mois, je peux dire que j’ai bien progressé dans la programmation temps-réel. Que j’ai réussi à faire et même finir des jeux légers. J’ai donc du étudier de nouveau la trigonométrie de base (suivez ce lien pour explication interactive simple), de l’algèbre vectoriel de base and et quelques autres éléments amusants des mathémtiques, que je considère personnellement comme des jeux de puzzles.

Banner of Falacy Gorx, pseudo 3d game, using lot of tables
J’ai également écrit (en anglais) une court article de making-off sur Itch.io en mars, 2021, pendant une compétition de bœuf de jeu (game jam, dans le même sens que les bœufs musicaux), au lieu de coder (malgré le temps limité à 2 semaines ^^). Tout cela m’a motivé à écrire d’avantage d’articles didactiques à propos de la programmation temps-réel/vectorielle et génération procédurale. Je vais tenter d’écrire une série une série d’articles expliquant les méthodes que j’ai utilisé. Je vais tenter de le faire avec autant de simplicité pour tout le monde, mais quelques connaissances de base en programmation générale et en mathématiques pourront beaucoup aider dans ce champs du développement, comme dans la vie en général.

Je commence donc ici une courte introduction avec ce que j’ai utilisé le plus dans ces développements. Des tables d’éléments et du hazard:,z
* Les tables et leur gestion de base commune, relative à une logique d’animation
* Créer une table
* Génération procédurale du contenu d’une table
* Exemple simple pour nettoyer une table
* Variation et nettoyage d’une table en fonction de tests
* Compacter un peu le code
* Génération procédurale du contenu de la table
* Exemple simple de système de particule graphique

Les tables et leur gestion de base commune, relative à une logique d’animation

Quelques usages généraux de tables dans des applications interactives, objets, personnages, particules

La plupart des choses sont gérées, pour la scalabilitées, sous forme de tables, que ce soit les acteurs principaux (comme les personnages des joueurs), les objets, les particules, les agents actifs, etc. Les objets eux-mêmes, comportent également souvent des sous-éléments sous forme de table, pensez par exemple aux parties du corps d’une chenille.

Donc, la plupart des structures ont généralement quatre fonctions logiques vitales pouvant être gérées de différentes façons :
* Nettoyage d’une table, utilisée lorsque les éléments ne le sont plus, mais peut-être pertinent de l’utiliser également pour initialiser un état général, comme passer du menu au jeu lui même.
* Initialisation de la table, incluans généralement le nettoyage si nécessaire et l’ajout d’1 à n éléments selon les besoins.
* Mise à jour de la table, et des état de ses éléments. Cela inclus leurs relations mécaniques et physiques, leur position, leur changement d’état relatif à leur tracé à l’écran, l’interaction aveec les autres objets, et enfin leur suppression ou création d’un nouvel élément si nécessaire. Tout cela dépendant de critères très variés.
* Sortie du contenu de la table, à l’écran pour l’affichage, mais aussi du son qu’il peut produire, etc.

Les exemples donnés ici peuvent être testé avec l’interpréteur en ligne de commande de Lua, soit en tapant lua dans un shell, puis en les copie-collant, ou sans doute plus pratique, en les collant dans un simple fichier texte, par exemple, fichier.lua, puis en l’exécutant via :

lua fichier.lua

Les derniers exemples utilisent TIC-80, qui est disponible gratuitement et peut être utiliser en Web, mais également pour différents systèmes, tels que Linux, Mac, Windows, Android, Rpi, etc. Il y a une version Pro, mais je n’ai jamais utilisé ses fonctionnalités. Les exemples sont également facilement portable sur d’autres environnements.

Créer une table

On va utiliser une table Lua que l’on appelle objs[] (objs comme objets, j’aime bien mettre un s à la table et pas de s un élément unique). En Lua, il y a une particualarité par rapport aux autre langages informatique. Par défaut, les tables commencent à l’élément 1 lorsque vous les remplissez par objs={elt1,elt2}, mais il est toujours possible d’avoir un éléement ayant pour indexe 0 en utilisantpar exemple objs[0]=elt0. Il est possible de (pre-)initialiser une table video avec objs={}. Si elle n’était pas vide et que ses anciens éléments ne sont plus utilisés, le ramasse miette se chargera de les néttoyer. Ayant pas mal codé en bas niveau (C/C++ et assembleur), je ne suis pas un grand fan des ramasses miettes, mais c’est bien pratique pour les prototypes rapides.

Le contenu de la table peut être simplement affiché à l’écran avec une boucle classique for. Pour la tables appellée objs, #objs peut être utilisé pour connaître le nombre d’éléménts qu’elle contient.

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

Génération procédurale du contenu d’une table

Les systèmes de particules sont utilisés ici pour les nuages, montagnes, personnages, et pour les éléments du corps du dragonEn génération procédurale, le meilleur ami du chaos, également appelé Nature, est la fonction aléatoire (random en anglais), qui génère des nombres aléatoires. Dans le cœur de Lua, la fonction math.random est dédié à ça. Elle accépte des paramètres d’étendue, limité à des entiers avec des valeurs croissantes uniquement. Nous pouvons par exemple, décider de générer un nombre compris entre 1 et 6 inclus, pour déterminer le nomrbe d’éléments que nous désirons obtgenir. Si vous essayez plusieurs fois de suite cette foncvtion, elle affichera une valeur différente comprise entre 1 et 6 à chaque fois, comme lors du lancé d’un dé à 6 faces.

print(math.random(1,6))

Dans un programme interactif ou animé, on veut généralement crée des objets aléatoires, et les faire varier suivant une certaine gestion et pendant un certain temps. Nous remplissons donc dans une tables des valeurs initiales aléatoires, qui seront ensuite réutilisées et modules. On doit donc en premier (re-)initialiser une table objs vide afin qu’elle puisse ensuite être remplie par la boucle for.

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

Nous avons donc généré ici 1 à 6 nombres aléatoires compris entre 1 et 50 et avont assigné ces valeurs à un paramètre appelé lt plutôt qu’à la table directement. Ce type d’élément est accessible de deux façons différentes en Lua, objs[i].lt ou objs[i]["lt"]. La seconde méthode peut être utilie daans certaines situations particulières, nous y reviendrons dans un autre tuto.
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

Nous utilisons ici le symbole de concaténation de chaînes de caractères (symbole ..) afin d’afficher d’avantage d’informations à propos de l’élément que nous affichons.

Exemple simple pour nettoyer une table

Il est important, lorsqu’on nettoie une table ou qu’on en retire des éléments en général, d’effectuer la boucle du dernier au premier indexe d’éléments, car lorsqu’un élément est supprimé, l’indexe des éléments qui le suivent dansla table est décrémenté, on risque donc de sauter des éléments, et de supprimer des éléments non désirés.

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

Dans la fonction Lua standard table.remove() (signifiant table.supprime()) les argumenst sont le nom de la table suivit de l’index de l’élément à supprimer.

Variation et nettoyage d’une table en fonction de tests

Ça peut être une bonne habitude d’utiliser une variable locale de pointeur avec un nom court pointant sur l’élément à traiter, afin de réduire le code à l’intérieur de la boucle, car on risque en général d’avoir à y accéder plusieurs fois. On supprime ici les éléments, lorsque lt (raccourcit pour lifetime, temps de vie) est arrivé à 0. Dans le cas contraire on le décrémente.

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

La variable o ne peut être passer à la fonction table.remove(), car elle est utilisée comme pointeur vers unélément de la table, et nom pas comme nom de la table. Le second argument, est l’index de la table correspondant à l’éléemnt, ça n’est donc pas non plus un pointeur vers un élément.

Nous avosn à présent la base générale d’un sytème de particules.

Tous les systems de particules fonctionne avec une génération, utilisant généralement un peu de hasard et un temps de vie comme critère de base des particules. Les autres critères change plus ou moins en fonction du type de particule.

Compacter un peu le code

J’ajoute générallement les varibles ocale à la fin de la la ligne for...do afin d’avoir un code plus lisible et compacte. De la même façon je place les changements, lorsqu’ils ne sont pas trop longs derrières les mots-clés if...then ou else, afin d’avoir un code plus compacte mais toujours lisible :

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

Lua permet également d’assigner facilement un pointeur de fonction à une variable, j’utilise donc généralement la méthode suivante pour compacter d’avantage le code, comme j’utilise beaucoup l’amis chaos :

m=math rnd=m.random

Donc, ici, m est assigné à la bibliothèque math puis rnd à m(ath).random, que l’on peut décrire comme la fonction random de la bibliothèque math.

Attention : Une contrainte est de ne pas utiliser la variable m, entre sa déclaration comme équivalent de math et l’assignation à d’autres variable des fonctions m.*. Il est donc mieux de les définir en tout débbut de code pour ne pasavoir de problmes et de pouvoir utiliser librement la variable m.

Exemple simple de système de particule graphique

Dans cet exemple, nous allons simplement ajouter une distance aléatoire x (axe horizontal) et y (axe vertical) autour d’un point central, ici on choisit (120,70)

On défini donc le point central 120,70 et on varie la position de départ au hazard de -15 à +15 pixels dans chaque direction :

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

Système de particule basiqueOn fera ensuite varier ces points aléatoirement dans le temps. avec un déplacement d’une distance de 0 à 1 pixel, dans les directions gauche/droite et haut/bas. On utilise donc :
Pour l’axe des x :
* -1 = gauche
* 0 = immobile
* +1 = droite
Pour l’axe des y :
* -1 = haut
* 0 = immobile
* +1 = bas

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

Dans Lua, les fonctions sont définies par function nom_de_la_fonction(arg1,arg2,...) et se terminent par end. Dans le cas de TIC-80, par example, qui a l’avantage d’avoir toutes les fonctionnalités embarquées dans un seul binaire executable, function TIC() est une fonction appelée périodiquement, à chaque rafraichissement d’écran (nouvelle image à l’écran), permettant ainsi d’avoir du cotenu lié au temps (donc de l’animation) facilement. La focntion cls(couleur) y est utilisé pour nettoyer l’écran avec une couleur particulière avec l’inedex de couleur, « couleur », comme TIC-80 utilise une pallette de 16 couleurs indexées sur un total de 16 millions (8bits=256 niveaux pour chaque composante, Rouge, Vert et Bleu. 8^3 ~= 16 millions de couleurs).

l’emplacement des particules est tracé ici par la fonction circ() (raccourcit pour cirle, signiant cercle en anglais).

Définition de la fonction :

circ(centre X, centre Y, rayon, couleur)

On place donc le centre du points aux coordonnées de l’objet, le cercle à un rayon de 1 et utilise l’index de couleur 0,; qi est noir par défaut sous TIC-80.

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

L’actuelle durée de vie restante de cette particule est affichée à l’aide de la fonction print (imprimer), à sa droite, pour la démonstration de cet exemple. Dans le cas de TIC-80 print(), est utilisé pour placer du texte sur l’écran graphique, et trace() sur la console texte.

La partie de arguments de la définition que nous utilisons de print sont sous cette forme :

print(texte, début X, début Y, couleur, fonte de largeur fixe, échelle, petite font)

Nous plaçons donc comme texte le temps de vie restant de la particule actuelle (o.lt), placé au centre de sa position son centre (o.x, o.y), déplacé dhorizontalement de +2 pixel (donc à droite) et verticalement -2 pixel (donc au dessus). Nous utilisons une largeur de fonte fixe (true), à l’échelle 1, et une fonte compacte (true):

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

En Lua on peut définir plusieurs variables sur une même ligne, notamment en croisant leur noms et leurs assignation. Par exemple, ici x=5 y=4 peut également être écrit 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

Dans l’exemple à charger la génération est placée dans une fonction appelée generate(). Celle-ci estg appelée lorsque le contenu de la table est nul (#objs==0) afin de créer une boucle simple de régénération.

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

Si vous désirez dans l’exemple téléchargeable, voir les particules sans leur nombre, il suffit que vous commentiez la ligne comportant le print. Pour commenter du code en Lua, il suffit simplement de le précéder de deux traits d’union.

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