[Tutoriel] Syntaxe lua et exemple de module |
Podoko « Citoyen » 1413725760000
| 15 | ||
Syntaxe lua Ce topic sert à apprendre comment créer des modules en maison de tribu sur Transformice. Les bases du langage ainsi que quelques points complexes y sont expliqués. N'oubliez pas que le seul meilleur moyen d'apprendre à coder est la pratique, lire ce tutoriel n'est pas suffisant pour savoir créer des modules. Essayer de créer des modules simples en vous aidant de l'api, faites des erreurs (beaucoup) pour vous améliorer et ne laissez pas tomber si vous n'arrivez pas à résoudre un problème, demandez de l'aide sur ce topic ou celui-là. Si vous voyez des erreurs ou si certains points ne sont pas clairs, signalez-le ;) (ça compte aussi pour les erreurs d'orthographe) Sommaire
Avant de commencer Liens utiles
Environnement de travail La fenêtre de Transformice pour lancer un module (/lua) n'est pas pratique pour coder, c'est à peut-près aussi utile qu'un bloc, il vaut donc mieux utiliser des éditeurs de textes tels que Kobra pour coder à plusieurs ou Notepad++. Voyez par exemple le même script affiché sur Notepad++, Sublime Text et Transformice. C'est normal si vous ne comprenez pas ce qui est écrit, regardez juste celui sur lequel vous voudriez travailler.
Notepad++ Notepad++ est un éditeur de texte / de code source qui prends en charge le langage Lua et beaucoup d'autres ( C, C++, PHP, HTML, Java, etc). Il est fiable, utilise peu de ressources et sans danger. Site officiel Notepad++ V6.6.8 - téléchargement direct Une fois un nouveau fichier créé, allez dans l'onglet Langage > L puis sélectionnez Lua pour activer la coloration des mots clés. Les mots clés propres au langage lua seront ainsi automatiquement coloré d'une couleur différente du reste de texte pour rendre votre code plus simple à lire.
Lancer un module Pour lancer un module en maison de tribu,
Essayez de lancer ce module dans votre maison de tribu, une fenêtre avec écrit "Le module a été lancé avec succès" doit apparaitre. Les commentaires Les commentaires sont des morceaux de code que le jeu ne lit pas, ils sont généralement utilisés pour expliquer ce que fait le code ou pour mettre une portion de code qui ne fonctionne pas entre parenthèses sans avoir à l'effacer. Vous pouvez écrire ce que vous voulez dans un commentaire, ça il ne modifie en rien l'exécution du module. Pour indiquer qu'un morceau de code est un commentaire vous pouvez le mettre après deux tirets -- pour un commentaire sur une ligne ou entre --[[ et ]] pour un commentaire sur plusieurs lignes. Exemple de commentaire a dit : Les variables Qu'est-ce qu'une variable ? Une variable est un emplacement dans la mémoire de votre module, elle permet de sauvegarder des informations afin de ne pas les perdre et pour les réutiliser plus tard. Vous pouvez mettre toutes sortes d'informations dans une variable : - des nombres (number) - des mots ou des phrases (string) - des "booléens" qui sont en fait les valeurs vrai et faux (boolean) - des fonctions (function) - des listes qui permettent de contenir d'autres variables (table) - nil qui représente en fait l'absence de valeur (nil) Déclarer une variable Vous pouvez déclarer une nouvelle variable à n'importe quel moment de votre programme. Une variable se déclare de la façon suivante : nom_de_la_variable = valeur Par exemple : nombre = 5 -- On met la valeur 5 dans la variable nombre chaine = "Ceci est une phrase." -- On met la chaine de caractères "Ceci est une phrase" dans la variable chaine vrai = true -- On met la valeur true dans la variable vrai faux = false -- On met la valeur false dans la variable faux uneListe = {1, 2, 3, 4, 5} -- On met les valeurs 1, 2, 3, 4 et 5 dans la liste uneListe vide = nil -- On dis que la variable vide ne contient rien Il est possible de mettre la valeur d'une variable dans une autre variable comme ceci : nombre1 = 5 nombre2 = nombre1 -- On met la valeur de nombre1 dans la variable nombre2 -- Ansi nombre2 a la valeur 5 et je peux modifier nombre1 sans changer la valeur de nombre2. nombre1 = 5 -- On met le chiffre 5 dans la variable nombre1 nombre2 = nombre1 -- nombre2 prend la valeur de nombre1 (5) et nombre1 vaut toujours 5 nombre1 = 7 -- nombre1 vaut 7 et nombre2 vaut encore 5 On peut aussi déclarer plusieurs variables à la fois de cette manière : unMot, unNombre = "Peluche", 7 -- On met le mot "Peluche" dans la variable unMot et le nombre 7 dans -- la variable unNombre -- Les virgules sont indispensables Nommer ses variables. Un nom de variable ne peut être composé que de lettres minuscules ou majuscules sans accent, des chiffres et du caractère _ , il doit obligatoirement commencer par une lettre. Important : Le lua est un langage sensible à la casse, c'est à dire qu'il fait la différence entre les lettre majuscules et les lettres minuscules, ainsi les noms vAriaBle et VAriabLe ne représentent pas la même variable. Certains mots ont une signification spéciale en lua et vous ne pouvez donc pas les utiliser comme nom de variable, En voici la liste : and break do else elseif end false for if in local nil not repeat then return true or until while function Conventions Pour faciliter la lecture d'un script, il est indispensable de nommer intelligemment ses variables. Le nom d'une variable doit décrire son utilité. Par exemple une variable qui doit contenir le pseudo d'un joueur devrait s'appeler pseudo (pseudo = "Podoko") tandis qu'une variable devant contenir un score devrait s'appeler score (score = 117) Si plusieurs mots sont nécessaires pour décrire une variable, la plupart des codeurs mettent une majuscule au début de chaque mot sauf le premier. Par exemple une variable devant contenir le meilleur score d'une partie devrait s'appeler meilleurScore Les opérateurs Les opérateurs arithmétiques Les opérateurs de arithmétiques permettent de faire des opérations telles que la somme, la soustraction, la multiplication. Voici comment les utiliser. n1, n2 = 6, 3 n3 = n1 + n2 -- + La somme, on met le résultat de 6+3 dans la variable n3 n4 = n2 - n1 -- - La soustraction n5 = n1 * n2 -- * La multiplication n6 = n1 / n2 -- / La division n7 = n1 ^ n2 -- ^ La puissance ( équivalent à n7 = 6 * 6 * 6 ) n8 = n1 % n2 -- % Le modulo, renvoie le reste de la division euclidienne de n1 par n2 (0 en l'occurrence) On peut aussi bien mettre des nombres que des variables dans l'expression de droite : n8 = n1 + 7 -- Cette expression est parfaitement valable. De la même façon, la variable dans laquelle vous voulez mettre votre résultat peut apparaitre dans l'expression de droite : n9 = 8 n9 = n9 + 5 -- Cette expression aussi est valable, elle est équivalente à n9 = 8 + 5 ou -- à "j'ajoute 5 à la valeur actuelle de n9" Vous ne pouvez utiliser ces opérateurs que sur des nombre, en effet ça n'aurait aucun sens d'écrire res = "Peluche" - "Ratatouille" Opérateurs de comparaison (ou opérateurs booléens) Ces opérateurs servent à vérifier des égalités et renvoient un booléen (true ou false) Voici comment les utiliser : n1, n2 = 5, 13 test1 = n1 == n2 -- == équivaut à est-ce que n1 est égal à n2 ? Le résultat est false et va dans test1 test2 = n1 ~= n2 -- ~= équivaut à est-ce que n1 est différent de n2 ? Le résultat est true et va dans test2 test3 = n1 < n2 -- < équivaut à est-ce que n1 est plus petit que n2 ? test4 = n1 > n2 -- < équivaut à est-ce que n1 est plus grand que n2 ? test5 = n1 <= 5 -- <= équivaut à est-ce que n1 est plus petit ou égal à 5 ? test6 = ni >= 6 -- >= équivaut à est-ce que n1 est plus grand ou égal à 6 ? Note : les opérateurs == et ~= fonctionnent aussi sur les autres types de variables tels que les string et les boolean. Les opérateurs logiques Les opérateurs logiques permettent de vérifier plusieurs propositions à la fois, on en compte trois : not, or, and L'opérateur or renvoie le premier argument s'il est différent de false ou de nil, sinon il renvoie le second argument. Il signifie "ou" en français. L'opérateur and renvoie le premier argument si sa valeur est false ou nil, sinon il renvoie le second argument. Il signifie "et" en français. L'opérateur not renvoie false si son argument est différent de nil ou de false et renvoie true sinon. C'est l'opérateur qui renvoie le contraire de son argument Quelques exemples avec les résultats -- or test1 = true or false -- true test2 = false or true -- true test3 = false or false -- false test4 = false or nil -- nil test5 = nil or 5 -- 5 test6 = "Peluche" or "Ratatouille" -- "Peluche" -- and test1 = true and false -- false test2 = false and true -- false test3 = true and nil -- nil test4 = 5 and true -- true test5 = nil and false -- nil test6 = "Peluche" and "Ratatouille" -- "Ratatouille" -- not test1 = not true -- false test2 = not false -- true test3 = not nil -- true test4 = not 5 -- false test5 = not "Peluche" -- false Autres opérateurs L'opérateur # permet de connaitre le nombre d'élément que contient un tableau ou une chaine de caractères, il renvoie toujours un nombre positif. monTableau = {5, 9, "chaine", true} tailleTableau = #monTableau -- tailleTableau vaut maintenant 4 comme il y a 4 éléments dans monTableau maChaine = "Je suis une peluche" tailleChaine = #maChaine -- tailleChaine vaut maintenant 19 comme il y a 19 caractères dans maChaine -- l'opérateur # compte tous les caractères, même les espaces L'opérateur .. (deux points à la suite) permet de créer une chaine de caractères à partir de deux autres, c'est ce qu'on appelle la concaténation. phraseDebut = "Bonjour, je suis " phraseFin = "une peluche" phrase = phraseDebut .. phraseFin -- phrase contient maintenant la chaine "Bonjour, je suis une peluche" Ordre de priorité Si vous faites des expressions un peu compliquées qui mélangent plusieurs opérateurs, les opérateurs prioritaires s'exécuteront avant ceux de priorité inférieure. Voici la liste des opérateurs par ordre décroissant de priorité : ^ not # - (pour dire -5 ou -13) * / % + - .. < > <= >= == ~= and or Vous pouvez modifier l'ordre dans lequel se font les opérations avec des parenthèses () comme en mathématiques Ainsi : 5 * 6 + 15 / 3 est équivalent à ( 5 * 6 ) + ( 15 / 3 ) 13 + 15 / 5 < 7 est équivalent à ( 13 + ( 15 / 5 )) < 7 false and 5 or true est équivalent à ( false and 5 ) or true Les structures de contrôle La condition : if La structure de contrôle if permet de n’exécuter un bloc d'instructions que si une certaine condition est vérifiée. La condition est considérée comme vérifiée si son résultat est différent de nil ou de false. Voici comment se construit une boucle if : Structure if a dit : si la condition n'est pas vérifiée vous pouvez faire une nouveau test pour exécuter d'autres instructions : if condition then instructions elseif condition2 then instructions2 elseif condition3 then instructions3 end Vous pouvez mettre autant de elseif que vous voulez à la suite, si une des conditions est vérifiée, le programme ne testera pas les conditions restantes (concrètement, si la condition 2 est vérifiée, les conditions 3, 4, etc ne seront pas testées) Vous pouvez rajouter un else pour le cas où aucune des conditions n'a été validée : if condition then instructions else autresInstruction end Le cas else se place toujours en dernière position dans une boucle if. nb1 = 5 nb2 = 9 if nb1 == nb2 then -- Cette condition est fausse nb3 = nb1 -- Cette ligne ne s’exécute pas elseif nb1 < nb2 then -- Cette condition est vraie nb3 = 8 -- Cette ligne s'exécute elseif nb1 == 5 then -- Cette condition est vraie mais une des conditions précédentes l'était déjà nb3 = 10 -- Cette ligne ne s'exécute pas else -- Une des conditions plus haut était vraie nb3 = nb2 -- donc cette ligne ne s'exécute pas end -- À la fin du programme, nb3 vaut 8 Note : if nb1 == nb2 then bool1 = true elseif nb1 < nb2 then bool1 = false end -- est équivalent à if nb1 == nb2 then bool1 = true else if nb1 < nb2 then bool1 = false end end la boucle while La structure de contrôle while permet de répéter la même série d'instructions tant qu'une condition est vérifiée. De même que pour le if, la condition est considérée comme vérifiée si son résultat est différent de false ou de nil. Voici comment se construit une boucle while : Structure while a dit : On peut le traduire par "Tant que ... tu fais ..." Par exemple : nb1 = 0 while nb1 < 6 do -- Tant que nb1 est inférieur à 6 nb1 = nb1 + 1 -- On ajoute 1 à nb1 end -- À la fin de l'exécution, nb1 vaut 6 Important : Il faut faire attention avec ce genre de structure pour éviter qu'elles ne tournent à l'infini, sinon votre module plante forcement. par exemple : nb1 = 1 while nb1 ~= 0 do nb1 = nb1 + 1 end Comme nb1 ne sera jamais égal à 0, votre module ne cessera pas d'ajouter 1 et plantera. La boucle repeat La structure de contrôle repeat est similaire au while, elle permet de répéter une suite d'instructions tant qu'une condition n'est pas vérifiée. Comme pour if et while, la condition est considérée comme vérifiée si son résultat est différent de false ou de nil. Voici comment se forme une boucle repeat : Structure repeat a dit : On peut le traduire par : "Fais ... jusqu'à ce que ..." Par exemple : nb1 = 0 repeat nb1 = nb1 + 1 -- Ajoute 1 à nb1 until nb1 == 5 -- Jusqu'à ce que nb1 vaille 5 Important : Comme la condition est énoncée à la fin de la boucle, les instructions s'exécutent toujours au moins une fois. Important² : Comme pour la boucle while, il faut faire attention à ce que la condition de la boucle repeat se vérifie bien à un moment sinon votre module plantera. La boucle for (numérique) Le for numérique permet d'exécuter une suite d'instructions un nombre prédéfini de fois. Voici comment se forme une boucle for : Structure for numerique a dit : Avec n1, n2, n3 qui sont des nombres. (ou des variables contenant des nombres, c'est la même chose) nb est un compteur qui commence à n1. n2 est la borne de fin, la boucle for se termine une fois que nb est égal à n2. n3 est le pas, après chaque exécution des instructions on ajoute n3 à nb C'est équivalent à "pour nb allant de n1 à n2 par pas de n3, faire ..." Par exemple : for i=0, 10, 2 do -- Pour i allant de 0 à 10 par pas de 2, tu dois instructions -- faire ce qui est écrit end par défaut n3 est égal à 1, donc for i=1, 10 do -- signifie : pour i allant de 1 à 10 par pas de 1 Important : Comme pour les boucle while et repeat, il faut faire attention à ce que la le compteur soit bien égal à la borne de fin à un moment, sinon votre module va planter. ("for i=1, 10, 2" fera planter votre module puisque i ne sera jamais égal à 10, il passera de 9 à 11) Important² : Vous ne pouvez pas modifier vous-même le compteur, la borne de fin ni le pas quand vous êtes dans la boucle for. Important³ : Il existe un autre type de boucle for : le for générique, c'est une notion trop compliquée à expliquer à ce point du tutoriel mais des exemples d'utilisations sont donnés dans les parties sur les manipulations de tables et les patterns. Les fonctions Qu'est-ce qu'une fonction ? Une fonction est un morceau de votre module qui contient une série d'instructions à exécuter lorsqu'elle est appelée. Elle peut appeler d'autres fonctions, modifier des variables,renvoyer un ou plusieurs résultats. Une fonction peut recevoir des paramètres à partir desquels elle travaille pour renvoyer un résultat ou modifier le jeu. Utiliser sa première fonction : print print est une fonction qui prend un paramètre de n'importe quel type (number, string, boolean, etc) et affiche son contenu dans le tchat de celui qui lance le module. Par exemple : print("Hello world!") -- affiche Hello world! dans le tchat print(true) -- affiche true dans le tchat print(var1) -- affiche le contenu de la variable var1 dans le tchat Créer des fonctions Pour déclarer une fonction, on commence toujours par le mot clé function suivit par le nom de la nouvelle fonction, puis par la liste des paramètres/arguments entre parenthèses. chaque paramètre étant séparé des autres par une virgule. On écrit ensuite les instruction de la fonction dans les lignes qui suivent et on ferme la fonction avec un end Comme ceci : function nomDeLaFonction ( param1, param2, param3 ) -- Une fonction qui prend trois arguments instructions end Si la fonction n'a pas besoin de paramètres, les parenthèses doivent quand même être mises : function nomDeLaFonction () -- Aucun argument instructions end Une fonction peut ou non renvoyer un ou plusieurs résultats grâce au mot clé return. Cette valeur retournée peut ensuite être sauvegardée dans une variable. Une fois le résultat renvoyé, la fonction se termine même si des instructions sont écrites après. En voici un exemple : function renvoi2 () -- Cette fonction ne demande pas de paramètre et renvoie 2 return 2 end nb = renvoi2() -- On met le résultat de renvoi2 dans la variable nb print( renvoi2() ) -- On affiche le résultat de renvoi2 dans le tchat Pour écrire une fonction qui fait la somme de deux nombres on peut écrire function somme( nb1, nb2 ) resultat = nb1 + nb2 return resultat end ou bien function somme (nb1, nb2) return nb1+nb2 end Par conséquent on peut directement renvoyer le résultat d'une expression plutôt que de passer par un résultat intermédiaire. Une seule fonction peut également renvoyer plusieurs résultats à la fois en les séparant par une virgule : function sommeProduit (nb1, nb2) som = nb1 + nb2 prod = nb1 * nb2 return som, prod -- on renvoie la somme et le produit des deux nombres reçus en argument end resSom, resPro = sommeProduit ( 2, 5 ) -- On met 7 dans resSom et 10 dans resPro resSom2 = sommeProduit ( 3, 7 ) -- On met la somme de 3 et 7 dans resSom2 et le produit n'est pas sauvegardé. On peut également appeler de nouvelles fonctions directement avec le résultat d'une autre. print ( somme(5, 7) ) -- On affiche le résultat de la somme de 5 et 7 print ( somme( sommeProduit(4,3) ) ) -- On affiche le résultat de la somme de la somme et du produit de 4 et 3 (donc (4+3) + (4*3)) Dernière modification le 1604046480000 |
Podoko « Citoyen » 1413725820000
| 11 | ||
Manipulation de tables Qu'est-ce qu'une table ? Les tables sont des variables particulières dans lesquelles ont peut mettre plusieurs variables, des nombres, des booléens, des chaines de caractères, d'autres tables. Si on voit les variables comme des tiroirs dans lesquelles on met des valeurs, alors on peut se représenter les tables comme de grandes armoires avec plusieurs tiroirs. On se sert la plupart du temps des tables pour ranger au même endroit des informations similaires comme par exemple la liste des joueurs d'un salon, une liste de records, etc. Une table se déclare de la façon suivante : Declaration table a dit : Accéder et modifier les élément d'une table Pour modifier un élément d'une table, il y a plusieurs solutions, la première est la suivante : nomDeMaTable[ nomDuTiroir ] = valeur Par exemple : maTable = {} -- Ne surtout pas oublier de déclarer la table, sinon le module plante maTable[1] = "val" -- On me la valeur "val" dans le premier tiroir de maTable maTable["case"] = 56 -- On met le nombre 56 dans le tiroir "case" de maTable maTable["1"] = true -- On met la valeur true dans le tiroir "1" de maTable (maTable[1] et maTable["1"] sont deux tiroirs différents) Vous pouvez ensuite utiliser les variables du tableau comme n'importe quelle autre variable : print( maTable["case"] ) print( maTable[1] ) print( maTable["1"] ) -- Avec les deux dernières lignes vous pouvez confirmer que maTable[1] et maTable["1"] sont bien deux tiroirs différents Vous pouvez également mettre une table dans une autre : maTable = {} -- On déclare la table maTable[1] = {} -- Le premier tiroir de maTable contient une table maTable[1]["case"] = "coucou" -- On met la valeur "coucou" dans le "sous-tiroir" du premier tiroir de maTable On peut également modifier un élément d'une table de la façon suivante : nomDeMaTable.nomDuTiroir = valeur -- Un point entre le nom de la table et le nom du tiroir par exemple : maTable = {} maTable.case = "Peluche" -- Équivalent à maTable["case"] = "Peluche" maTable.sousTable = {} maTable.sousTable.sousTiroir = "Ratatouille" -- Équivalent à maTable["sousTable"]["sousTiroir"] = "Ratatouille -- Équivalent à maTable["sousTable"].sousTiroir = "Ratatouille -- Équivalent à maTable.sousTable["sousTiroir"] = "Ratatouille Les avantages de la première méthode sur la deuxième sont les suivants : On ne peut pas accéder aux tiroirs numérotés avec la deuxième méthode. maTable = {} maTable.1 = "valeur" -- Cette ligne fera planter le module, le nom de "tiroir" doit respecter les même règles que celui d'une -- variable comme commencer par une lettre On peut mémoriser le nom d'un tiroir avec la première méthode maTable = {} adresse = "case" maTable[adresse] = "Peluche" -- On met "Peluche" dans le tiroir "case" de maTable Une troisième méthode permet d'ajouter les éléments au tableau dès sa déclaration : maTable = { "Peluche", 56, true, "Ratatouille" } --[[ Cette ligne est équivalente à maTable = {} maTable[1] = "Peluche" -- Notez que le compte commence à 1 et pas à 0 comme dans d'autres langages, c'est important maTable[2] = 56 maTable[3] = true maTable[4] = "Ratatouille" ]] On peut aussi faire comme ceci : maTable = { case="coucou", autre = "Peluche" } --[[ C'est équivalent à maTable = {} maTable.case = "coucou" maTable.autre = "Peluche" ]] La dernière solution est d'utiliser une fonction : table.insert Note : Si vous suivez un peut vous remarquez que cette fonction est dans une table. On peut donc bien mettre une fonction dans une table. Cette fonction, comme son nom l'indique insère un élément dans une table à la suite des autres éléments. Elle prend deux arguments : le nom de la table et l'élément à insérer. par exemple : maTable = { "test", 56, true, "Peluche" } table.insert (maTable, "Ratatouille") -- On rajoute "Ratatouille à la fin de la table -- À la fin, maTable[5] vaut "Ratatouille" Vous pouvez également indiquer à quel numéro vous voulez insérer l'élément, dans ce cas l'élément au numéro indiqué et tous les suivants seront déplacés vers la case d'après : table.insert (nomDeLaTable, numero, valeur) par exemple : maTable = { "test", 56, true, "Peluche" } table.insert ( maTable, 3, "Ratatouille" ) --[[ Revient à faire maTable[5] = maTable[4] maTable[4] = maTable[3] maTable[3] = "Ratatouille" ]] La fonction inverse à table.insert est table.remove qui retire un élément à une table : table.remove (nomDeLaTable, numero) maTable = { "test", 56, "Peluche", "Ratatouille" } table.remove (maTable, 2) --[[ Revient à faire maTable[2] = maTable[3] maTable[3] = maTable[4] maTable[4] = nil ]] Choses à savoir sur les tables L'opérateur # Cet opérateur, comme c'est indiqué au début du tutoriel, sert à connaitre la taille d'une table ou d'un string. C'est en réalité un peu différent, il regarde le premier élément de la table, puis le second, le troisième, ... jusqu'à tomber sur un élément qui vaille nil pour trouver la taille du tableau, par conséquent il ne compte pas les éléments qui n'ont pas de numéro. Un exemple vaut mieux que des explications vagues : maTable = { "test", 56, "Peluche" } print(#maTable) -- Affichera 3 maTable["test"] = "Ratatouille" print(#maTable) -- Affichera encore 3 maTable[4] = "Souris" print(#maTable) -- Affichera 4 maTable[6] = "Fromage" print(#maTable) -- Affichera toujours 4 maTable[5] = "Chamane" print(#maTable) -- Affichera 6 Copie de table Le tutoriel dit au début qu'on peut copier la valeur d'une variable dans une autre variable avec le symbole = et qu'on peut ensuite manipuler chacune des variables sans affecter l'autre nb1 = 5 nb2 = nb1 -- On copie nb1 et on le met dans nb2 nb1 = 3 -- On modifie la valeur de nb1 mais nb2 ne change pas print(nb1) print(nb2) Avec les tables, ce n'est pas vrai. Par exemple : tab1 = { "test", 56, true, "Peluche" } tab2 = tab1 -- On copie tab1 dans tab2 tab1[2] = "Ratatouille" -- On change la valeur de tab1[2] print(tab2[2]) -- On devrait afficher 56 mais pourtant c'est "Ratatouille" qui s'affiche. Donc les deux noms de variables permettent de manipuler la même table. Si vous voulez vraiment copier la table et ses éléments dans une nouvelle variable vous devez créer une fonction pour ça. (pas donnée dans ce tutoriel car peut vite manger des ressources pour les grandes tables et parce que c'est un bon entrainement à chercher) Note : Si vous savez ce qu'est un pointeur, en réalité ce n'est pas le tableau lui-même que contient la variable mais le pointeur vers ce tableau. On copie donc le pointeur et pas le tableau, c'est de là que vient ce "problème". Parcourir tous les éléments d'une table Il arrive souvent d'avoir besoin d'exécuter les mêmes instructions sur tous les éléments d'une table, pour cela on utilise la boucle for générique de la façon suivante : tab = { "test", "Peluche", "Ratatouille" } tab.fromage = "Souris" for key, val in ipairs(tab) do instructions end ou bien : for key, val in pairs(tab) do instructions end --[[ key est "le nom du tiroir" dans la table et val sa valeur La différence entre les fonctions pairs et ipairs est que pairs permet de parcourir vraiment tous les éléments de la table qui sont différents de nil comme tab.fromage alors que ipairs ne parcourt que les éléments de 1 à #tab (donc tab[1], tab[2], etc jusqu'à ce que la valeur soit nil) ]] Note : si la valeur ne vous intéresse pas, vous pouvez très bien écrire "for key in pairs(tab)" ou for "key in ipairs(tab)", ça ne pose pas de problème. Fonctions sur les strings Rappels Les strings sont des variables qui contiennent des chaines de caractères, c'est à dire des mots, des phrases, tu texte, etc. Il existe plusieurs façons de déclarer un nouveau string : str1 = "Texte" -- entre " et " str2 = 'Texte' -- entre ' et ' str3 = [[Texte]] -- entre [[ et ]] Avec l'opérateur # vous pouvez connaitre le nombre de caractères que contient une variable : str1 = "Je suis une peluche" print(#str1) -- Affiche la longueur de la chaine : 19 Vous pouvez réunir deux chaines de caractères en une seule grâce à l'opérateur .. str1 = "Bonjour, " str2 = "je suis une peluche" str3 = str1..str2.. " et j'aime la ratatouille." print(str3) -- "Bonjour, je suis une peluche et j'aime la ratatouille." Enfin, vous pouvez comparer deux chaines de caractères avec les opérateurs <, >, <= et >= Ceci peut permettre par exemple de ranger des mots par ordre alphabétique : "Peluche" < "Ratatouille" -- true puisque P vient avant R dans l'alphabet. Prendre un morceau d'un string (première version) Le langage lua possède beaucoup de fonctions pour manipuler les chaines de caractères. Il permet entre autres de récupérer un bout de cette chaine grâce à la fonction string.sub Cette fonction prend trois arguments : la chaine de caractères, l'emplacement de la première lettre à récupérer et l'emplacement de la dernière lettre à récupérer. Si le troisième argument n'est pas donné (la dernière lettre à prendre), alors la fonction renvoie la fin de la chaine. str = "Je suis une peluche" str1 = string.sub(str, 1, 7) -- "Je suis" str2 = string.sub(str, 13) -- "peluche" str3 = string.sub("Ratatouille", 1, 3) -- "Rat" Il est aussi possible d'appeler cette fonction en mettant le nom de la variable contenant le string suivit de :sub(debut, fin) Par exemple : str = "Je suis une peluche" str1 = str:sub(13, 19) -- "peluche" (équivalent à string.sub(str, 13, 19)) Cette fonction string.sub est très utile pour créer des commandes qui prennent des paramètres grâce à la fonction eventChatCommand Voici par exemple une fonction qui permet de donner le fromage à un joueur grâce à la commande "!cheese nom_du_joueur" : function eventChatCommand(name, command) if command:sub(1,6) == "cheese" then -- Si les 6 premières lettres forment "cheese" alors tfm.exec.giveCheese( command:sub(8) ) -- on donne le fromage au joueur dont le nom est donné end end Avancé : Les patterns Prendre un morceau d'un string (seconde version) Il peut parfois arriver d'avoir besoin de traiter de façon plus complexe une chaine de caractères, ça peut être le cas si vous voulez créer une commande dans le tchat qui demande de donner deux informations ou plus. Par exemple une commande "!addPoint [name] [nbPoints]" qui servirait à donner un certain nombre de points ("[nbPoints]") à un joueur ("[name]") au score d'un joueur. Par exemple : "!addPoints Peluche 15" donnerait 15 points au joueur Peluche. On ne peut pas créer ce genre de fonction si l'on a que string.sub à disposition puisque le nom du joueur peut être plus long que ce qu'on a initialement prévu. Une méthode utile est donc de récupérer tous les mots dans une chaine de caractère avant de faire ses test. Voici le code qui permet de mettre tous les mots d'une chaine de caractères dans un tableau : local monString = "Je suis une peluche avec une moustache !" -- On crée notre chaine de caractères à analyser local listeMots = {} -- On crée la table qui va contenir la liste des mots for word in string.gmatch ( monString, '%S+' ) do -- Pour chaque mot dans monString... table.insert ( listeMots, word ) -- Ajouter le mot à la liste des mots déjà trouvés. end Vous pouvez ensuite afficher tous les éléments de la table pour voir le résultat. for _, word in ipairs(listMots) do print(word) end --[[ Résultat : Je suis une peluche avec une moustache ! ]] Avec cette méthode il est très simple de créer la commande !addPoint : function eventChatCommand(name, command) local listeMots = {} for word in command:gmatch( '%S+' ) do -- On liste les mots de la commande table.insert(listeMots, word) end if listeMots[1] == 'addPoint' then -- Si le premier mot de la commande est 'addPoint' alors tfm.exec.setPlayerScore(listeMots[2], listeMots[3], true) -- On ajoute listeMots[3] (le nombre de points) à listeMots[2] (le nom du joueur) end end Regardons de plus près la ligne suivante : for word in string.gmatch( monString, '%S+' ) do et plus précisément '%S+' , sans en avoir l'air, cette simple chaine de caractères a énormément de sens. C'est un pattern qui représente "une suite de caractères différents d'un espace la plus longue possible" Par exemple, dans "Je suis une peluche !", "Je" correspond à ce pattern, "une" aussi. Même "!" y correspond puisque ce n'est pas un espace Attention, "pelu" ne correspond pas puisque le caractère suivant dans la chaine n'est pas un espace, "peluche" quand à lui, correspond. "%S" représente une classe de caractères : tous les caractères différents d'un espace (" ") le "+" est un opérateur de répétition, en étant lié au "%S" il permet d'indiquer qu'on cherche une suite de caractères aussi longue que possible, c'est donc lui qui fait que "pelu" ne correspond pas au pattern "%S+" mais que "peluche" oui. Les classes de caractères. Il existe plusieurs classes de caractères comme %S qui servent chacune à trouver des caractères différents : Les principaux
D'autres classes
Important : remplacer le caractère représentant une classe par sa majuscule représente le contraire de cette classe. Par exemple %S représente tous les caractères sauf les espaces, %D représente tous les caractères sauf 0 1 2 3 4 5 6 7 8 9. Créer sa classe de caratères Grâce aux crochets [] vous pouvez définir vos propres classes de caractères, il suffit de lister les caractères entre les crochets comme ceci : [abcdef] -- Représente les caractères a b c d e et f minuscules Si vous cherchez toutes les lettres correspondant à cette nouvelle classe vous aurez une chose comme ceci : str = "J'ai caliné une peluche" for car in str:gmatch('[abcdef]') do print(car) end -- Vous obtiendrez a c a e e c e -- NB : le é n'a pas été affiché, c'est normal puisque e et é sont des caractères différents -- si vous voulez avoir le é, votre classe de caractères doit être [abcdefé] Un raccourcis : plutôt que d'écrire [abcdef] il possible d'écrire [a-f] qui veut dire "tous les caractères de a jusqu'à f" Vous pouvez également inclure une des classes prédéfinies dans vos propres classes comme ceci : [a-fA-F%d] -- cette classe représente les lettres de a à f, de A à F et les caractères décimaux : 0 1 2 3 4 5 6 7 8 9 -- Elle est donc équivalente à la classe %x (les caractères hexadécimaux) Les modificateurs Les modificateurs permettent de récupérer plusieurs caractères à la fois plutôt qu'un seul. Ils se mettent après une classe de caractères pour récupérer plusieurs lettres correspondantes à cette classe à la fois. Il existe quatre modificateurs : + Permet de récupérer une série de un ou plusieurs caractères * Permet de récupérer une série de 0 ou plusieurs caractères - Pareil que pour *, mais récupère la chaine la plus courte posible ? Permet Permet de récupérer une ou zéro répétitions du caractère Quelques exemple : '%S+' signifie une chaine de un ou plusieurs caractères différents d'un espace, c'est à dire un mot phrase = "Je suis une peluche." for str in phrase:gmatch('%S+') do print(str) end -- "Je" "suis" "une" "peluche." ' .* ' signife une chaine de caractères correspondante à un espace suivit d'un ou plusieurs caractères puis d'un autre espace phrase = "Je suis une peluche." for str in phrase:gmatch(' .* ') do print(str) end -- " suis une " ' .- ' signife une chaine de caractères correspondante à un espace suivit d'un ou plusieurs caractères la plus courte possible puis d'un autre espace phrase = "Je suis une peluche." for str in phrase:gmatch(' .- ') do print(str) end -- " suis " '-?%d+' signifie un ou aucun caractère - suivit d'un ou plusieurs chiffres phrase = "négatif : -13 positif : 42" for str in phrase:gmatch('-?%d+') do print(str) end -- "-13" "42" Exercices : Essayez de créer les patterns permettant de trouver les chaines de caractères suivantes : un nombre à virgule (positif) %d+,%d+ -- Virgule obligatoire ( 42 n'est pas pris en compte) %d+,?[%d+]? -- Virgule facultative (42 est pris en compte) un nombre à virgule (positif ou négatif) -?%d+,%d+ -- Virgule obligatoire ( 42 n'est pas pris en compte) -?%d+,?[%d+]? -- Virgule facultative (42 est pris en compte) une date ( jj/mm/aaaa ) %d%d/%d%d/%d%d%d%d un mot %S+ un mot suivit d'une date ( blabla jj/mm/aaaa ) %S+ %d%d/%d%d/%d%d%d%d "pseudo : " suivit d'un nom pseudo : %S+ une série de caractères avec des 0 aux extrémités 0.-0 -- Ne peut pas contenir des 0 0.*0 -- Peut contenir des 0 Exemple de module Dans cet exemple nous allons créer un mini-jeu sans chamane dans lequel chaque joueur sera capable de lancer des esprits pour atteindre le fromage puis rentrer au trou. Nous allons devoir décider des règles et du fonctionnement du jeu puis le coder. Étape N°1 : Sortir un papier et un crayon Avant de commencer à coder il faut bien décider de ce que vous allez coder et ne pas foncer tête en bille sans savoir où vous allez, prenez le temps de réfléchir aux fonctions que vous allez devoir mettre en place, celles dont vous aurez besoin et celles Les joueurs ne pourront lancer d'esprit que toutes les secondes Il pourront choisir où l'esprit sera invoqué par rapport à eux dans un carré de 30*30 autour d'eux (offset) L'esprit se lancera en se baissant Il faudra désactiver le changement automatique de cartes pour mettre ses propres cartes. Par conséquent il faudra savoir quand changer de carte : temps à 0 ou plus de souris sur la carte. Nous avons donc besoin : D'une table personnalisée par joueur pour sauvegarder l'offset et le moment où il a lancé un esprit pour la dernière fois D'une table où sauvegarder la liste des cartes D'activer l'écoute pour les touches bas et S (pour lancer l'esprit) De désactiver le changement automatique de carte De désactiver la sélection automatique d'une chamane De la fonction eventLoop pour savoir si la carte doit être changée Des fonction eventPlayerWon et eventPlayerDied pour activer la fonction précédente De la fonction eventKeyboard pour permettre aux joueurs de lancer des esprits D'une fonction pour compter le nombre de joueurs restant quand un joueur rentre ou meurt De la fonction os.time() pour obtenir l'heure à laquelle un joueur essaie de lancer un esprit Étape N°2 : Rotation de cartes Comme nous créons un mini-jeu sur plusieurs cartes, il faut s'occuper de savoir quand passer à la suivante et quelle carte passer. Commençons par désactiver le changement automatique de carte, la fonction pour le faire est tfm.exec.disableAutoNewGame et prend un argument booléen pour savoir s'il faut activer ou désactiver le changement de carte. a dit : Comme il s'agit d'un fonction qu'on va utiliser uniquement au lancement du module, on peut y mettre dans une fonction qu'on appellera lors du lancement du module et qui servira à faire toutes les actions du début de jeu : a dit : Il nous faut également une liste des cartes que jouera le module, on peut la mettre dans un tableau qu'on appelle mapList a dit : Maintenant qu'on a une liste de cartes et qu'on sait que le jeu ne va pas changer de carte tout seul, on peut décider de quand charger une nouvelle carte. De toutes évidence c'est quand il n'y a plus aucun joueur ou quand le temps est arrivé à zéro. Commençons par gérer le cas où tous les joueurs sont rentrés ou morts : On va compter le nombre de joueurs vivants chaque fois qu'un joueur meurt ou rentre avec le fromage. Il va nous falloir une nouvelle fonction pour ça : a dit : Une fois qu'on a cette fonction on peut l'appeler quand un joueur meurt ou rentre dans le trou. Deux fonctions se déclenchent lorsqu'un joueur meurt ou rentre : eventPlayerWon pour une souris qui rentre et eventPlayerDied pour une qui meurt. a dit : Nous devons également changer la carte lorsque le temps restant tombe à zéro. On peut voir le temps restant avec la fonction eventLoop(tempsPasse, tempsRestant) qui se déclenche automatiquement toutes les demie-secondes a dit : Désormais notre code doit ressembler à ceci : a dit : Vous pouvez déjà lancer ce code en maison de tribu pour vérifier qu'il fonctionne, vous verrez que la carte change toute seule, c'est un code utilisé dans beaucoup de modules qui utilise une rotation de cartes donc vous pouvez vous en resservir pour d'autres mini-jeux. Étape N°3 : Lancer les esprits Maintenant que nous pouvons changer les cartes automatiquement on peut s'occuper de permettre aux joueurs de lancer des esprits :) Les joueurs pourront lancer les esprits en se baissant, il faut donc que l'on soit au courant quand un joueur appuie sur les touches pour se baisser : On active l'écoute d'une touche avec la fonction tfm.exec.bindKeyboard a dit : Comme la boucle for de ce code est utilisée uniquement au lancement du module, on peut y rajouter à la fonction main() a dit : Dans le "cahier des charges" du jeu, on a dit que le joueur devait pouvoir choisir l'offset de son esprit, il faut donc une table où sauvegarder ces offset et les initialiser en même temps qu'on active l'écoute des touches du clavier : a dit : Maintenant qu'on a activé l'écoute des touches, on peut attaquer la mise de l'esprit lorsqu'un joueur se baisse. Lorsqu'un joueur appuie sur une touche don on a activé l'écoute il active la fonction eventKeyboard, c'est dans celle-ci qu'on va travailler désormais. Lorsque la fonction eventKeyboard est activé on doit placer un esprit en fonction de son offset, mais seulement s'il est vivant et si la touche qu'il active est bien la flèche du bas ou S : a dit : Si vous êtes à l'aise avec les expressions booléennes, vous pouvez réunir les deux boucles if en une seule : a dit : Il nous manque une dernière chose pour terminer l'étape des esprits. Si vous essayez de lancer le module tel qu'il est pour le moment vous allez vite vous rendre compte que vous n'avez pas besoin d'attendre une seconde pour lancer plusieurs esprits, c'est quelque chose à corriger. Premièrement on va créer une nouvelle table qui servira à sauvegarder le dernier moment où un joueur a lancé un esprit, puis initialiser cette table pour chaque joueur grâce aux fonctions main et eventNewPlayer : a dit : On peut maintenant ajouter une condition au lancement d'un esprit dans la fonction eventKeyboard : le dernier esprit qu'a lancé le joueur doit dater d'au moins une seconde. a dit : Le code du module est maintenant : a dit : Vous pouvez déjà utiliser ce code, il contient la majorité des fonctionnalités qu'on voulait. Il ne manque plus que la possibilité pour le joueur de changer l'offset de leur esprit. Étape N°4 : modification de l'offset Il y a plusieurs moyen pour qu'un joueur modifie sont offset, le plus simple est de passer pas une commande du tchat grace à la fonction eventChatCommand qui s'active lorsqu'un joueur tape un message qui commence par '!' comme !Peluche ou !coucou la commande devrait être "!offset x y" avec x et y les coordonnées de l'offset (!offset -5 10 par exemple) Pour pouvoir reconnaitre la commande on va utiliser la fonction string.gmatch(texte, pattern), je vous invite à lire le chapitre sur les strings pour comprendre ce qu'on va faire. a dit : Si vous avez eu du mal avec cette ligne : offsets[name] = { x = a and math.abs(a)<30 and a or offsets[name].x, y = b and math.abs(b)<30 and b or offsets[name].y } c'est normal, elle fait beaucoup de choses à la fois et il faut la lire attentivement pour bien comprendre ce qu'elle fait. x = a and math.abs(a)<30 and a or offsets[name].x Cette petite ligne est l'équivalent de : a dit : De même pour l'expression "y = b and math.abs(b)<30 and b or offsets[name].y" Avec ces expressions réduites, on exploite efficacement les opérateurs and et or Voila, il ne reste plus qu'à ajouter cette fonction la suite du code pour que le module soit terminé a dit : Dernière modification le 1605371760000 |
Elyolucas « Consul » 1414938900000
| 1 | ||
Pour le moment, je suis un peu trop débutant en LUA, je me consacrerais au Module plus tard. En tout cas ça à l'air d'être compliqué et très long à apprendre, j'espère y arriver un jour ! ^^ Un topic très bien présenter tout de même, je n'est pas eu le courage de tout lire, mais un ptit peu quand même, j'espère que ce sera utile pour les autres personnes. ^^ |
1 | ||
Bof Notepad++.. Autant faire télécharger Sublime Text, il est plus joli et on s'y repère beaucoup mieux dans un long code.. Sinon gg le topic Dernière modification le 1415036280000 |
Ausecourr « Citoyen » 1415045700000
| 0 | ||
Bien joué le topic! Si tu as le temps d'expliquer un peu comment tu fais pour faire une interface graphique comme pour ton snake ça m'intéresserait beaucoup :) |
0 | ||
Bravo pour ce sujet ! |
Elyolucas « Consul » 1415133840000
| 0 | ||
C'est dommage qu'il ne soit pas plus actif, il aurait peut-être plus être épinglé, qui sais. |
0 | ||
Bravo ! J'demande a ce qui soit épingle hein ! |
0 | ||
Bathchaboom a dit : Voeu exaucé :) Bravo Podoko pour ce très bon travail ! Dernière modification le 1415182560000 |
0 | ||
Ouiii ! |
Elyolucas « Consul » 1415188860000
| 0 | ||
EPINGLER EPINGLER ! |
Podoko « Citoyen » 1415262780000
| 0 | ||
Owi un topic épinglé ! Merci à tous \o/ Pour le choix Notepad++/Sublime_Text, les deux se valent à mes yeux mais j'ai l'habitude de travailler sur Notepad++ et il est facile à mettre en français. (en soit prendre l'un ou l'autre fait de grande différence) Pour le Snake, je verrai si j'ai le temps d'écrire comment il est fait, c'est juste une série de textArea bien placés avec un fond transparent. ^^' |
Redstarz « Censeur » 1415292660000
| 0 | ||
Dans la catégorie "Opérateurs", il y a une petite faute à "nombre que tu as écrit sans -s (juste avant les Opérateurs de comparaison ) Je suis en train de lire, ça m'intéresse vraiment et tu explique super bien :D |
Linkaito « Consul » 1415305380000
| 1 | ||
Oh j'avais pas vu le topic, bravo ! Il me servira certainement \o/ |
0 | ||
podoko a dit : Il y a un plugin LUA Transformice pour sublime text qui permet de coder plus vite et de ne pas tout apprendre par coeur. Pourquoi mettre Sublime text en français ? C'est inutile ! Sachant que sur sublime on s'y retrouve beaucoup mieux :s |
Mcfloy « Citoyen » 1415390880000
| 0 | ||
Un beau tutoriel, félicitations pour le travail fourni. Simple et complet, c'est exactement ce genre de topic qu'il manquait. :-) |
Elyolucas « Consul » 1415392140000
| 0 | ||
mcfloy a dit : Totalement d'accord, cependant, malgré qu'il soit bien expliquer, le Lua reste assez compliqué pour les vraiment débutants. Il faudrait peut-être des personnes attitrées pour apprendre le lua au personnes postulants, je sais pas trop. :') |
Nicolasledu « Citoyen » 1415450280000
| 0 | ||
elyolucas a dit : Le lua est quand même un des langages les plus faciles :/ |
Elyolucas « Consul » 1415465460000
| 0 | ||
C'est pour le comprendre que j'ai du mal. Toutes les directives à employer (Du moins, je l'appel comme ça) sont assez longues et compliquées quand on a personne pour nous aidés, c'est pourquoi, même avec ce topic, cela reste compliqué dans aide d'une personne en jeu, ou extérieur. |
0 | ||
Elyolucas, je peux t'aider si tu le souhaites. @Nicolasledu Non, c'est loin d'être le plus facile, c'est le HTML qui est a porté de tous. |