Découvrons les fonctions et leur usage
Avant de commencer à implémenter les œufs et les carottes, regardons ce qu'est une fonction.
Les fonctions sont un aspect très important du C++, elles vous permettent de découper votre code en blocs réutilisables. Les fonctions sont très pratiques car elles nous laissent répartir notre code sur plusieurs fichiers (nous y viendrons dans un instant) et de s'organiser. setup() et loop() sont des fonctions par exemple. Vous avez créé ces fonctions et Arduino les appelle automatiquement.
Mais vous pouvez créer et appeler vos propres fonctions.
Ce que nous allons faire, c'est de créer nos 3 parties (entrées / mise à jour / affichage) sous forme de 3 fonctions. Ainsi notre boucle loop() ressemblera à ça :
void loop() {
while(!gb.update());
entrees();
miseAJour();
affichage();
}
En quoi c'est utile ? Bonne question car en fin de compte, avec ou sans fonctions, cela revient à la même chose non ? Et c'est bien vrai, à chaque fois que vous appelez une fonction, cela revient exactement à copier-coller le code de la fonction là où vous l'avez appelé. Mais le but des fonctions est d'organiser le code (vous avez peut-être remarqué que ce chapitre se focalise beaucoup la-dessus). Les fonctions permettent aussi d'exécuter la même suite d'instructions à plusieurs endroits dans le programme. En réalité, vous utilisez des fonctions depuis le tout premier atelier ! Toutes les fonctions dans la page référence sont... des fonctions, notamment :
Si à chaque fois que vous avez à utiliser une de ces fonctions vous aviez tapé tout le code qui se cache derrière... Vous en seriez encore au début de la première étape ! En plus, si nous trouvons un bug dans une des fonctions, il suffit juste de corriger la fonction et vous n'avez pas besoins d'intervenir. Bref, les fonctions sont nos amies.
Mais comment en créer une ?
type nomDeFonction() {
// Code de la fonction ici
}
Pour définir une fonction, il suffit de faire comme ci-dessus. Là où vous trouvez type
, on doit y mettre le type de retour de la fonction. En effet les fonctions peuvent "retourner" une valeur avec le mot clé return
. Par exemple :
// Ici on définit la fonction //
int aireDuPanier() {
return panierLargeur * PANIER_HAUTEUR; // retourner l'aire du panier
}
// Autre part dans notre code //
int aire = aireDuPanier();
Attention, le mot "return" termine la fonction. C'est-à-dire que tout ce que vous mettez après return
ne sera même pas exécuté.
Mais maintenant, vous allez me dire: Mais les fonctions setup()
et loop()
ont void
comme type de retour. Qu'est-ce que c'est que cevoid
? C'est vrai que void
n'est pas un type. C'est justement l'absence de type. Dire qu'une fonction retourne void
signifie qu'elle ne retourne rien. Comme vous pouvez le voir, setup()
et loop()
n'utilisent jamais le mot return
.
Nous allons mettre nos trois fonctions dans trois autres fichiers. C'est mieux pour nous d'avoir plusieurs fichiers de taille modérée, qu'un seul fichier gigantesque. De cette manière, nous pourrons retrouver notre code bien plus rapidement. Pour créer un fichier, il suffit de cliquer sur la petite flèche en haut à droite de l'IDE, puis sur "Nouvel onglet"
Il faut savoir que Arduino lira tous les fichiers dans un certain ordre. Mais il commencera toujours par le fichier ayant les fonctions setup()
et loop()
("Attrapoeuf.ino" dans mon cas). Il faut donc déclarer toutes les variables globales dans ce fichier-là, comme ça, toutes les fonctions y auront accès.
C'est parti pour découper notre programme en plusieurs fichiers !
Attrapoeuf.ino
Pas la peine de le créer, il existe déjà !
#include <Gamebuino-Meta.h>
// Panier
int panierX = 20; // Le panier peut bouger horizontalement, donc ce n'est pas une constante
const int PANIER_Y = gb.display.height() - 4; // Constante car le panier est fixe selon l'axe Y
int panierLargeur = 0; // Pas constant car la taille dépend de la nourriture restante
const int PANIER_HAUTEUR = 3; // Constante
int score = 0;
int highscore = 0;
int nourriture; // Plus de nourriture est mieux. 0 nourriture = game over
void setup() {
gb.begin();
nourriture = 300;
}
void loop() {
while(!gb.update());
entrees();
miseAJour();
affichage();
}
entrees.ino
// entrees.ino //
void entrees() {
if (gb.buttons.repeat(BUTTON_LEFT, 0) && panierX > 0) {
panierX -= 2;
}
else if (gb.buttons.repeat(BUTTON_RIGHT, 0) && panierX < gb.display.width() - panierLargeur) {
panierX += 2;
}
}
miseAJour.ino
void miseAJour() {
// La nourriture fait doucement baisser notre nourriture dans la panier
nourriture--;
panierLargeur = nourriture / 20;
// Somme nous mort par manque de nourriture??
if (nourriture <= 0) {
score = 0; // Recommencer le jeu
nourriture = 300; // Reset nourriture
}
}
affichage
// affichage.ino //
void affichage() {
gb.display.clear();
// Panier
gb.display.setColor(WHITE);
gb.display.fillRect(panierX, PANIER_Y, panierLargeur, PANIER_HAUTEUR);
// Score
gb.display.setColor(WHITE);
gb.display.setCursor(gb.display.width() - 8, 0);
gb.display.print(score);
gb.display.setColor(RED);
gb.display.setCursor(gb.display.width() - 8, 8);
gb.display.print(highscore);
}
En une étape nous avons vu comment créer des fonctions et comment découper notre programme. Nous avons créé des fonctions pour chaque partie
entrees()
miseAJour()
affichage()
Chacune d'elles est consignée dans un fichier : c'est plus clair, plus aéré et pas besoin de défiler des kilomètres pour chercher !