Ce cours va vous apprendre à écrire des scripts simples pour Planet.
Dans chaque objet 3D, vous pouvez ajouter des scripts qui s'exécutent et rendent l'objet vivant.
Pour créer un script :
// mon premier script event start () { say ("Salut les amis !"); say ("Comment allez-vous ?"); }
Cliquez sur le bouton "Appliquer" : le script se compile puis s'exécute alors et affiche sur la fenêtre Conversation :
Salut les amis ! Comment allez-vous ?
Voilà, vous avez écrit votre premier script !
Regardons maintenant ce premier programme en détails.
// mon premier script
La première ligne commence par le signe // qui indique un commentaire. Elle est donc ignorée.
event start ()
La deuxième ligne est un déclencheur.
Event signifie evènement, donc si quelque chose se passe, le script se réveille et il exécute les lignes entre accolades. L'évènement start se déclenche automatiquement lorsque le script démarre.
{ say ("Salut les amis !"); say ("Comment allez-vous ?"); }
Les accolades { } entourent une séquence d'instructions à exécuter. l'instruction say() sert à afficher un texte sur le chat. Chaque instruction se termine obligatoirement par un point-virgule (;)
say est en fait une fonction. Pour l'exécuter, on donne simplement son nom (ici say) et on donne d'éventuels arguments entre parenthèses (ici "Salut les amis !"). S'il n'y a pas d'arguments, on ajoute simplement une paire de parenthèses vides ().
Durant la compilation du script, celui-ci est entièrement vérifié et contrôlé, ce qui peut faire apparaitre des erreurs de syntaxe.
Par exemple si vous aviez oublié l'accolade finale } à la fin,
vous auriez eu tout en bas un message d'erreur
qui vous indique exactement où le problème se situe :
line 5 col 1 : syntax error : '}' expected here
Il suffit alors d'aller à la ligne 5 colonne 1 de votre script, de corriger le texte, et de recliquez sur "Appliquer".
Pour éviter les erreurs de syntaxe et aussi faciliter la lecture, il est important d'avoir un style d'écriture clair.
Exemple :
// mon 2ème script event start () { string(32) s; int i; s = ""; for (i=0; i<16; i++) { s = s + chr(0,i); } say ("icons : " + s); }
Vous voyez, dans l'exemple ci-dessus, que les lignes entres accolades { } sont à chaque fois décalées de deux blancs à droite. En plus, une accolade { se trouve toujours à la verticale d'une accolade }. C'est une habitude que vous devez absolument prendre, cela vous évite d'oublier des accolades !
Le script suivant fonctionne aussi mais est tout à fait déconseillé parce qu'on n'y comprend plus rien !
Exemple :
// mon 3ème script (déconseillé) event start () { string(32) s; int i; s = ""; for (i=0; i<16; i++) { s = s + chr(0,i); } say ("icons : " + s); }
Quand vous postez un script sur un groupe ou un forum, changez le font en "Courier New" car avec cette police
de caractère les décalages sont conservés.
N'hésitez pas, pour clarifier un script, à ajouter plein de lignes de commentaires n'importe où dans votre script.
Il suffit pour cela de commencer une ligne par //
Ces lignes sont ignorées par la compilation.
Exemple:
// voici mon premier script // que j'ai créé pour animer // un peu ma salle. // Copyright le scripteur event start () { // la commande say va afficher un texte sur le chat ! say ("Salut les amis !"); }
Une variable est une cellule de la mémoire RAM du PC à laquelle on donne un nom.
Chaque variable numérique contient une valeur entre -2147483648 et +2147483647 (un peu plus de 2 milliards).
Celle valeur change généralement au fur et à mesure que le programme se déroule.
Pour créer une variable numérique, il faut la 'déclarer', c'est-à-dire réserver de la place mémoire pour son contenu, à l'aide d'une déclaration 'int'.
int compteur; // je crée mon compteur
Pour mettre une valeur dans une variable, on écrit une 'assignation' qui ressemble à ceci :
compteur = 2; // maintenant, compteur a la valeur 2
Pour rechanger la valeur d'une variable, il suffit de lui donner une nouvelle valeur :
compteur = 5; // maintenant, compteur a la valeur 5
On peut effectuer des calculs aussi. Dans l'exemple suivant on peut voir à chaque ligne:
. à gauche du signe =, la variable où sera stocké le résultat du calcul,
. à droite du signe =, une formule pour la valeur à calculer.
compteur = 2 + 5 * 7; // maintenant, compteur a la valeur 37 compteur = 5 / 2; // maintenant, compteur a la valeur 2 compteur = -45; // maintenant, compteur a la valeur -45 compteur = 100 - 101; // maintenant, compteur a la valeur -1
Vous avez sans doute deviné que l'astérisque sert à multiplier. Voici une liste des symboles utilisés couramment : (à apprendre par coeur !)
opération symbole --------------------- ------- addition + soustraction - multiplication * division / reste de la division %
Si vous êtes attentif, vous avez aussi dû être étonné que l'exemple précédent donne comme résultat 37 et non pas 49.
compteur = 2 + 5 * 7; // maintenant, compteur a la valeur 37
La raison est que, comme en mathématiques, les multiplications et divisions sont effectuées en premier, tandis que les additions et soustractions viennent ensuite. Si vous n'êtes pas sûr de la priorité des opérations, vous pouvez ajouter des parenthèses pour forcer l'ordre des calculs, par exemple comme ceci :
compteur = (2 + 5) * 7; // maintenant, compteur a la valeur 49
De même, l'exemple précédent a dû vous laisser perplexe.
compteur = 5 / 2; // maintenant, compteur a la valeur 2
En effet le résultat de 5 divisé par 2 est 2, on ignore la partie fractionnaire parce que compteur est de type 'int' et ne peut donc stocker que des nombres entiers.
Signalons encore les opérateurs de "shift" :
compteur = 3 << 3; // maintenant, compteur a la valeur 24 compteur = 35 >> 1; // maintenant, compteur a la valeur 17
Les opérateurs << et >> multiplient ou divisent par une puissance de 2.
Ainsi (a << b) est équivalent en mathématique à a . ( 2 b )
et (a >> b) est équivalent à a / ( 2 b )
Voici comment augmenter la valeur d'une variable de 1 :
compteur = compteur + 1; // calcule compteur + 1 et stocke le résultat dans compteur
Il existe cependant une manière abbréviée de faire la même chose, l'incrémentation :
compteur++; // augmente compteur de 1
De la même façon, pour diminuer une variable de 1, on fait une décrémentation.
compteur--; // diminue compteur de 1
Voici comment augmenter la valeur d'une variable de 10 :
compteur = compteur + 10; // calcule compteur + 10 et stocke le résultat dans compteur
Il existe cependant une manière abbréviée de faire la même chose, l'assignation avec addition :
compteur += 10; // augmente compteur de 10
De la même façon, pour diminuer une variable de 10 :
compteur -= 10; // diminue compteur de 10
Pour multiplier une variable par 3 :
compteur *= 3; // multiplie compteur par 3
Il y a une opération qui arrête le script avec une erreur, c'est de diviser par zéro, c'est interdit !
compteur = 3 / 0; // erreur compteur = 3 % 0; // erreur
Après avoir étudié le type 'int' au chapitre précédent, nous allons maintenant voir le type 'float' qui sert à stocker des variables numériques fractionnaires.
Exemple:
float f; f = 15.2476; f = 67.762 + 87.126; f *= 1.2;
Vous remarquerez qu'avec le type 'float', les nombres ont toujours un point obligatoire, même s'il n'y a pas de partie après la virgule. Par exemple pour spécifier la valeur 12 vous devrez écrire 12.0
Une variable de type 'float' peut stocker des nombres très grands, jusqu'à 38 chiffres. Pourtant, elle prend la même place en RAM qu'une variable de type 'int'. Comment est-ce possible ?
En fait une variable 'float' n'enregistre que les 6 ou 7 chiffres les plus significatifs de la valeur, ainsi qu'un exposant qui indique combien de zéros il faut ajouter.
f = 3.12345678901234567890; // sera stocké comme 3.12345600000000000 f = 3.12e8; // f vaut 3.12 x 10_exposant_8, donc 31200000.0 f = 0.5; // f vaut un demi f = 5.0e-1; // f vaut un demi aussi
Sur Planet, le type 'float' est très utilisé, pour stocker des distances en mètres, des angles de rotation ou des temps en secondes.
Le type 'float' permet les opérations suivantes :
opération symbole --------------------- ------- addition + soustraction - multiplication * division /
De plus, les fonctions suivantes sont disponibles :
float fabs (float value); // valeur absolue float sin (float angle); // sin, avec angle en degrés float cos (float angle); // cos, avec angle en degrés float atan2 (float y, float x); // arc tangeante, calcule un angle en degrés float sqrt (float angle); // racine carrée float trunc (float angle); // enlève la partie fractionnaire en tronquant float round (float angle); // enlève la partie fractionnaire en arrondissant string ftos (float value, int width=0, int decimals = 3); // converti un float en string
Exemple:
event start() { float n = sin(34.0); say ("sin(34) = " + ftos(n)); } // ce qui va afficher : sin(34) = 0.55919
Il existe une 3ème sorte de variable : les variables chaines de caractères, appelées 'string' en anglais.
Celles-ci ne contiennent pas de nombres mais des chaines de caractères (lettres, chiffres, ponctuation, etc ..).
Exemple:
string(100) nom; // je crée une variable string de maximum 100 caractères
Pour changer la valeur d'une variable string, on effectue une 'assignation' qui ressemble à ceci :
nom = "Bonjour"; // maintenant, nom a la valeur "Bonjour"
Remarquez que la valeur est mise entre guillemets.
Pour changer la valeur de la variable, il suffit de lui donner une nouvelle valeur :
nom = "Bonsoir"; // maintenant, nom a la valeur "Bonsoir"
On peut coller plusieurs chaines ensembles avec l'opérator "+".
nom = "Bon" + "soir"; // maintenant, nom a la valeur "Bonsoir" nom = nom + " mes amis"; // maintenant, nom a la valeur "Bonsoir mes amis"
Attention: la longueur d'une variable string ne peut pas dépasser 1024 caractères.
Pour effacer une variable string, vous pouvez lui assigner une chaine vide.
nom = ""; // maintenant, nom est vide
Le type 'string' permet les opérations suivantes :
int len (string value); // calcule la longueur de la chaine string chr (int c1, int c2, int c3, ..., int c16); // converti des codes ascii en chaine int asc (string value, int index=1); // converti le nième caractère de la chaine en code ascii string left (string value, int count); // prendre les N premiers caractères string right (string value, int count); // prendre les N derniers caractères string mid (string value, int index, int count=); // prendre les N caractères commençant au ième int pos (string phrase, string word); // trouve la position d'une chaine dans une autre string dup (string value, int count); // dupliquer une chaine N fois string upper (string value); // enlève les accents et converti en majuscules string lower (string value); // enlève les accents et converti en minuscules string trim (string value); // enlève les espaces avant et après string ltrim (string value); // enlève les espaces avant string rtrim (string value); // enlève les espaces après
On peut convertir une variable numérique en variable string à l'aide de la fonction itos(). Ce nom signifie en fait i vers s, donc int vers string.
Exemple:
int compteur; string(32) nom; compteur = 12; nom = itos(compteur); // maintenant, nom contient "12" nom = "compteur = " + itos(compteur); // maintenant, nom contient "compteur = 12"
A l'inverse, on peut convertir une variable string en variable numérique à l'aide de la fonction stoi()
int compteur; string(32) nom; nom = "12"; compteur = stoi (nom); // maintenant, compteur égale 12 compteur = stoi ("13"); // maintenant, compteur égale 13 compteur = stoi ("ab"); // ceci va donner une erreur qui arrête le script, // car "ab" ne peut être converti en valeur numérique !
L'affichage dans la fenêtre Conversation se fait à l'aide de la procédure say()
Exemple:
say ("Bonjour !"); say (nom);
Il n'est pas permis de donner à say() une variable numérique, par exemple ceci ne va pas fonctionner :
say (compteur); // erreur
Pour afficher la valeur de compteur, il faut le convertir d'abord en chaine de caractères :
say (itos(compteur));
On peut combiner cela en collant plusieurs chaines ensembles:
say ("la valeur de compteur égale " + itos(compteur));
Les conditions servent à "tester" des variables.
On peut par exemple dire "Si la variable machin est égale à 50, fais ceci"...
Mais ce serait dommage de ne pouvoir tester que l'égalité !
Il faudrait aussi pouvoir tester si la variable est inférieure à 50, inférieure ou égale à 50, supérieure, supérieure ou égale...
Ne vous inquiétez pas, le langage script a tout prévu (mais vous n'en doutiez pas hein)
Avant de voir comment on écrit une condition de type "if... else", il faut donc que vous connaissiez 2-3 symboles de base. Ces symboles sont indispensables pour réaliser des conditions.
Voici un petit tableau de symboles à connaître par coeur :
Symbole Signification ======= ============= == Est égal à > Est supérieur à < Est inférieur à >= Est supérieur ou égal à <= Est inférieur ou égal à != Est différent de
Faites très attention, il y a bien 2 symboles "==" pour tester l'égalité. Une erreur courante que font les débutants et de ne mettre qu'un symbole =. Je vous en reparlerai un peu plus bas.
Attaquons maintenant sans plus tarder. Nous allons faire un test simple, qui va dire à l'ordinateur :
SI la variable vaut ça ALORS fais ceci
Par exemple, on pourrait tester une variable "age" qui contient votre âge. Tenez pour s'entraîner, on va tester si vous êtes majeur, c'est-à-dire si votre âge est supérieur ou égal à 18 :
Exemple:
if (age >= 18) { say ("Vous êtes majeur !"); }
Le symbole >= signifie "Supérieur ou égal", comme on l'a vu dans le tableau tout à l'heure.
S'il n'y a qu'une instruction entre les accolades, alors celles-ci deviennent facultatives.
Vous pouvez donc écrire :
if (age >= 18) say ("Vous êtes majeur !");
Si vous voulez tester les codes précédents pour voir comment le if fonctionne, il faudra placer le if à l'intérieur d'un évenement start et ne pas oublier de déclarer une variable age à laquelle on donnera la valeur de notre choix.
Ca peut paraître évident pour certains, mais apparemment ça ne l'était pas pour tout le monde aussi ai-je rajouté cet exemple :
// exemple: event start () { int age; age = 20; if (age >= 18) say ("Vous êtes majeur !"); }
Ici, la variable age vaut 20, donc le "Vous êtes majeur !" s'affichera.
Essayez de changer la valeur initiale de la variable pour voir. Mettez par exemple 15 : la condition sera fausse, et donc "Vous êtes majeur !" ne s'affichera pas cette fois.
Servez-vous de ce code de base pour tester les prochains exemples du chapitre.
La façon dont vous placez les accolades n'est pas importante, votre programme marchera aussi bien si vous écrivez tout sur une même ligne.
Par exemple :
if (age >= 18) { say ("Vous etes majeur !"); }
Pourtant, même si c'est possible d'écrire comme ça, c'est ultra déconseillé !! En effet, tout écrire sur une même ligne rend votre code difficilement lisible.
Si vous ne prenez pas dès maintenant l'habitude d'aérer votre code, plus tard quand vous écrirez de plus gros programmes vous ne vous y retrouverez plus !
Essayez donc de présenter votre code source de la même façon que moi : une accolade sur une ligne, puis vos instructions (précédées de deux blancs pour les "décaler vers la droite"), puis l'accolade de fermeture sur une ligne.
Il existe plusieurs bonnes façons de présenter son code source.
Ca ne change rien au fonctionnement du programme final, mais c'est une question de "style informatique" si vous voulez. Si vous voyez un code de quelqu'un d'autre présenté un peu différemment, c'est qu'il code avec un style différent.
Le principal, c'est que son code reste aéré et lisible.
Maintenant que nous savons faire un test simple, allons un peu plus loin : si le test n'a pas marché (il est faux), on va dire à l'ordinateur d'exécuter d'autres instructions.
En français, nous allons donc écrire quelque chose qui ressemble à cela :
SI la variable vaut ça ALORS fais ceci SINON fais cela
Il suffit de rajouter le mot else après l'accolade fermante du if.
Petit exemple :
if (age >= 18) // Si l'âge est supérieur ou égal à 18 { say ("Vous etes majeur !"); } else // Sinon... { say ("Ah c'est bête, vous etes mineur !"); }
Les choses sont assez simples : si la variable age est supérieure ou égale à 18, on affiche le message "Vous êtes majeur !", sinon on affiche "Vous êtes mineur".
On a vu comment faire un "si" et un "sinon". Il est possible aussi de faire un "sinon si".
On dit dans ce cas à l'ordinateur :
SI la variable vaut ça ALORS fais ceci SINON SI la variable vaut ça ALORS fais ça SINON fais cela
Traduction:
if (age >= 18) // Si l'âge est supérieur ou égal à 18 { say ("Vous etes majeur !"); } else if (age > 4) // Sinon, si l'âge est au moins supérieur à 4 { say ("Bon t'es pas trop jeune quand meme..."); } else // Sinon... { say ("Aga gaa aga gaaa gaaa"); // Langage Bébé, vous ne pouvez pas comprendre ;o) }
L'ordinateur fait les tests dans l'ordre :
D'abord il teste le premier if : si la condition est vraie, alors il exécute ce qui se trouve entre les premières accolades.
Sinon, il va au "sinon si" et fait à nouveau un test : si ce test est vrai, alors il exécute les instructions correspondantes entre accolades.
Enfin, si aucun des tests précédents n'a marché, il exécute les instructions du "sinon".
Le "else" et le "else if" ne sont pas obligatoires. Pour faire une condition, il faut juste au moins un "if" (logique me direz-vous, sinon il n'y a pas de condition !)
Notez qu'on peut mettre autant de "else if" que l'on veut. On peut donc écrire :
SI la variable vaut ça ALORS fais ceci SINON SI la variable vaut ça ALORS fais ça SINON SI la variable vaut ça ALORS fais ça SINON SI la variable vaut ça ALORS fais ça SINON fais cela
Il peut aussi être utile de faire plusieurs tests à la fois dans votre if.
Par exemple, vous voudriez tester si l'âge est supérieur à 18 ET si l'âge est inférieur à 25.
Pour faire cela, il va falloir utiliser de nouveaux symboles :
Symbole Signification ======= ============= && ET || OU ! NON
Si on veut faire le test que j'ai mentionné plus haut, il faudra écrire :
if (age > 18 && age < 25)
Les deux symboles "&&" signifient ET.
Notre condition se dirait en français :
"Si l'âge est supérieur à 18 ET si l'âge est inférieur à 25"
Pour faire un OU, on utilise les 2 signes ||. Je dois avouer que ce signe n'est pas facilement accessible sur nos claviers. Pour le taper sur un clavier AZERTY français, il faudra faire Alt Gr + 6. Sur un clavier belge, il faudra faire Alt Gr + &.
Imaginons un programme débile qui décide si une personne a le droit d'ouvrir un compte en banque. C'est bien connu, pour ouvrir un compte en banque, il vaut mieux ne pas être trop jeune (on va dire arbitrairement qu'il faut avoir au moins 30 ans) ou bien avoir plein d'argent (parce que là même à 10 ans on vous acceptera à bras ouverts)
Notre test pour savoir si le client a le droit d'ouvrir un compte en banque pourrait être :
if (age > 30 || argent > 100000) { say ("Bienvenue chez Picsou Banque !"); } else { say ("Hors de ma vue, misérable !"); }
Ce test n'est valide que si la personne a plus de 30 ans ou si elle possède plus de 100 000 euros
Le dernier symbole qu'il nous reste à tester est le point d'exclamation.
En informatique, le point d'exclamation signifie "Non".
Vous devez mettre ce signe avant votre condition pour dire "Si cela n'est pas vrai" :
Exemple:
if (!(age < 18))
Cela pourrait se traduire par "Si la personne n'est pas mineure".
Si on avait enlevé le "!" devant, cela aurait signifié l'inverse : "Si la personne est mineure".
Si on veut tester si la personne a tout juste 18 ans, il faudra écrire :
if (age == 18) { say ("Vous venez de devenir majeur !"); }
N'oubliez pas de mettre 2 signes "égal" dans un if, comme ceci : ==
Une autre erreur courante de débutant : vous mettez parfois un point-virgule à la fin de la ligne d'un if. Or, un if est une condition, et on ne met de point-virgule qu'à la fin d'une instruction et non d'une condition.
Le code suivant ne marchera pas comme prévu car il y a un point-virgule à la fin du if :
if (age == 18); // Notez le point-virgule ici qui ne devrait PAS être là say ("Tu es tout juste majeur");
L'ordinateur va interpréter l'exemple erroné ci-dessus comme suit :
if (age == 18) ; // Notez le point-virgule ici qui ne devrait PAS être là say ("Tu es tout juste majeur");
Ce qui signifie que le say() sera toujours exécuté, quelle que soit le résultat du if !
Nous allons maintenant rentrer plus en détail dans le fonctionnement d'une condition de type if... else.
En effet, les conditions font intervenir quelque chose qu'on appelle les booléens en informatique.
C'est un concept très important, donc ouvrez grand vos oreilles (euh vos yeux plutôt)
En cours de Physique-Chimie, mon prof avait l'habitude de nous faire commencer par quelques petites expériences avant d'introduire une nouvelle notion. Je vais l'imiter un peu aujourd'hui.
Voici un code source très simple que je vous demande de tester :
if (true) { say ("C'est vrai"); } else { say ("C'est faux"); }
Résultat :
C'est vrai
Mais ??? On n'a pas mis de condition dans le if, juste true (vrai en français). Qu'est-ce que ça veut dire ça n'a pas de sens ?
Si, ça en a, vous allez comprendre.
Faites un autre test maintenant en remplaçant le true par un false :
if (false) { say ("C'est vrai"); } else { say ("C'est faux"); }
Résultat :
C'est faux
En fait, à chaque fois que vous faites un test dans un if, ce test renvoie la valeur true s'il est vrai, et false s'il est faux.
Par exemple :
if (age >= 18)
Ici, le test que vous faites est "age >= 18".
Supposons que age vaille 23. Alors le test est vrai, et l'ordinateur "remplace" en quelque sorte "age >= 18" par true.
Ensuite, l'ordinateur obtient (dans sa tête) un "if (true)".
Quand la valeur est true, comme on l'a vu, l'ordinateur dit que la condition est vraie, donc il affiche "C'est vrai" !
De même, si la condition est fausse, il remplace age >= 18 par false, et du coup la condition est fausse : l'ordinateur va lire les instructions du "else".
Testez maintenant un autre truc : envoyez le résultat de votre condition dans une variable, comme si c'était une opération (car pour l'ordinateur, c'est une opération !).
Exemple:
int age; bool majeur; age = 20; majeur = age >= 18; if (majeur) say ("majeur"); else say ("mineur");
Comme vous le voyez, la condition age >= 18 a renvoyé true car elle est vraie. Du coup, notre variable majeur vaut true.
Faites le même test en mettant age = 10 par exemple. Cette fois, majeur vaudra false.
Cette variable "majeur" est un booléen ! Vous voyez qu'on l'a déclarée avec :
bool majeur;
Retenez bien ceci : On dit qu'une variable à laquelle on fait prendre les valeurs false et true est un booléen.
Souvent, on fera un test "if" sur une variable booléenne :
bool majeur; majeur = true; if (majeur) { say ("Tu es majeur !"); } else { say ("Tu es mineur"); }
Comme majeur vaut true, la condition est vraie, donc on affiche "Tu es majeur !".
Ce qui est très pratique, c'est que la condition se lit facilement par un être humain.
On voit "if (majeur)", ce que peut traduire par "Si tu es majeur".
Les tests sur des booléens sont donc faciles à lire et à comprendre, pour peu que vous ayez donné des noms clairs à vos variables.
Tenez, voici un autre test imaginaire :
if (majeur && garcon)
Ce test signifie "Si tu es majeur ET que tu es un garçon".
garcon est ici une autre variable booléenne qui vaut true si vous êtes un garçon, et false si vous êtes... une fille ! Bravo, vous avez tout compris !
Les booléens servent donc à exprimer si quelque chose est vrai ou faux.
C'est très utile, et ce que je viens de vous expliquer vous permettra de comprendre bon nombre de choses par la suite.
La condition "if... else" que l'on vient de voir est le type de condition le plus souvent utilisé.
En fait, il n'y a pas 36 façons de faire une condition. Le "if... else" permet de gérer tous les cas.
Exemple:
if (age == 2) { say ("Salut bebe !"); } else if (age == 6) { say ("Salut gamin !"); } else if (age == 12) { say ("Salut jeune !"); } else if (age == 16) { say ("Salut ado !"); } else if (age == 18) { say ("Salut adulte !"); } else if (age == 68) { say ("Salut papy !"); } else { say ("Je n'ai aucune phrase de prête pour ton âge "); }
Si vous devez tester une suite d'égalités comme dans l'exemple ci-dessus, il existe aussi l'instruction 'switch' qui permet de ré-écrire cela plus proprement :
switch (age) { case 2: say ("Salut bebe !"); break; case 6; say ("Salut gamin !"); break; case 12: say ("Salut jeune !"); break; case 16: say ("Salut ado !"); break; case 18: say ("Salut adulte !"); break; case 68: say ("Salut papy !"); break; default: say ("Je n'ai aucune phrase de prête pour ton âge "); break; }
Les conditions peuvent aussi s'appliquer aux types 'float' et 'string'.
Par exemple on écrira (f >= 1.0 && f <= 2.0) pour tester si f est entre 1 et 2.
De la même manière (nom >= "ARBRE" && nom <= "CROCO") testera si nom est entre ARBRE
et CROCO en ordre lexicographique (ordre du dictionnaire).
Qu'est-ce qu'une boucle ?
C'est une technique permettant de répéter les mêmes instructions plusieurs fois.
Tout comme pour les conditions, il y a plusieurs façons de réaliser des boucles.
Au bout du compte, cela revient à faire la même chose : répéter les mêmes instructions un certain nombre de fois.
Dans tous les cas, le schéma est le même :
<---------- Instructions ^ Instructions ^ Instructions ^ Instructions ^ -----------^
Voici ce qu'il se passe dans l'ordre :
L'ordinateur lit les instructions de haut en bas (comme d'habitude)
Puis, une fois arrivé à la fin de la boucle, il repart à la première instruction
Il recommence alors à lire les instructions de haut en bas...
... Et il repart au début de la boucle.
Le problème dans ce système c'est que si on ne l'arrête pas, l'ordinateur est capable de répéter les instructions à l'infini !
Il n'est pas du genre à se plaindre vous savez, il fait ce qu'on lui dit de faire ..
Et c'est là qu'on retrouve... des conditions ! Quand on crée une boucle, on indique toujours une condition.
Cette condition signifiera "Répète la boucle tant que cette condition est vraie".
Il y a plusieurs manières de s'y prendre comme je vous l'ai dit. Voyons voir sans plus tarder comment on réalise une boucle de type "while".
Voici comment on construit une boucle while :
while ( Condition ) { // Instructions à répéter }
C'est aussi simple que cela. While signifie "Tant que".
On dit donc à l'ordinateur "Tant que la condition est vraie : répète les instructions entre accolades".
On veut que notre boucle se répète un certain nombre de fois.
On va pour cela créer une variable "compteur" qui vaudra 0 au début du programme et que l'on va incrémenter au fur et à mesure.
Vous vous souvenez de l'incrémentation ? Ca consiste à ajouter 1 à la variable en faisant "variable++;".
Regardez attentivement ce bout de code et, surtout, essayez de le comprendre :
int compteur; compteur = 0; while (compteur < 5) { say ("Salut !"); compteur++; }
Résultat :
Salut ! Salut ! Salut ! Salut ! Salut !
Ce code répète 5 fois l'affichage de "Salut !".
Comment ça marche exactement ?
Au départ, on a une variable compteur initialisée à 0. Elle vaut donc 0 au début du programme.
La boucle while ordonne la répétition TANT QUE compteur est inférieur à 5.
Comme compteur vaut 0 au départ, on rentre dans la boucle.
On affiche la phrase "Salut !" via un say.
On incrémente la valeur de la variable compteur, grâce à l'instruction "compteur++;". Compteur valait 0, il vaut maintenant 1.
On arrive à la fin de la boucle (accolade fermante), on repart donc au début, au niveau du while.
On refait le test du while : "Est-ce que compteur est toujours inférieur à 5 ?". Ben oui, compteur vaut 1 Donc on recommence les instructions de la boucle.
Et ainsi de suite... Compteur va valoir progressivement 0, 1, 2, 3, 4, 5.
Lorsque compteur vaut 5, la condition "compteur < 5" est fausse. Comme l'instruction est fausse, on sort de la boucle.
On pourrait voir d'ailleurs que la variable compteur augmente au fur et à mesure dans la boucle, en l'affichant dans le say :
int compteur; compteur = 0; while (compteur < 5) { say ("la variable compteur vaut " + itos(compteur)); compteur++; }
Cela affichera:
La variable compteur vaut 0 La variable compteur vaut 1 La variable compteur vaut 2 La variable compteur vaut 3 La variable compteur vaut 4
Voilà, si vous avez compris ça, vous avez tout compris. Vous pouvez vous amuser à augmenter la limite du nombre de boucles ("< 10" au lieu de "< 5").
Lorsque vous créez une boucle, assurez-vous toujours qu'elle peut s'arrêter à un moment ! Si la condition est toujours vraie, votre programme ne s'arrêtera jamais !
Voici un exemple de boucle infinie :
while (true) { say ("Boucle infinie"); }
Souvenez-vous des booléens. Ici, la condition est toujours vraie, donc ce programme affichera "Boucle infinie" sans arrêt !
Faites donc très attention : évitez à tout prix de tomber dans une boucle infinie.
En théorie, la boucle while permet de réaliser toutes les boucles que l'on veut. Toutefois, il est dans certains cas utiles d'avoir un autre système de boucle plus "condensé", plus rapide à écrire.
Les boucles for sont très très utilisées en programmation.
Je n'ai pas de statistiques sous la main, mais sachez que vous utiliserez certainement autant de for que de while, donc il vous faudra savoir manipuler ces deux types de boucles.
Comme je vous le disais, les boucles for sont juste une autre façon de faire une boucle while.
Voici un exemple de boucle while que nous avons vu tout à l'heure :
int compteur; compteur = 0; while (compteur < 10) { say ("Salut !"); compteur++; }
Voici maintenant l'équivalent en boucle for :
int compteur; for (compteur = 0 ; compteur < 10 ; compteur++) { say ("Salut !"); }
Quelles différences ?
Il y a beaucoup de choses entre les parenthèses après le for (nous allons détailler ça après) Il n'y a plus de compteur++; dans la boucle.
Intéressons-nous à ce qui se trouve entre les parenthèses, car c'est là que réside tout l'intérêt de la boucle for. Il y a 3 instructions condensées, séparée chacune par un point-virgule :
La première est l'initialisation : cette première instruction est utilisée pour préparer notre variable compteur. Dans notre cas, on initialise la variable à 0.
La seconde est la condition : comme pour la boucle while, c'est la condition qui dit si la boucle doit être répétée ou pas. Tant que la condition est vraie, la boucle for continue.
Enfin, il y a l'incrémentation : cette dernière instruction est exécutée à la fin de chaque tour de boucle pour mettre à jour la variable compteur. La quasi-totalité du temps on fera une incrémentation, mais on peut aussi faire une décrémentation (variable--;) ou encore n'importe quelle autre opération (variable += 2; pour avancer de 2 en 2 par exemple).
Bref, comme vous le voyez la boucle for n'est rien d'autre qu'un condensé du while. Sachez vous en servir, vous en aurez besoin plus d'une fois !
L'instruction break sert à abandonner et quitter une boucle.
for (i=0; i<5; i++) { if (i == 3) break; // exit here say (itos(i)); }
va afficher
0 1 2
L'instruction continue sert à passer tout de suite au prochain tour de boucle.
for (i=0; i<5; i++) { if (i == 1 || i == 3) continue; say (itos(i)); }
va afficher
0 2 4
Aux chapitres précédents, vous avez pu écrire des scripts qui tournaient tout seuls en ignorant complètement les avatars.
Maintenant, nous allons passer à un autre genre de script : ceux qui interagissent avec les avatars et qui leur répondent !
En effet, les avatars provoquent des actions, par exemple :
- ils cliquent sur l'objet
- ils écrivent des lignes de texte
etc ...
A chaque fois qu'une action se produit, l'évènement correspondant est exécuté.
Exemple :
// réagir par un message quand le chatteur touche l'objet event touch() { say ("Bienvenue " + avatar_name(touched_avatar())); }
Dans l'évènement, on a accès à tout un tas de paramètres concernant l'action : par exemple touched_avatar() renvoie une clé sur l'avatar qui a touché. On peut passer cette clé dans la fonction avatar_name() pour récupérer le nom de l'avatar qui a touché.
Il faut savoir que pendant 99% du temps, un script ne fait rien, il dort !
Mais dès qu'un avatar provoque une action, le script se réveille !
Il exécute alors les quelques instructions contenues dans un évènement (par exemple il affiche un message), et quand c'est terminé, le script se remet à dormir en attendant la prochaine action.
Entre deux actions, donc pendant qu'il dort, le script a complètement perdu la mémoire, c'est-à-dire que toutes les variables sont remises à zéro !
Il y a une seule exception à cette règle, ce sont les variables globales (celles qui sont déclarées tout en haut du script). Ces dernières sont donc très utiles car elles gardent leur valeur tant que le script tourne !
Il faut cependant savoir que les variables globales augmentent le coût du script, tandis que celles déclarées plus bas ne coûtent rien. Il ne faut donc utiliser de variables globales que si leur valeur doit être conservée entre 2 évènements.
Le script suivant dit à chaque avatar combien d'avatars ont touché l'objet avant lui. Pour cela, il utilise une variable déclarée en haut du script.
// un script qui compte les chatteurs int g_compteur = 0; event touch() { say ("Bienvenue " + avatar_name(touched_avatar())); g_compteur++; say ("tu es la " + itos(g_compteur) + " personne qui me touche depuis que mon script tourne"); }
Souvent, les variables déclarées tout en haut du script commencent par g_ pour indiquer global.
Ce n'est pas obligatoire mais c'est une convention parmi les informaticiens.
Au lieu de réserver une seule variable, on peut aussi réserver tout un tableau de variables.
Exemple:
int[100] compteur; // je crée 100 compteurs
En fait, l'exemple ci-dessus crée les 100 compteurs suivants :
compteur[0] compteur[1] compteur[2] compteur[3] ... compteur[99]
Pour effacer tout le tableau en une fois (mettre tous les compteurs à zéro), on utilise l'instruction clear :
clear compteur;
On peut stocker des valeurs dans ces compteurs, comme ceci :
compteur[5] = 12; // stocker 12 dans le compteur numéro 5 compteur[5]++; // augmenter le compteur 5 de 1 compteur[i] = 13; // stocker 13 dans le compteur i
Le dernier exemple ci-dessus va donner une erreur de script si la variable "i" n'a pas de valeur comprise entre 0 et 99.
Les structures sont un autre mécanisme pour déclarer plusieurs variables, mais d'un type différent. Par exemple ici on va créer une structure INFO composée de deux zones : name et cost :
struct INFO { string(32) name; int cost; }
Une fois la structure créée, on peut déclarer des variables de celle-ci, par exemple :
INFO info;
et on peut y assigner des valeurs :
info = {name => "Marc", cost => 10};
Pour n'accéder qu'à un champ de la structure, on utilise un point suivi du nom du champ. Exemple:
say (info.name);
On peut combiner structure et tableau, par exemple on peut déclarer un tableau de 100 structures INFO :
INFO[100] table;
Pour effacer une grande variable en une fois, l'instruction clear est pratique :
clear table;
Pour écrire la valeur 2 dans le champ cost du 5ème élément du tableau, on écrira :
table[5].cost = 2;
Qu'est-ce qu'une fonction ? et bien par exemple "atan2()", qui permettent de calculer l'arc-tangeante.
float f = atan2 (30.0, 40.0);
Vous connaissez aussi "say()", qui permet d'afficher un texte à l'écran.
say ("hello");
Ces deux fonctions sont déclarées avec le formalisme suivant :
float atan2 (float y, float x); void say (string s);Ce formalisme indique que :
En fait une fonction qui commence par void c'est une commande, tandis qu'une fonction sans void calcule un résultat. A part cela, les deux sont très semblables.
Nous allons étudier quelques fonctions courantes pour voir comment ça marche :
date_time now (); // fonction qui calcule la date du jour int rnd (int a,int b); // renvoie un nombre aléatoire entre a et b
La fonction now() est simple : elle n'a aucun paramètre et calcule la date et l'heure du PC. Par exemple on peut écrire :
event start() { date_time ma_date; ma_date = now(); // mettre la date dans ma_date say (itos(ma_date.day, 2, "0") + "/" + itos(ma_date.month, 2, "0") + "/" + itos(ma_date.year, 2, "0")); }
ce qui va imprimer par exemple:
02/12/2020
La fonction rnd() permet de tirer un nombre au hasard, ce qui est très utile pour les jeux.
Exemple:
event touch() { int i; i = rnd (1, 100); // choisir un nombre de 1 à 100 à mettre dans i say ("on choisit " + itos(i)); }
Dans la documentation du langage script, vous trouverez des listes de toutes les procédures et fonctions prédéfinies.
On peut aussi créer ses propres fonctions. Tenez par exemple si on voulait créer une fonction tan() qui calcule la tangeante, on pourrait écrire ceci :
float tan (float a) { float t = sin (a) / cos (a); return t; }
Vous voyez qu'on a déclaré la fonction avec le formalisme (mais sans point-virgule à la fin), ensuite entre accolades on a mis une suite d'instructions pour calculer la valeur, et finalement on termine la fonction par l'instruction "return" qui termine la fonction et spécifie la valeur du résultat.
Voici une autre fonction qui dit bonjour :
void say_hello (key k) { say ("Hello " + avatar_name (k)); } event touch() { say_hello (k => touched_avatar()); }
L'event touch va appeler la fonction say_hello en donnant en paramètre une clé d'avatar, et cette fonction va afficher sur l'écran Hello et le nom de cet avatar.
Si on veut terminer une fonction void, on peut simplement écrire "return;"
// dire bonjour aux femmes seulement void say_hello_to_female (key k) { if (avatar_gender (k) != 1) return; say ("Hello " + avatar_name (k)); } event touch() { say_hello_to_female (k => touched_avatar()); }
Ici la fonction teste le genre de l'avatar. Si ce n'est pas une femme la fonction se termine immediatement avec le return
sans rien afficher. Sinon on continue pour afficher le hello.
Lorsque vous utilisez plusieurs fois la même valeur dans un long script, vous pouvez déclarer cette valeur tout en haut du script par une constante. En cas de changement de la valeur, vous ne devrez la changer qu'à un seul endroit et vous pourrez la retrouver facilement.
Exemple: des constants numériques et string
const int NOMBRE_DE_PLACES = 4; const float SECONDES = 30.0; const string ACCUEIL_1 = "Bonjour, j'ai "; const string ACCUEIL_2 = " places"; say (ACCUEIL_1 + itos(NOMBRE_DE_PLACES) + ACCUEIL_2);
Souvent, les constantes sont écrites en majuscules, c'est une convention parmi les informaticiens.
Exemple: des constantes de tableaux
const string(23)[3] MENU1 = {"Jeu contre l'ordinateur", "Play against computer", "Spiel gegen Computer"};
Exemple: des constantes de tableaux de structures
struct BOISSON { string(16) name; } const int MAX_OBJECTS = 5; const BOISSON G_BOISSON[MAX_OBJECTS] = { {name => "Bière"}, {name => "Soda coca"}, {name => "Soda orange"}, {name => "Becher Kaffee"}, {name => "Becher Tee"}, };
Voici un script qui répète un texte toutes les 10 secondes.
event start() { start_timer (0, 10.0); } event timer (int nr) { say ("Salut les amis !"); say ("J'espère que vous allez bien :p"); start_timer (0, 10.0); }
La procédure start_timer(0, 10.0); signifie: "déclenchez la minuterie numéro 0 dans 10 secondes"
Quand event timer est exécuté, elle écrit le texte, et le start_timer la redéclenche pour dans 10 secondes, etc ... et ça tourne en boucle !
La procédure say() permet d'afficher un texte, par exemple :
say ("Bonjour !");
On peut coller plusieurs morceaux de textes ensembles en utilisant l'opérateur + (plus), par exemple:
say ("Bonjour " + "Chers Amis !");
bon, dans ce cas-ci, on aurait pu écrire aussi :
say ("Bonjour Chers Amis !");
Mais voici un cas plus intéressant :
say ("Bonjour " + userid + " !");
ici, on colle le bonjour et le nom du chatteur ensembles.
Notez que si vous écrivez :
say (count);
vous allez avoir une erreur car say() n'accepte que des variables string !
Pour afficher une valeur, il faut d'abord la convertir en texte avec la fonction itos().
Exemple :
say ("tu es la " + itos(count) + " personne qui me touche depuis que mon script tourne");
Pour écrire en différents style, vous pouvez utiliser les fonctions :
color (0xFFFFFF) : changer de couleur font (5) : numéro de font style (underlined => true, italic => true, bold => true) : changer de style souligné italique ou gras
Exemple:
// message d'accueil string font(int f) { return chr(1, f); } string style(bool underlined, bool italic, bool bold) { int s=0; if (underlined) s++; if (italic) s+=2; if (bold) s+=4; return chr(2, s); } string color(int col) { return chr(4, col & 0xFFFF, col>>16); } event touch () { say ("big " + color(0x8080FF) + "kiss" + font(9) + color(0x00FF00) + style(underlined => true, italic => true, bold => true) + " from Didi"); }
Cet exemple affiche le message de bienvenue en rouge !
Mais bon, si vous affichez beaucoup de texte rouge ce n'est pas pratique.
Car le jour où vous voulez changer de couleur, vous devez changer tous les color(0x8080FF) dans votre programme.
Ce que vous pouvez faire c'est d'écrire votre propre fonction de changement de couleur.
Exemple:
// message d'accueil string font(int f) { return chr(1, f); } string style(bool underlined, bool italic, bool bold) { int s=0; if (underlined) s++; if (italic) s+=2; if (bold) s+=4; return chr(2, s); } string color(int col) { return chr(4, col & 0xFFFF, col>>16); } string ftitle () { return color(0x8080FF) + font(8); // couleur rouge + font Impact } event touch () { say (ftitle() + "Bonjour !"); }
Voilà donc si vous voulez changer les couleurs ou le font, il vous suffit de modifier la fonction ftitle.
Voici un autre exemple qui montre qu'on peut mettre tout un texte en fonction :
Exemple:
// message d'accueil string font(int f) { return chr(1, f); } string style(bool underlined, bool italic, bool bold) { int s=0; if (underlined) s++; if (italic) s+=2; if (bold) s+=4; return chr(2, s); } string color(int col) { return chr(4, col & 0xFFFF, col>>16); } string red () { return color(0x8080FF); } string Impact () { return font(8); } string Bienvenue (string userid) { return red() + Impact() + "Bienvenue " + userid + " !"; } event touch () { say (Bienvenue (avatar_name(touched_avatar()))); }
Remarquez dans l'exemple ci-dessus qu'on a passé le paramètre userid à la fonction Bienvenue() car elle en avait besoin !
Une autre solution aurait été d'utiliser une procédure au lieu d'une fonction. La différence entre les deux est très mince : une fonction renvoie une valeur ou un texte, une procédure ne renvoie rien ! (void en anglais)
Exemple:
// message d'accueil string font(int f) { return chr(1, f); } string style(bool underlined, bool italic, bool bold) { int s=0; if (underlined) s++; if (italic) s+=2; if (bold) s+=4; return chr(2, s); } string color(int col) { return chr(4, col & 0xFFFF, col>>16); } string red () { return color(0x8080FF); } string Impact () { return font(8); } void Bienvenue (string userid) { say (red() + Impact() + "Bienvenue " + userid + " !"); } event touch () { Bienvenue (avatar_name(touched_avatar())); }
Ci-dessus, vous pouvez remarquer que la procédure say() n'est plus dans l'évènement touch, mais dans la procédure Bienvenue.
Comment afficher un message de bienvenue aléatoire ?
A l'aide de la fonction rnd() !
Exemple:
// message de bienvenue aléatoires event touch () { int n; n = rnd (1, 3); // tire un nombre aléatoire entre 1 et 3 if (n == 1) say ("salut, ça va ?"); else if (n == 2) say ("oula, toi je ne t'aime pas !"); else say ("reviens plus tard, j'suis pas là :p"); }
Remarquez ici que la variable 'n' n'a pas été déclarée en haut du script mais dans la procédure : elle perd donc sa valeur entre deux actions pendant que le script dort, mais cela convient bien puisqu'on ne souhaite pas garder sa valeur.
Le script suivant va choisir un texte de bienvenue au hasard dans un fichier que vous avez placé dans le dossier script de l'objet :
// message de bienvenue aléatoires event touch () { // compte le nombre de lignes dans le fichier bienvenue.txt int count = count_lines ("bienvenue.txt"); // tire un nombre aléatoire entre 1 et count int n = rnd (1, count); // extrait la ligne choisie du fichier string(128) s = read_line ("bienvenue.txt", n); // affiche la ligne say (s); }
Vous savez que les variables déclarées en haut du script gardent leur valeur entre deux actions. Mais que se passe-t-il lorsque le script est changé ? Elles sont évidemment effacées ..
Ce qu'il faudrait, c'est un moyen de garder des données de façon permanente, sur le disque dur ...
On utilise pour cela les fonctions store et fetch qui permettent d'écrire des informations sur le serveur Planet puis de les relire plus tard.
store (tiroir, valeur); // stocke la valeur dans le tiroir du serveur // exemple: store ("JEU-DEVINE", "1 35 16 32 89 12"); s = fetch (tiroir); // renvoie la valeur contenue dans le tiroir // exemple: fetch ("JEU-DEVINE") == "1 35 16 32 89 12"
Comment cela fonctionne-il ?
Imaginez que vous êtes dans une grande bibliothèque avec un mur de tiroirs devant vous.
Sur chaque tiroir est écrit un nom.
Quand vous ouvrez un tiroir vous pouvez y mettre une valeur et le refermer.
Plus tard, vous pouvez ouvrir le tiroir à nouveau et récupérer la valeur que vous y avez mise.
C'est exactement comme cela que fonctionnent store et fetch.
Vous êtes évidemment libre de mettre la valeur que vous voulez dans le tiroir. Cela peut être un score, des points, le nombre de fois qu'un chatteur est entré en salle, la date et l'heure de sa dernière venue, ou toute autre info.