Archives pour la catégorie Practice-oriented tutorials

Some practice-oriented tutorials

Leçon 1 : Premiers pas avec le Lua sur TI-Nspire

Aujourd’hui, Inspired-Lua vous propose une traduction et adaptation du guide de Steve Arnold que vous pouvez retrouver en cliquant ici. Depuis l’OS 3.0, les Ti-Nspire possèdent une nouvelle fonctionnalité en matière de programmation : le Lua. Ce dernier est un langage de programmation à la fois moderne et rapide. Les scripts écrits en Lua avec un simple éditeur de texte peuvent être convertis en .tns (format des documents TI-Nspire) à l’aide de TI-Nspire Scripting Tool . De tels scripts donnent de nouvelles possibilités étonnantes et puissantes pour la création de documents TI-Nspire afin d’apprendre ou d’enseigner.

Avec un peu d’expérience, les programmeurs de Lua peuvent créer d’incroyables programmes, auxquels l’imagination est la seule limite. A titre d’exemple, voici un tableau périodique des éléments réalisé par l’équipe de TI-Planet. Comme vous pouvez le voir, les possibilités sont énormes. Toutefois, même les débutants peuvent profiter des particularités offertes par le Lua dans des conditions plus limitées mais qui restent quand même puissantes. Ce tutoriel pour débutants offre de bonnes bases grâce auxquelles les élèves comme les enseignants pourront commencer à créer leurs propres documents !

L’objectif ici sera de commencer le Lua en affichant du texte. Des graphiques et des images dynamiques suivront plus tard.

Leçon 1.1: Premiers pas avec le Lua sur TI-Nspire

Pour cette première leçon, nous utiliserons le programme Oclua (On Calc lua) développé par Olivier Armand. Commencez par télécharger l’archive Oclua d’après ce lien . Ensuite, décompressez l’archive et transférez le fichier .tns sur votre calculatrice.

Gif Oclua
Oclua fonctionne à la fois sur la calculatrice et sur le logiciel TI-Nspire. Pour commencer à utiliser Oclua, ouvrez tout d’abord le fichier, puis créer une nouvelle application dans le classeur. (CTRL+I) Choisissez l’éditeur mathématique. Vous pourrez écrire le code en Lua ici. Ensuite, pour l’exécuter, vous n’aurez qu’à copier ce code et à le coller dans le premier onglet. (CTRL+A pour tout sélectionner, CTRL+C pour le copier, et enfin CTRL+V pour le coller) Rapide et facile à prendre en main, Oclua est idéal pour commencer à utiliser le Lua. Cette procédure est expliqué à travers l’image en gif ci-contre (Ignorez les deux lignes horizontales, elles sont dues au logiciel utilisé pour enregistrer l’animation – elles n’apparaîtront pas sur votre version du document). Toutefois, nous verrons par la suite que de meilleures solutions existent.

Les choses sérieuses commencent : nous allons créer votre première fonction en Lua ! Mais ne vous inquiétez pas, rien de bien compliqué. Tout d’abord, nous allons apprendre comment afficher du texte en Lua. Insérez une page éditeur mathématique comme nous l’avons vue. Recopiez-y le code ci-dessous

function on.paint(gc)
  gc:drawString("hello world", 0, 20)
end

Notez que l’indentation (ajout d’espace/tabulation dans des scripts) n’est pas du tout obligatoire elle permet juste de mieux se retrouver dans de longues lignes de codes. (Ici elle n’a que peu d’intérêt mais il faut mieux prendre ces habitudes dès le départ)
Le Lua est un langage sensible à la casse c’est-à-dire que vous devez écrire exactement les fonctions comme montrées ici. Dans cet exemple, tout est en minuscules, excepté le « S » de String.
Vous devriez voir le texte « hello world » écrit en haut à gauche de la page. Voyons ce que l’on peut apprendre de cet exemple :

  • La structure pour définir une fonction est la même que dans beaucoup de langages.
function nom(argument)
  quelques instructions
end
  • Dans notre exemple, nous avons utilisé une fonction standard du Lua appelée « on.paint ». Vous la rencontrerez dans la plupart (si ce n’est tous) les scripts en Lua. Lorsque vous utilisez cette fonction, elle affiche le texte sur l’écran.
  • « gc » signifie « graphics context ». (Contexte graphique :P) Il est utilisé quand des éléments graphiques de n’importe quel type sont employés. Vous pouvez voir dans cette fonction, l’unique ligne de code est définie par ce terme gc. Ne vous inquiétez pas, vous vous y habituerez vite !
  • La ligne d’instruction de cette fonction est assez explicative : gc:drawString (“hello world”,0,20). Dans le contexte graphique (gc) on va afficher (draw, dessiner) la chaîne de caractère (String) qui est “hello world” à la position (0,20) sur la fenêtre
  • Il faut savoir que le système de coordonnées à pour origine le coin en haut à gauche de l’écran. Ainsi, les coordonnées ne doivent pas être négative pour afficher correctement du contenu graphique. Dans notre exemple, le point choisi est (0,20). Si l’ordonnée était inférieure, le texte serait coupé.
Vous devriez prendre quelques minutes pour découvrir cette première fonction et appliquer ce que vous venez d’apprendre. Essayez de déplacer le texte afin de comprendre le système de coordonnées. Essayez de centrer votre texte. Vous en apprendrez ainsi plus sur les dimensions de l’écran.
Cependant, vous verrez plus tard qu’un texte centré sur une plateforme (calculatrice, ordinateur) n’est pas forcément adapté à une autre. Mais alors, comment faire ? Nous allons voir cela dans la suite de notre cours ! En attendant, amusez-vous bien ! 🙂

Mais pourquoi ?

Il est peut-être temps de s’arrêter un instant et de se demander – Pourquoi s’ennuyer à faire cela ? Il y a d’autres façons beaucoup simples pour afficher du texte à l’écran.
Deux propriétés très importantes d’une fenêtre en Lua sur TI-Nspire, par opposition à une fenêtre classique dans l’éditeur mathématique :
  • Cliquez sur n’importe quelle fenêtre en Lua. Déplacez-la, essayez de l’éditer. C’est impossible. Le texte que vous affichez ne peut pas être édité par l’utilisateur du document. Dans l’éditeur mathématique, l’utilisateur peut bien sur changer – et en effet détruire – tout ce que l’auteur a pris le temps de faire. En plus, comme on peut le faire dans l’éditeur, le texte affiché peut être à la fois dynamique et statique. Donc on peut facilement créer de puissants outils d’apprentissage tout comme on peut le faire avec l’éditeur, mais dans un environnement plus sécurisé.
  • Dans la seconde partie de cette leçon, vous apprendrez à contrôler la taille de la police, la couleur et le style, et comment facilement centrer le texte sur une ligne, et même au centre de la fenêtre. En Lua, on a un contrôle significatif de la façon dont le texte est affiché – bien plus qu’en utilisant l’éditeur. En terme de couleurs, vous avez accés à des millions de couleurs !

Leçon 1.2: Un peu plus intéressant ?

Bon, retour au travail. Prêt pour la suite ?
Si vous n’êtes pas sur la page 1.2 d’Oclua, retournez-y. Nous allons ajouter quelques lignes à notre script on.paint.
function on.paint(gc)
  gc:setFont("sansserif", "b", 12)
  gc:setColorRGB(158, 5, 8)
  gc:drawString("Ceci est mon texte", 20, 20)
end
A nouveau, étudiez ces quelques lignes – essayez de modifier les différentes valeurs. Vous allez vite vous rendre compte que setFont possède trois entrées :
  • la famille : « serif » ou « sansserif »
  • le style : « b » pour bold (gras) ; « r » pour regular (normal) ; « i » pour italic (italique) ; « bi » pour bold italic (gras et italique)
  • la taille

setColorRGBpermet d’accéder simplement à une multitude de couleurs : RGB signifie Red (rouge ; 255,0,0) Green (vert ; 0,255,0) Blue (bleu ; 0,0,255). Il y a de nombreuses couleurs entre ces valeurs, ou vous pouvez accéder à la liste en ligne ou juste télécharger le PDF que j’utilise. Mes couleurs fétiches sont burgundy (158, 5, 8 )> et navy (20, 20, 138), et qui vont très bien ensemble ! C’est vraiment mieux qu’une simple palette de 9 à 15 couleurs actuellement disponible sur TI-Npire !Si vous n’êtes pas perdu en lisant ce cours, c’est que vous êtes sur la bonne voie ! Nous allons finir cette leçon par une notion importante en Lua : centrer le texte. Nous en profiterons pour introduire les variables locales et globales.

Le Lua dispose de toutes sortes de commandes très utiles, comme platform.window:heigth() et platform.window:width().

Comme vous pouvez le deviner, ces commandes permettent de récupérer les valeurs actuelles de la fenêtre. Ainsi, platform.window:heigth() permet de connaître la hauteur de l’écran tandis que platform.window:width(). permet d’en connaître la largeur. Une nouvelle fois, faites bien attention aux majuscules et aux espaces ! Ici, tout est en minuscules.
Si on stock ces valeurs dans des variables, que nous appellerons w et h (pour width et height respectivement), nous pourrons les réutiliser hors de la fonction et dans un script plus grand. Mais nous aurons l’occasion d’y revenir un peu plus tard.

Voici deux nouvelles fonctions tout aussi importantes : getStringHeight et getStringWidth. Comme leurs noms l’indiquent, elle permettent de déterminer la largeur et la hauteur d’une chaîne de caractères.

function on.paint(gc)
  local h=platform.window:height()
  local w=platform.window:width()
  gc:setFont("sansserif", "b", 12)
  gc:setColorRGB(158, 5, 8)
  local sw = gc:getStringWidth("Ceci est mon texte")
  local sh = gc:getStringHeight("Ceci est mon texte")
  gc:drawString("Ceci est mon texte", w/2 - sw/2, h/2 + sh/2)
end
On commence par définir les dimensions de la fenêtre avec w et h. On peut aussi obtenir les dimensions de la chaîne de caractères
Maintenant, pour centrer la chaîne :
  • Horizontalement : on prend le centre de la fenêtre (w/2) puis on recule de la moitié de la largeur de la chaîne de caractères (w/2 – sw/2).
  • Veritcalement : on suit la même procédure, à une différence près : verticalement, on compte à l’envers en Lua : plus on va bas, plus le nombre est grand ; plus on va haut, plus il est faible ! (h/2 + sh/2)

Et maintenant ?

C’est tout pour cette leçon – à vous de jouer !
Pourquoi ne pas essayer d’aligner votre texte à droite ? Jetez un œil au centrage que nous venons de réaliser et inspirez-vous-en pour aligner le texte à droite et à gauche.
Et pour le placer en haut ou en bas ? Comment feriez vous ? Essayez différentes couleurs !Dans la prochaine leçon, nous apprendrons à donner vie à notre texte et à utiliser une table pour organiser plusieurs lignes de texte de façon structurée sur votre page !

Leçon 2 : Créer une table dynamique

Dans cette leçon, nous allons introduire deux notions très importantes, et surtout pratiques du Lua : créer une table, et récupérer une variable d’une application TI-Nspire vers un script en Lua. Nous allons aussi rencontrer les boucles « For ». Si vous débutez en programmation, je vous recommande fortement de vous familiariser avec cette boucle dans d’autres langages, par exemple en TI Basic, avant de tenter ce genre de choses en Lua.A nouveau nous utiliserons Oclua pour créer et tester les scripts vus lors de ce cours, seulement pour notre confort. Les scripts en Lua peuvent être écrits dans n’importe quel éditeur de texte (De NotePad à Word, en passant par le bloc-notes). Pour les utilisateurs de windows, la gratuité de NotePad++ en fait un excellent choix pour ce genre de travail car il colore le texte et participe à la structure de votre script. Pour les utilisateurs de Mac, Xcode est sur votre CD d’installation sous les Outils Développeurs, et fera parfaitement l’affaire. Si vous êtes prêts à dépenser quelques euros, TextMate est excellent (et « connaît » même le Lua ce qui peut aider pour la syntaxe et les bugs).

Mais alors, pour quoi ne pas garder Oclua ? Eh bien, le document peut seulement être lu. Lorsque vous créez une page en Lua en collant votre script, tout semble normal. Cependant, fermez et ré ouvrez votre document (même après avoir enregistré) et vous revoilà devant la page vide « Paste your script here ». Ainsi, ce programme est génial pour apprendre et tester les scripts, mais si vous avez besoin d’utiliser un script à n’importe quel moment, vous aurez besoin de TI-Nsipre Scripting Tools, dont nous reparlerons dans la prochaine leçon. En attendant, nous continuerons avec Oclua. Dans la dernière leçon, nous avons découvert les variables locales, et la création de w et h qui représentent la largeur et la hauteur de la fenêtre. Ces variables s’ajustent dynamiquement. Ainsi, si vous passez de la vue en mode ordinateur à la vue calculatrice, ou si vous redimensionnez ou partagez la fenêtre, alors les variables s’adapteront. Utiliser ces variables plutôt que des valeurs statiques signifie que votre page aura le même affichage, quelle que soit la fenêtre.

Dans cet exemple, nous commencerons par définir deux nouvelles variables locales : La table, grâce à des accolades vides (comme sur TI-Nspire), et le nombre de lignes.

Leçon 2.1 : La boucle For en Lua

Comme je l’ai dit précédemment, je suppose que vous avez déjà eu l’occasion de rencontrer la structure « For…End » (Elle s’appelle « For…EndFor » sur TI-Nspire. En Lua, les fonctions de contrôle se terminent toutes par End)

Boucle sur TI-Nspire

For k, 1, 10
   var := k* (k+1)
EndFor

Boucle en Lua

for k = 1, 10 do
   var = k* (k+1)
end

Le résultat de ces deux boucles est identique : à la fin, la variable var vaudra 110. La syntaxe en Lua est similaire à celle de la TI-Nspire. Au lieu d’utiliser For k, de, à, [pas] sur TI-Nspire, le Lua remplace la première virgule par un égal, le mot « do » apparaît à la fin de la ligne de définition, et enfin, veillez à ce que tout soit en minuscules. Le pas est [optionnel] dans les deux cas.

Nous allons maintenant nous appuyer sur un script qui nous servira d’exemple dans la suite de ce cours.

function on.paint(gc)
  local h = platform.window:height()
  local w = platform.window:width()
  local table = {}
  local nbligne = 3
  gc:setFont("sansserif","r",10)
  gc:setColorRGB(158,8,5)
 
  for k = 1, nbligne do
    table[k] = "Ligne #"..k
    strheight = gc:getStringHeight(table[k])
    strwidth = gc:getStringWidth(table[k])
    gc:drawString(table[k], w/2-strwidth/2, h*k/(nbligne + 1) + strheight/2)
  end
end

Dans cet exemple, nous irons de k = 1 à k = 3, en affichant chaque ligne au fur et à mesure. Les possibilités de cette structure sont assez évidentes – ici, on peut facilement afficher 10 lignes, ou n’importe quel nombre …

Vous avez peut-être reconnu les quelques ligne de l’exemple précédent : lignes qui définissent la police, la couleur, la largeur / hauteur de la chaîne de caractères, et enfin qui affiche le string. Ici, on ajoute une ligne qui crée chaque ligne de notre table. Histoire de bien mettre les choses au clair, la syntaxe table[k] fait référence au k-ème élément de la table. Donc table[1] est la première « ligne » ou « rangée » ou quoi que ce soit qui vous permette de visualiser. Cela fonctionne exactement de la même façon que sur TI-Nspire.

Leçon 2.3 : Créons des lignes pour notre Table !

Pensons un instant à l’organisation d’une table sur TI-Nspire. On la définirait ainsi :

 table := { "un", "deux", 7 }

Maintenant, si on utilisait table[1], on obtiendrait « un », et pour table[3], on obtiendrait la valeur 7. En Lua, la même chose se produirait. En fait, le Lua est même un peu plus flexible dans la maniabilité des variables. Sur TI-Nspire, il faut bien faire attention à distinguer le string « 7 » du chiffre 7. Ces deux variables ont une structure de données différente. En Lua, cela n’a pas d’importance, tant qu’elles sont utilisées de manière adéquate. Donc même si vous utilisez une variable num qui contient le string « 7 », le Lua peut parfaitement l’utiliser en tant que chiffre, avec par exemple 2*num qui va donner 14. En revanche, si num contenait « sept », le calcul serait impossible, car on ne peut évidemment pas multiplier un string par un nombre.

Revenons en à notre exemple : on crée en fait chaque ligne de notre table au fur et à mesure que le programme progresse. Quand k = 1, alors table[1] est défini comme la concaténation (Mot barbare, la mise bout à bout de deux chaînes) grâce aux deux points « .. » du string « ligne # » et de la valeur de k (1). Donc, table[1] = « ligne#1 ». Facile !

Leçon 2.4 : Plaçons ces nouvelles lignes !

Créer toutes ces lignes est plutôt facile. Mais nous devons un peu réfléchir et calculer avant de les afficher correctement. On les centrera horizontalement, comme on l’a déjà fait. Cependant, nous devons les espacer de la même façon verticalement. En d’autres termes, nous devons diviser notre hauteur de fenêtre (h) par un plus le nombre de ligne (1 – nbligne) – car on place en fait les espaces entre les lignes ! Une fois que l’on a compris ceci, le calcul devient plus simple : h*k / (nbligne + 1).
Un petit exemple pour bien comprendre : On veut afficher 3 lignes.
– On aura la première à 1*h / 4
– La deuxième à 2*h / 4 (qui donne h/2)
– La dernière à 3*h / 4
On peut encore faire mieux ! Comment me direz-vous ? En ajoutant la moitié de la hauteur du string ! (h*k / (nbligne + 1) + strheight / 2) Les lignes seront maintenant parfaitement alignées !

________________________

Wow ! On a déjà parcouru un long chemin depuis vos débuts ! Prenez une pause ! Je vous conseille d’essayer de comprendre ce qui se passe plus haut. Modifiez, touchez à tout, comprenez ! On apprend toujours par ses erreurs !

Vous êtes maintenant prêts pour ma dernière partie de ce cours ! On va rendre le tout dynamique !

________________________

Leçon 2.5 : Donnons vie à nos lignes !

Avant de commencer, un petit rappel : un affichage dynamique est par définition le contraire d’un affichage statique. C’est-à-dire qu’un affichage dynamique va s’ajuster grâce à différents paramètres, par exemple un ou plusieurs changements dans une / des variable(s) ; alors qu’un affichage statique ne change pas. (Il porte bien son nom !)

Revenons-en à nos moutons. Nous allons commencer par diviser notre écran (sur le Ti-Nspire Computer Software, en allant dans DOC, et choisir le partage vertical), ensuite dans une des deux parties, nous allons créer un curseur grâce à l’application géométrie.

Après avoir choisi cette application, allez dans Menu > Actions > Insérer un curseur. Ensuite, placez le où vous voulez. Click droit sur le curseur, puis choisissez les paramètres du curseur :
– Variable : lignes
– Valeur : 5 (Cela n’a pas d’importance)
– Minimum : 1
– Maximum : 5
– Incrément : 1
– Style : vertical

Pour une meilleure apparence (optionnel !), click droit sur le curseur, puis choisissez réduire avec le style vertical.

Créer ce curseur est un jeu d’enfant. Mais à quoi ça sert si on ne l’utilise pas dans un script en Lua ? Une solution très simple existe. Elle s’appelle var.recall. Cette commande va nous permettre de remplacer la valeur fixe de nbligne par une valeur dynamique, celle du curseur. On va donc utiliser :

 local nbligne = (var.recall("lignes") or 1)

Ici, var.recall recherche une variable appelée « lignes » et attribue sa valeur à nbligne. (Si la variable lignes existe bien sur) Sinon, elle attribue la valeur 1 – pour ne pas faire planter le programme dans le cas où lignes n’existe pas. Cool.

Et maintenant ?

Bravo ! Ainsi s’achève la deuxième leçon. Prenez un peu de temps pour assimiler toutes ces nouveautés avant de passer à la suite.

Dans la prochaine leçon, on verra comment modifier le contenu de ces lignes, car je suppose qu’obtenir un alignement de « ligne#1 », « ligne#2 », etc ne vous sera que de faible utilité ! 😀

Leçon 3 : Varier le contenu d’une table et opérateur conditionnel

Dans cette leçon, nous allons continuer notre travail sur les tables et sur les variable issues de TI-Nspire. Nous allons facilement customiser notre document, et avec un changement d’une ligne, nous allons créer une page qui peut être utilse à ceux qui veulent tirer avantage du Lua dans leur programmes TI-Nspire.
Mais avant, nous allons quitter Oclua pour TI-Nspire Scripting Tools, ou pour Luna. Tous deux sont légers et faciles à utilser, mais différents de Oclua. Pour cela, je vous envoie vers ce lienqui présente les façons d’exécuter un script écrit en Lua.

 

Leçon 3.1 : Modifions le contenu de nos lignes d’affichage

Un simple changement dans notre script transforme notre affichage de plusieurs lignes en un outils plus…utile.
Souvenez-vous : la ligne du script qui créait chacune des lignes d’affichage était celle-ci :

table[k] = "Ligne#"..k
Elle concaténait la valeur actuelle de k avec le string « Ligne# », ce qui faisait de la première « Ligne#1 ».
Souvenez-vous : la commande var.recallva chercher la valeur d’une variable TI-Nspire et l’attribue à une variable du script lua. Dans notre exemple, nous l’avions utilisé pour saisir le nombre de lignes que l’on voulait afficher.Maintenant, supposons que nous ayons une variable appelée ligne1, contenant ce que l’on veut afficher en première ligne. Puis une autre appelée ligne2 et ainsi de suite ? On pourait facilement contrôler le contenu de notre affichage, et les modifier n’importe quand depuis la Ti-Nspire. Pour cela, on pourrait simplement changer la ligne ci-dessus par :
table[k] = (var.recall("line"..k) or "Line #"..k)

Etudiez ces nouvelles lignes et essayez de comprendre ce qui se passe. Lorsque k = 1, var.recall recherche une variable appelée ligne1 et la range dans table[1] (La première entrée de la table, « table »). Si on ne la trouve pas, alors elle est stockée en tant que « ligne #1 ». (On aurait très bien pu laisser un blanc, avec juste «  ».) Et ainsi de suite pour les différentes valeurs de k.

Donc, en stockant ces variables dans un document TI-Nspire, elles sont immédiatemment affichées dans la page du script Lua.

Leçon 3.2 : Les conditions

Pour notre introduction au lua, nous avons besoin d’autres ingrédients : les structures conditionnelles. Ces dernières se ressemblent fortement en Lua et en TI-Nspire.
if condition then
  instructions
else
  instructions
end

Seul le endif se transforme en end !

Prenons un exemple : on veut que la première et la dernière ligne soient de la même couleur. Reprenons notre script.

for k = 1, linecount do
  gc:setFont("sansserif", "r", 10)
  gc:setColorRGB(158, 5, 7)
  table[k] = (var.recall("line"..k) or "Line #"..k)
  strwidth = gc:getStringWidth(table[k])
  strheight = gc:getStringHeight(table[k])
  gc:drawString(table[k], w/2 - strwidth/2 ,h*k/(linecount+1) + strheight/2)
end
Maintenant, il suffit d’ajouter une condition dans le bloc For. Si la ligne actuelle est la première / dernière, alors elle sera colorée.
if k == 1 or k == linecount then
  gc:setFont("sansserif", "b", 10)
  gc:setColorRGB(20, 20, 137)
else
 gc:setFont("sansserif", "r", 10)
 gc:setColorRGB(158, 5, 7)
 
end
Il faut bien entendu mettre le tout dans la fonction on.paint(gc). Aussi, notez l’emploi du double signe égal que l’on utilise pour tester une égalité. Un simple signe égal est utilisé pour une définition. (k = 1)
A part cela, vous êtes largement en mesure de comprendre ce morceau de script. Sinon, retournez voir les leçons précédentes !Et de 3 ! Vous venez de finir la troisième leçon de ce tutoriel. Maintenant vous pouvez afficher du texte (un peu plus intéressant) et utiliser les conditions ! Prenez un peu de temps avant de passer à la suite ! ;)Dans le prochain cours, nous apprendrons à écrire du texte directement dans notre fenêtre Lua, ce qui est la base pour les jeux de type quizz !

Comment réaliser un Gestionnaire d’Ecrans

Lorsque l’on crée un jeu ou un outil quelconque de manière « complète », on désire souvent réaliser un panel d’écrans dans lequel l’utilisateur naviguera. Il existe plusieurs manières de réaliser un moteur qui nous permettra de gérer tous ces écrans, du plus simple à coder mais le moins pratique, au plus difficile à comprendre mais facile d’utilisation. L’objectif de ce tutoriel n’est bien évidemment pas de vous donner une idée fixe de ce à quoi ressemble un gestionnaire d’écran (il en existe une multitude de types), mais de vous présenter un panel de choix. Ce tutoriel est long car exhaustif en exemples et théorie, ne lâchez pas le fil!

Tout d’abord, ce que l’on entend par « gestionnaire d’écrans » c’est une manière d’organiser le code afin que l’on puisse isoler les parties de dessin des parties fonctionnelles. Plus cette frontière est marquée, plus le code est propre et lisible, et permettra donc d’intégrer plus facilement notre fameux « gestionnaire d’écrans ».

Prenons un exemple, nous souhaitons réaliser un jeu simple avec un menu, le jeu, une page d’aide et une page de records. A première vue, le nombre d’écrans est limité et fixé avant la création par notre cahier des charges. Ce même nombre est faible (4) et il est donc facile d’envisager quelque chose en ce sens :

function on.create()
  screen = 0 -- 0=menu, 1=game, 2=help, 3=highscores
end
 
function on.paint(gc)
  if screen == 0 then -- we draw the menu
  elseif screen == 1 then -- we draw the game
  elseif screen == 2 then -- we draw the help
  elseif screen == 3 then -- we draw the highscores
  end
end
 
function on.enterKey()
  if screen == 0 then
    screen == 1
  elseif screen == 1 then
....

Ok ! inutile d’aller plus loin ! On a compris. Pour créer un code moche, long à écrire et j’en passe, c’est la meilleure solution. Il est avant tout destiné aux applications de très petite taille car facilement implémentable.

Il y a cependant moyen de faire moins moche, en utilisant des tableaux de fonctions.

function on.create() -- or on.construction with OS >= 3.2
  menu, game, help, highscores = 1, 2, 3, 4
  screen = menu
  paints = {}
  enterKeys = {}
end
 
function on.paint(gc)
  paints[screen](gc)
end
 
function on.enterKey(gc)
  enterKeys[screen](gc)
end
 
paints[menu] = function(gc)... end -- we draw the menu here
paints[jeu] = function(gc) ... end -- we draw the game here
...
enterKeys[menu] = function(gc)... end -- menu handling here
enterKeys[jeu] = function(gc) ... end -- game handling here
....

Ici, il est évident que la lecture du code sera bien plus simple qu’auparavant. Par ailleurs, l’utilisation d’étiquettes au lieu de valeurs propres améliore considérablement la lecture du code ! N’hésitez pas à en abuser ! Vous pouvez, si vous avez trop de « constantes », utiliser un tableau de constantes afin de les organiser, comme ceci :

screen = {menu=1, jeu=2, aide=3, records=4}
--> screen.menu == 1

Ou encore pour faire quelque chose d’automatisé (plus besoin de compter/décaler les chiffres) :

function createEnv(t)
  local env = {}
  for i, v in ipairs(t) do
    env[v] = i
  end
  return env
end
screen = createEnv({"menu", "game", "help", "highscores"})
--> screen.menu == 1

Ceci étant, la gestion des différents écrans reste archaïque pour des usages autres que les jeux. Il est bien entendu possible de créer un système plus élaboré qui facilite l’utilisation et le coding. Quoi demander de plus ?

Vous l’aurez deviné, il faut utiliser … les classes !

Ce que l’on va s’apprêter à coder est en fait une surcouche de l’API TI-Nspire. Vous connaissez les évènements on.paint(), on.arrowKey() etc … et bien nous allons by-passer leur utilisation par notre gestionnaire d’écrans. L’intérêt de coder une classe mère ici est que nous sommes sûr qu’un écran a telles ou telles méthodes; méthodes que l’on appellera depuis les évènements standards sans risquer d’en oublier lorsque l’on code un nouvel écran.

Tout d’abord, il faut créer notre classe Screen :

Screen = class()
function Screen:init() end

Pour commencer, un écran n’a pas besoin d’initialisation spéciale. Rappelons le encore une fois, ce que nous définissons est une surcouche de l’API TI-Nspire, nous allons donc écrire (sans en définir le contenu !!) exhaustivement la liste des fonctions évènementielles qui sont disponibles :

function Screen:paint(gc) end
function Screen:arrowKey(key) end
function Screen:timer() end
function Screen:charIn(ch) end
....

Ces fonctions sont qualifiées de « virtuelles » qui devrons être redéfinies . Parce que la classe ne comprend ici que des fonctions virtuelles, elle est également qualifiée de virtuelle (un peu de vocabulaire ne fait pas de mal). Le gestionnaire d’écrans passe par la création d’une classe virtuelle, un modèle, un tampon qui nous garanti l’existence des fonctions lorsque l’on va coder la liaison évènementielle :

activeScreen = Screen()
function on.paint(gc) activeScreen:paint(gc) end
function on.arrowKey(key) activeScreen:arrowKey(key) end
function on.timer() activeScreen:timer() end
function on.charIn(ch) activeScreen:charIn(ch) end

Ainsi, lorsque l’on veut rajouter le code pour un écran, on code comme si on ne codait qu’un écran ! Il suffit de penser que « Menu: » est « on. »

Menu = class(Screen)
function Menu:init() end
function Menu:paint(gc) gc:drawRectangle(0, 0, 50, 50) end
function Menu:arrowKey(key) ... end
activeScreen = Menu()

Cette technique est très utilisée mais elle a cependant un point faible : à chaque changement d’écran on recréer un objet d’écran. Dans certains ça peut être très utile (réinitialisation du jeu), dans d’autres c’est inutile (le menu ne bouge pas). On peut toujours, stocker ça dans des variables, ou bien passer uniquement la classe elle même en paramètre. Mais il y a encore mieux.

En effet, il est souvent d’usage de coupler cette technique avec un pile. Une pile est liste spéciale : une structure de donnée surnommée « first in, first out » (ou encore FIFO), littéralement, « premier rentré, premier sorti ». L’utilisation d’une pile ici permet de stocker les écrans initialisés dans une liste ordonnée, tout en conservant le fonctionnement précédent.

Nous allons donc rajouter la gestion de la pile. Pour cela il faut changer les accès à activeScreen par activeScreen(), remplacer les assignations de activeScreen par une fonction qui va rajouter l’écran à la pile (PushScreen()) et ne pas oublier de dépiler les écrans une fois qu’on ne s’en sert plus.

Voici ce que cela donne :

------ Screen Manager
Screen = class()
 
function Screen:init() end
 
-- virtual functions to override
function Screen:paint(gc) end
function Screen:timer() end
function Screen:charIn(ch) end
function Screen:arrowKey(key) end
function Screen:escapeKey() end
function Screen:enterKey() end
function Screen:tabKey() end
function Screen:contextMenu() end
function Screen:backtabKey() end
function Screen:backspaceKey() end
function Screen:clearKey() end
function Screen:mouseMove(x, y) end
function Screen:mouseDown(x, y) end
function Screen:mouseUp() end
function Screen:rightMouseDown(x, y) end
function Screen:help() end
 
local Screens = {}
 
function PushScreen(screen)
    table.insert(Screens, screen)
    platform.window:invalidate()
end
 
function PullScreen()
    if #Screens > 0 then
        table.remove(Screens)
        platform.window:invalidate()
    end
end
 
function activeScreen()
    return Screens[#Screens] and Screens[#Screens] or Screen
end
 
-- Link events to ScreenManager
function on.paint(gc)
   for _, screen in pairs(Screens) do
        screen:paint(gc)
    end
end
 
function on.timer()
    for _, screen in pairs(Screens) do
        screen:timer()
    end
end
 
function on.charIn(ch) activeScreen():charIn(ch) end
function on.arrowKey(key) activeScreen():arrowKey(key) end
function on.escapeKey()	activeScreen():escapeKey() end
function on.enterKey() activeScreen():enterKey() end
function on.tabKey() activeScreen():tabKey() end
function on.contextMenu() activeScreen():contextMenu() end
function on.backtabKey() activeScreen():backtabKey() end
function on.backspaceKey() activeScreen():backspaceKey() end
function on.clearKey() activeScreen():clearKey() end
function on.mouseDown(x, y) activeScreen():mouseDown(x, y) end
function on.mouseUp() activeScreen():mouseUp() end
function on.mouseMove(x, y) activeScreen():mouseMove(x, y) end
function on.rightMouseDown(x, y) activeScreen():rightMouseDown(x, y) end
function on.help() activeScreen():help() end
 
function on.create() PushScreen(Menu()) end
function on.resize() end

NB : le fait d’être exhaustif à ce point n’est pas obligé. Il faut par contre que le nombre de fonctions dans la classe Screen corresponde au nombre d’évènements définis.

Utilisation d’une variable existante dans un classeur TI-Nspire

Retour à la partie 3

Cette partie vous montrera que le Lua est bel et bien en parfaite harmonie avec la TI-Nspire et son framework. Pour cela nous vous proposons d’étudier l’API var et les évènements qui en découlent.

Tout d’abord , créez un nouveau classeur TI-Nspire et définissez y une variable n, par exemple un curseur permettant d’en faire varier la valeur entre 0 et 10 ou directement dans la page de l’application calculs.

C’est cette variable que nous allons récupérer dans le script Lua !

Pour cela, créez un nouveau fichier Lua avec votre éditeur de texte préféré et nous allons commencer à le remplir.

L’API var permet de faire pleins de choses intéressantes et nous allons les étudier.

Tout d’abord, notre script doit savoir si la variable n change. Nous trouvons donc cette ligne :

 

-- On indique ici qu'il faut surveiller le contenu de la variable n
var.monitor("n")

Au passage, nous pouvons écrire une fonction récursive qui renverra la factorielle d’un nombre, rien que pour l’exemple :

function factorielle(n)
	if math.floor(n) < n or n < 0 then
		return ("Erreur")
	elseif n == 0 then
		return(1)
	else
		return(n * factorielle(n - 1))
	end
end

Maintenant, nous allons nous intéresser au couplage des évènements. Il nous faut deux évènements. D’abord celui pour dessiner à l’écran, c’est à dire on.paint(), mais également un évènement déclenché lorsque notre variable change. Cet évènement est on.varChange() et est lancé chaque fois qu’une variable appartenant à la liste des variables surveillées (avec var.monitor()) est modifiée.

function on.varChange(varlist)
	-- On provoque une reactualisation de la fenetre
	platform.window:invalidate()
end

Concrètement, dès qu’une variable surveillée change, on demande à ce que l’écran soit actualisé. Donc maintenant, il faut faire cette partie d’affichage en créant la fonction on.paint(). En effet, appeler platform.window:invalidate() marque l’écran comme « invalide », donc bon à être actualisé. Au prochain tour de boucle de processus, comme l’écran doit être actualisé, le framework de la TI-Nspire lancera la fonction on.paint()

function on.paint(gc)
	local wh, ww, n, x
	-- nombre de pixels (hauteur et largeur)
	wh = platform.window:height()
	ww = platform.window:width()
 
	-- affichage d'un trait de separation
	gc:setPen("medium", "smooth")
	gc:drawLine(0, 60, ww, 60)
 
	-- affichage de la taille de la fenetre en bas de l'ecran
	-- il s'agit juste d'un exemple !
	gc:setColorRGB(200, 200, 200)
	x = gc:drawString(wh, 10, wh - 10, "bottom")
	gc:drawString(ww, x + 10, wh - 10, "bottom")
 
	-- affichage de n!
	n = var.recall("n")
	if math.floor(n) < n or n < 0 then
		gc:setColorRGB(255, 0, 0)
		gc:setFont("sansserif" , "b", 10)
		gc:drawString("n n'est pas un ",10,10,"top")
		gc:drawString("entier naturel ",10,25,"top")
	else
		gc:setColorRGB(0, 0, 255)
		gc:setFont("sansserif" , "b", 20)
		x = gc:drawString(n.."! = ", 10, 10, "top")
		x = gc:drawString(factorielle(n), x + 5, 10, "top")
	end
end

Voilà ! C’est tout !

Lancez ensuite TI-Nspire Scripting tools et cliquez sur le premier bouton (ou choisissez tools, Lua Script to Clipboard) puis sélectionnez le fichier contenant le script que nous venons de créer. Allez dans le logiciel TI-Nspire, et utilisez Ctrl V pour copier le code Lua.

Faites ensuite varier la valeur de n, et la miracle !

La valeur dans la fenêtre Lua est actualisée !

Tip : Si vous avez modifié le script, il vous suffit dans TI-Nspire Scripting Tools de

  • cliquer sur le second bouton (ou choisissez tools, Reload Script).
  • Allez ensuite dans le logiciel TI-Nspire, cliquer sur la fenêtre correspondant au code Lua.
  • Ctrl K pour sélectionner cette fenêtre
  • Ctrl V pour copier le nouveau script Lua

Idées d’améliorations :

Vous pouvez tester une première « amélioration » de ce script en ajoutant les lignes suivantes, permettant de « piloter » n avec les touches « vers le haut » ou « vers le bas » :

function on.arrowUp()
	var.store("n", var.recall("n") + 1)
end
 
function on.arrowDown()
	var.store("n", var.recall("n") - 1)
end

>> Partie 5