Les expressions sont des instructions qui permettent d’attribuer une valeur à des variables.
Dans le cas le plus simple, nous attribuons une valeur à une variable:
a = 10
Important: lors de la première affectation d’une valeur, on détermine le type de la variable. Si rien n’est indiqué, on utilise normalement “Int”. Ce type de données peut stocker un nombre de -32768 à 32767.
Si l’on programme à la place ce qui suit
a = 10.5
un autre type est utilisé. Dans ce cas, la variable est de type “float”. Ce type de données stocke un nombre dit à virgule flottante dans une plage de valeurs allant de 1.17549e-038 à 3.40282e+038. On appelle ce type de données ainsi parce que l’écriture exponentielle permet de représenter des nombres très grands et aussi très petits en déplaçant la virgule. La précision est toutefois limitée en raison du nombre restreint de chiffres.
Toutes les valeurs numériques peuvent être calculées à volonté
a = b / 5 -10
etc.
Il est également possible d’appeler des fonctions de la bibliothèque de fonctions, comme par exemple
a = sin(b) * 100
Calcule le sinus de la valeur du radian b et multiplie la valeur par 100.
En principe, nous appliquons la règle du point avant le tiret, comme nous l’avons appris en cours de mathématiques. On peut toutefois modifier l’ordre à l’aide de parenthèses:
a = (5 + sin(b)) * (100 - c)
Pour les affectations, on peut aussi utiliser des valeurs de tableau. Celles-ci sont indiquées avec l’index entre crochets:
somme = a[0] + a[1] + a[2] + a[3]
Si l’index du tableau se trouve à gauche de l’affectation, on peut modifier un élément du tableau:
a[i] = a[i+1]
Dans la mesure où les objets de classe contiennent des composants numériques, on peut les utiliser comme des variables normales. Ici, nous utilisons l’opérateur de point (“.”):
v1 = vector(x=1,y=1)
v2 = vector(x=2,y=2)
dotProduct = v1.x * v2.x + v1.y * v2.y
Outre les affectations simples avec le signe d’égalité “=”, il existe des variantes d’affectation supplémentaires:
”++”: Ce signe augmente la valeur de la variable de 1.
i=10
i++
i++
i++
“i” a maintenant la valeur 13.
”–”: réduit la valeur de 1.
”+=”: augmente la valeur de la variable de l’expression qui se trouve à droite.
i=10
i+= (100-95)*3
“i” a la valeur 25.
”-=”: réduit la valeur de l’expression à partir de la droite.
Comme une variable, une constante est un caractère de remplacement que vous pouvez spécifier n’importe où dans le programme à la place d’une valeur numérique. Cependant, contrairement aux variables, la valeur d’une constante ne peut être définie qu’une seule fois et ne peut plus être modifiée.
Pour la déclarer, nous utilisons l’instruction “const”. Exemple :
const MAX_SIZE = 5.8
Pour faciliter l’identification des constantes dans le code, on les écrit généralement en majuscules et en snake-case (voir Conventions d’appellation).
Utilisation de l’éditeur de constantes :
Si l’on déclare les constantes selon le modèle suivant, elles apparaissent en outre dans l’éditeur de constantes sous forme de curseur ou de case à cocher :
const NOM = VALEUR # de la plage à la plage ...
Exemple :
const COLOR = 0 # 0 .. 255
Déclare une constante “COLOR” avec une valeur initiale de 0 et une plage de valeurs de 0 à 255. Ceci peut ensuite être réglé via le curseur.
const FAST_MODE = true # true, false
Déclare une constante booléenne qui peut être soit “true” (vraie) soit “false” (fausse). Dans l’éditeur de constantes, un simple interrupteur est dessiné ici, que l’on peut activer/désactiver en cliquant dessus.
Si une valeur de couleur doit être sélectionnée, “HUE” peut être utilisé :
const COLOR = 0 # HUE
Les constantes peuvent également contenir des calculs, à condition qu’ils se limitent à des valeurs numériques ou à d’autres constantes déclarées précédemment :
const WIDTH = 100
const HEIGHT = 80
const VOLUME = WIDHT * HEIGHT
const HALF_VOLUME = (WIDTH * HEIGHT) / 2
Note importante : Il doit y avoir au moins 8 espaces avant le caractère #, sinon l’éditeur de coût ne fonctionnera pas.
Une fonction est une procédure qui effectue un calcul et renvoie une valeur.
La manière la plus simple de comparer cela est avec les fonctions mathématiques, par exemple les fonctions trigonométriques sinus, cosinus, racine carrée, etc. Par exemple, on peut attribuer une valeur à une variable pour déterminer la valeur du sinus:
unevaleur = sin(PI/2)
Le sinus de PI/2 est “1”. C’est-à-dire que la variable “uneValeur” aura la valeur 1 après cet appel.
Les fonctions peuvent également faire partie d’un objet. La classe “vector” contient la fonction “distance” qui permet de calculer la distance entre deux vecteurs.
Exemple:
v1 = vector(x=2,y=4)
v2 = vector(x=10,y=10)
d = v1.distance(v2)
“d” contient la valeur 10.
Il est possible de déclarer ses propres procédures et fonctions avec l’instruction “def”:
Déclaration d’une procédure sans valeur de retour:
def Nom de la procédure(paramètre1, paramètre...):
# instructions...
Déclaration d’une fonction avec valeurs de retour:
def Nom de la fonction(paramètre1, paramètre ..)->Valeur de retour:
# ....
return valeur de retour
Exemples:
def drawHelloWorld():
background(0,0,0)
stroke(255,255,255)
drawText(10,10, "Hello World !")
update()
def drawMatrix(taille):
for x in size:
for y in size:
drawRectangle(x,y,size,taille)
def diff(a:float,b:float)->float:
if a>b:
return a-b
else
return b-a
Toutes les fonctions exécutent les instructions en retrait. L’instruction “return” permet de quitter immédiatement la fonction. Si la fonction a défini une valeur de retour, il faut en plus indiquer une valeur pour “return”.
Ces fonctions définies peuvent être appelées de cette manière:
drawHelloWorld()
Dessine “Hello World !” sur l’écran.
drawMatrix(10)
Dessine 10 * 10 rectangles de 10 * 10 pixels.
d = diff(10.4,2.1)
Renvoie la différence entre les deux nombres (=8.3) et stocke la valeur dans la variable “d”. Nous voyons ici dans le code que “return” renvoie un calcul. Selon le nombre le plus grand, on renvoie soit le résultat du calcul de “a-b”, soit celui de “b-a”.
Avec “while”, un bloc d’instructions peut être répété jusqu’à ce qu’une condition ne soit plus remplie.
La structure est la suivante:
while condition:
# instructions
“Condition” peut être une expression quelconque qui est soit vraie soit fausse. Tant que la condition est remplie, le bloc est exécuté à plusieurs reprises.
Exemple:
fond(0,0,0)
y=10
while y<240:
drawLine(0,y,240,y)
y = y + 10
update()
Cet exemple dessine une ligne verticale tous les 10 pixels.
Si la condition est toujours remplie, on parle de boucle infinie. Celle-ci peut par exemple être déclarée ainsi:
while true:
background(0,0,0)
update()
delay(500)
background(255,255,255)
update()
delay(500)
L’exemple fait s’allumer l’écran en noir et blanc sans fin.
Un programme peut être construit de deux manières.
Par événement ou comme une suite d’instructions.
Dans l’approche événementielle, le programme réagit aux événements du système et s’exécute en principe sans fin.
Trois procédures événementielles sont disponibles: “onDraw()”, “onClick()” et “onTimer()”.
“onDraw()” est exécuté en permanence, chaque fois que le système est déchargé.
Cela signifie que “onDraw()” est appelé plusieurs milliers de fois par seconde, selon la situation.
Dans l’animation, cette fonction sert à dessiner et à actualiser l’écran.
Mais on peut aussi l’utiliser à d’autres fins.
“onClick()” n’est appelé que lorsqu’un ou plusieurs boutons sont enfoncés. Cette fonction sert à interroger et à réagir aux clics.
Le système d’événements vérifie en permanence si un bouton est pressé. Si c’est le cas, après l’appel de “onDraw()”, “onClick()” est appelé. Les appels sont donc toujours séquentiels et non parallèles.
Structure générale:
# Déclaration des classes, des variables globales et des fonctions...
def onDraw():
# Instructions...
def onClick():
# instructions...
Exemple:
hue:int
def onDraw():
backgroundHSV(hue,255,255)
update()
def onClick():
b:buttons = getButtons()
if b.up: hue = 0
if b.down: hue = 50
if b.left: hue = 100
if b.right: hue = 150
if b.middle: hue = 255
L’exemple colore l’écran d’une couleur en fonction du bouton sur lequel on a appuyé.
Il est également possible de renoncer aux procédures événementielles et de formuler son programme comme une simple suite d’instructions. L’exemple suivant écrit “Hello World !” sur l’écran et se termine (s’arrête) ensuite. L’écran reste affiché jusqu’à ce que l’Oxocard reçoive un nouveau programme.
fond(0,0,0)
drawText(10,10, "Hello World !")
update()
Les deux variantes peuvent également être combinées à volonté, en tenant compte du fait que les appels définis globalement ne sont exécutés que lors du premier démarrage du script ou lors du redémarrage du script.
Exemple:
fond(0,0,0)
drawText(10,10, "Écrire ceci une fois")
flip:bool
noStroke()
def onDraw():
flip = not flip
if flip:
fill(255,0,0)
else:
fill(0,255,0)
drawRectangle(10,80,220,80)
update()
delay(500)
Les quatre premières lignes de ce script ne sont exécutées que lors du premier démarrage. Ensuite, le gestionnaire d’événements démarre et exécute indéfiniment “onDraw()”.
Une variable est un espace réservé pour une valeur. On peut aussi appeler une variable un “tiroir” pour lequel de la place est réservée dans la mémoire de l’ordinateur afin de stocker une valeur quelconque.
Chaque variable possède un type de données qui permet de fixer la taille et le type de contenu. Ces deux éléments ne peuvent plus être modifiés après avoir été spécifiés une fois. Cette convention est appelée “typage statique”. Dans les langages typés dynamiquement, les mêmes noms de variables peuvent être déclarés à nouveau, ce qui permet d’avoir d’autres contenus, mais malheureusement, de nombreuses erreurs peuvent aussi se glisser.
La déclaration d’une variable est nécessaire, c’est-à-dire qu’avant de l’utiliser, il faut la définir. Il existe ici deux possibilités:
a = 10
b = true
c = 3.14
v = vector(x=10,y=20)
“a” est déclaré comme valeur int, b comme booléen, c comme float et v comme vector. La valeur détermine donc le type de données de la variable, sachant que pour les valeurs numériques, on utilise toujours au moins le type de données “int”.
a:int
b:byte
c:float
d:Rectangle
Tous les types de base et classes internes, ainsi que les classes personnalisées, peuvent être utilisés comme types de données.
Cas particulier des types de tableaux:
Si l’on souhaite obtenir plusieurs valeurs d’une variable, on peut indiquer le nombre de valeurs entre crochets.
points:int[10]
Ceci déclare une liste de points nommée “punkte”. La liste contient 10 entrées numérotées de 0 à 9.
Lors de l’attribution, il faut maintenant indiquer à chaque fois l’index, c’est-à-dire le numéro de l’entrée:
points[0] = 10
points[1] = 99
...
Le nombre d’éléments ne peut pas être modifié. Le nombre doit être un nombre, mais peut aussi être une constante:
const NOMBRE = 10
points:int[NOMBRE]
Tu trouveras plus d’informations sur les variables ici:
Il est également possible d’effectuer des opérations sur les bits sur Ganzahlen.
Les options suivantes sont disponibles:
nombre << n | Déplace le nombre bit par bit de n chiffres vers la gauche |
nombre >> n | Déplace le nombre bit par bit de n chiffres vers la droite |
nombre1 | nombre2 | Concaténation logique "ou" des deux nombres |
nombre1 & nombre2 | Concaténation logique "et" des deux nombres |
nombre1 ^ nombre2 | Logique exclusive de la combinaison "ou" des deux nombres. nombres (XOR) |
En décalant les nombres de n bits, le décalage vers la gauche correspond à une multiplication, le décalage vers la droite à une division par 2^n.
Quelques exemples:
0b00000001 << 1 = 0b00000010
0b10000000 >> 1 = 0b01000000
0b00000001 | 0b111111 = 0b111111
0b00000001 & 0b111111 = 0b00000001
0b00000001 ^ 0b111111 = 0b11111110
Dans le monde informatique, on utilise souvent le système décimal, mais aussi le système binaire et le système hexadécimal. Dans NanoPy, il est possible d’utiliser les trois systèmes.
En règle générale, nous utilisons le système décimal courant. Nous pouvons simplement attribuer les nombres comme valeur à une variable ou les utiliser dans des calculs:
a = 10
b = 4711
c = a / 5 - 10
La base de ces nombres est 10 et nous utilisons les “symboles” 0- 9.
Dans le système binaire, nous ne connaissons que 0 et 1. Dans NanoPy, les nombres binaires sont utilisés avec 0b.
a = 0b00001111
b = 0b0101
Il est également possible de calculer normalement avec des nombres binaires:
a = 10 + 0b00001111
Le troisième système de numération s’appelle l’hexadécimal. Ici, nous avons 16 symboles différents, qui est le système de seize. Nous complétons les chiffres de 0 à 9 par les lettres a - f (a=10, b=11, c = 12, etc.). Les nombres sont introduits par 0x:
a = 0xff
b = 0x10
Notez que 0x10 ne correspond PAS à la valeur décimale 10, mais à 16 !
Pour savoir comment les systèmes de numération sont convertibles entre eux, on peut consulter différentes sources sur youtube.
Un type de données définit l’étendue de la valeur d’une variable. En mathématiques, nous connaissons les nombres réels, entiers, naturels, rationnels et irrationnels. En informatique, il existe encore d’autres ensembles de ce type et on peut aussi définir les siens.
Types de données intégrés:
Type de données | plage de valeurs |
---|---|
byte | 0 à 255 |
int | -32768 à 32767 |
long | -2147483648 à 2147483647 |
float | 1.17549e-038 à 3.40282e+038 |
bool | true ou false |
Ces types de base peuvent être regroupés en compositions au moyen de classes. Par exemple, la classe vecteur (“vector”) contient deux variables de type “float” (x et y).
Les types de données intégrés suivants sont disponibles:
Type de données | Description |
---|---|
vector | Classe de vecteurs à deux dimensions avec des paramètres x et y (floats) et de nombreuses fonctions utiles de traitement des vecteurs. |
vector3D | Classe de vecteurs à trois dimensions avec des paramètres x, y et z (floats) et de nombreuses fonctions utiles de traitement des vecteurs. |
L’Oxocard peut également afficher des textes de différentes tailles sur l’écran.
Il y a plusieurs options à choisir pour la sortie du texte.
Dans le cas le plus simple, est suffisant pour appeler drawText():
drawText(10,10, "Hello World !")
update()
Les textes peuvent également être composés d’autres textes ou de chiffres, comme le montre cet exemple :
nom = "Leo"
drawText(10,10, "Mon nom est " + nom)
update()
L’exemple suivant montre l’heure actuelle lorsque le programme est exécuté :
background(0,0,0)
textFont(FONT_ROBOTO_24)
drawText(10,10, "Il est " + getHour() + " :" + getMinute())
update()
La boucle for permet de parcourir une liste d’éléments.
La structure est la suivante:
for variable in expression:
# instructions
“expression” peut être un nombre, une liste ou une variable.
Exemple 1:
push()
fond(0,0,0)
translate(120,120)
for i in 12:
rotate(PI/6)
drawCircle(80,0,10)
update()
pop()
Cet exemple dessine 12 cercles. Tout d’abord, le point d’origine est placé au centre de l’écran. A chaque passage de la boucle, le dessin est déplacé de 30 degrés dans le sens des aiguilles d’une montre et un cercle est dessiné.
Pour plus d’informations: voir Transformation de coordonnées et push() et pop().
La boucle peut aussi être initialisée avec une liste.
list = [1,20,80,100,80,20,1]
x = 20
fond(0,0,0)
fill(255,255,255)
for y dans list:
drawRectangle(x,240-y,20,240)
x = x+30
update()
Cet exemple dessine un diagramme à barres avec les valeurs de la liste qui ont été fixées ici.
L’exemple suivant initialise une liste de vecteurs:
vectors:vecteur[250]
for i in sizeof(vectors):
vectors[i].random()
vectors[i].mulScalar(random(5,180))
angle = 0.0
def onDraw():
push()
strokeWeight(5)
translate(120,120)
rotate(angle)
fond(0,0,0)
for i in sizeof(vectors):
strokeHSV(255,255,i%255)
drawLine(0,0,vectors[i].x,vectors[i].y)
update()
pop()
angle = angle + 0.05
Cet exemple déclare une liste (tableau) de 250 vecteurs. Tous ces vecteurs sont initialisés avec une direction arbitraire et ont une longueur aléatoire comprise entre 5 et 180 pixels.
Dans la procédure d’événement “onDraw”, ces vecteurs sont maintenant dessinés comme des lignes à partir du centre de l’écran. Après chaque passage, le centre est tourné de 0,05 radian.
Les boucles For sont à chaque fois réalisées avec la fonction:
sizeof(vecteurs)
est initialisée. La fonction “sizeof(…)” peut être appliquée à toutes les listes et renvoie le nombre d’éléments - dans ce cas 250.
Les instructions conditionnelles sont formulées à l’aide de l’instruction if.
La structure est la suivante:
if Ici se trouve une condition:
Voici les instructions qui seront exécutées,
si la condition est remplie.
elif Ici se trouve une autre condition:
si la deuxième condition est remplie, ce
bloc est exécuté.
else (ou autre):
Ici se trouvent les instructions qui sont exécutées alternativement.
Les parties elif/else sont facultatives et peuvent être omises. En outre, le bloc “elif” peut être indiqué plusieurs fois, le bloc “else” devant toujours se trouver à la fin (ou être omis).
Exemple:
def onDraw():
background(0,0,0)
r = random(0,5)
if r == 0:
drawText(10,10, "Zero")
elif r == 1:
drawText(10,10, "One")
else:
drawText(10,10, "Nothing")
update()
delay(1000)
Les opérateurs de comparaison suivants peuvent être utilisés:
Opérateurs de comparaison</td> | Description</td> </tr> |
---|---|
== | est égal à |
!= | n'est pas égal |
> | plus grand que |
>= | plus grand ou égal à |
< | plus petit que |
<= | inférieur ou égal à |
&& ou "and" | Et |
|| ou "or" | Ou |
not | Non |
Une procédure est une sorte d’instruction que l’ordinateur exécute lorsqu’on donne le nom de la procédure sous la forme “prozedur()”. est indiqué. Les parenthèses indiquent à l’ordinateur que nous voulons appeler une procédure et doivent toujours être indiquées. Entre les parenthèses, il est parfois nécessaire d’indiquer des valeurs, appelées paramètres. On trouve dans la documentation quelles sont ces valeurs ou si elles sont nécessaires. Les paramètres doivent toujours être indiqués avec précision, sinon la procédure ne peut pas fonctionner correctement et une erreur s’affiche.
Exemple de procédure sans paramètres:
returnToMenu()
Cette fonction termine le programme en cours et affiche à nouveau le menu. Exemple de procédure avec des paramètres:
drawPixel(50,100)
Cette fonction dessine un pixel à la coordonnée x= 50, y= 100.
Les procédures peuvent également renvoyer des valeurs. On parle alors de fonction.
Dans l’Oxocard, il existe de nombreuses procédures et fonctions internes que l’on peut utiliser. En outre, il est possible de construire ses propres fonctions. Des fonctions de classe sont également possibles. Voir l’entrée “Fonction”.
Les classes permettent de créer de nouveaux types de données. Ce terme est issu de la programmation orientée objet, qui permet de regrouper des objets dans une classe.
Nous pouvons par exemple définir une classe Point3D, qui stocke une coordonnée tridimensionnelle contenant une valeur x, y et z. Cette classe peut être utilisée pour créer des objets de type “point”.
classe Point3D:
x:float
y:float
z:float
def draw():
drawPixel(x+(z/2),y+(z/2))
La classe peut maintenant être utilisée comme un type de données normal:
p1:Point3D
p1 a maintenant trois variables intégrées x,y,z, que l’on peut définir et lire individuellement:
p1.x = 10
a = p1.y
etc...
Il est également possible d’utiliser l’initialisateur de classe:
p1 = Point3D(x=10,y=5,z=3)
Dans la documentation, on trouve une liste des classes internes qui sont déjà déclarées et peuvent être utilisées (“vector”, “color” et autres).
L’exemple suivant déclare une classe “Circle” (cercle). Ce qui est spécial ici, c’est que la variable de classe “pos” a de nouveau un type de classe.
classe Cercle:
pos:vector
size:int
def init(x:int,y:int,s:int):
pos.x = x
pos.y = y
size = s
def draw():
drawCircle(pos.x,pos.y,size)
Nous pouvons maintenant définir la variable Circle “c” et appeler les fonctions définies:
c:Cercle
c.init(120,120,10)
c.draw()
Structure générale:
class Noms de classe:
Variable1
Variable2
Variable ...
...
Fonction1
Fonction2
Fonction ...
Notes importantes:
Le concept orienté objet de l’héritage des variables et des fonctions n’est pas implémenté. C’est pourquoi les classes sont plutôt à qualifier de composants. De plus, il n’y a pas encore de constructeurs/déstructeurs dans la version préliminaire d’NanoPy.
Une procédure événementielle est une fonction spéciale que l’on ne doit pas appeler soi-même, mais que le système appelle automatiquement à des moments précis. Nous utilisons principalement la fonction “onClick()”, qui est appelée par le système chaque fois qu’une touche est enfoncée, et “onDraw()”, que l’ordinateur appelle lorsqu’il n’y a rien d’autre à faire.