Compteur d'invités

Créations

Aurélien Rodot

il y a 6 ans

Découvrez les variables, les structures conditionnelles si et l'affichage de rectangles.

Faites un outil pour compter des invités, du stock ou des moutons

Durée 20 minutes (et plus si affinité)

Niveau débutant total

Prérequis

Notre objectif est de faire un petit compteur d'invités, qui ajoute +1 quand on appuie sur haut, et qui enlève 1 quand on appuie sur bas. On peut trouver ce type de compteur (habituellement mécanique) à l'entrée des événements pour compter le nombre d'entrées. On peut aussi retrouver un code similaire dans un jeu pour compter le nombre de mouvements d'un joueur par exemple. Il va donc falloir stocker la valeur du compteur dans une variable et la faire changer si on appuie sur les boutons.

Les variables

Vous partez du squelette de programme que nous venons de découvrir avec "hello, world", avec quelques modifications:

#include <Gamebuino-Meta.h>

int counter = 0;  // Nouvelle ligne

void setup() {
  gb.begin();

}

void loop() {
  while (!gb.update());
  gb.display.clear();

  gb.display.print(counter);  // Quelque chose a changé ici :)
}

Regardons plus en détail les modifications qu'on a fait au programme:

int counter = 0;

Cette ligne déclare et initialise une variable que l'on affiche à l'écran dans loop:

counter est une variable qui mémorise la valeur du compteur. Une variable est un espace dans la mémoire de la Gamebuino pour stocker temporairement une donnée. Il peut s'agir du score actuel, de l'image d'un personnage, du texte d'un dialogue ou encore l'ensemble de la carte d'un jeu de plateforme. Lorsque l'on éteint la console, la valeur est perdue.

On lui donne une valeur initiale, ici 0 avec l'opérateur =. Nous verrons plus tard comment sauvegarder des données sur la carte micro SD.

Une variable a un nom, ici on a choisi de prendre counter. Il faut un nom qui décrit bien ce à quoi elle sert pour que le code reste lisible. En utilisant des variables qui s'appellent a, b et c, on a vite fait de se mélanger les pinceaux.

Une variable contient un type de donnée, ici int, abréviation de integer en anglais, ce qui veut dire "entier". On peut donc y stocker un nombre sans virgule, positif ou négatif, comme par exemple 0, 1, 5 ou -34.

Ici, l'instruction ne se situe pas dans une fonction (les fonctions sont délimitées par des accolades { }). En effet, en C/C++ on peut placer des instructions hors des fonctions. Ces instructions seront lus et exécutées par la Gamebuino de haut en bas une fois au démarrage. Cependant, seules les instructions sont exécutées de cette manière (je vous rappelle que toutes instructions finissent par un point-virgule ;, et donc les fonctions, comme setup et loop, ne sont pas des instructions).


gb.display.print(counter);

On a déjà vu dans "hello, world" que print permet d'afficher une chaîne de caractères. Ce qu'on ne vous a pas dit, c'est qu'elle permet également d'afficher des integer, dans ce cas notre variable qui s'appelle counter.

if - La structure conditionnelle

Jusqu'ici rien ne bouge, ce n'est pas très palpitant. Comme son nom l'indique, une variable peut changer de valeur. Avant de commencer le code, je vais vous montrer la logique que l'on veut obtenir en pseudo-code. Ce n'est pas du code qui peut être compilé, mais il permet de facilement expliquer un algorithme:

Si on appuie sur "haut" (UP)
Alors on ajoute 1 à "counter"

Si on appuie sur "bas" (DOWN)
Alors on enlève 1 à "counter"

Si on appuie sur "menu" (MENU)
Alors on met "counter" à 0

Ici, on cherche un algorithme qui fait simplement varier la valeur de counter avec les flèches HAUT et BAS. On veut aussi que le bouton MENU remette counter à zéro. Vous voyez, rien de compliqué ? Le si s'utilise comme ça en C++:

if (condition) {
  // Faire des choses
}

Les bilingues parmi vous auront remarqué que if veut dire si, ça tombe bien ;) Si la condition est vraie, alors on exécute toutes les instructions qui se trouvent entre les accolades { }. Voilà comment ça se traduit en langage Gamebuino. Je ne vous donne que le bouton HAUT, à vous de faire le reste !

#include <Gamebuino-Meta.h>

int counter = 0;

void setup() {
  gb.begin();

}

void loop() {
  while (!gb.update());
  gb.display.clear();

  if (gb.buttons.pressed(BUTTON_UP)) {  // Si on appuie sur "haut"
    counter = counter + 1;    // On ajoute 1 à "counter"
    gb.sound.playTick();    // On joue un son
  }  // Fin du si

  gb.display.print(counter);
  gb.display.fillRect(counter, 8, 2, 4);
}

A vous de jouer!

Je vous laisse ajouter le code nécessaire pour que les boutons BAS et MENU remplissent leur rôle, comme décrit dans le pseudo-code plus haut. Si vous avez un doute sur la syntaxe (l'orthographe du code), vous pouvez aller vérifier dans la Référence. Mais pour cette fois je suis sympa, je vous donne les noms des boutons qu'il vous faut: BUTTON_DOWN et BUTTON_MENU.


gb.sound.playTick();

J'en ai profité pour ajouter deux petites nouveautés. gb.sound.playTick permet de jouer un son prédéfini "tick". Comme on l'a mis dans la condition if, le son est joué quand le bouton est appuyé.



gb.display.fillRect(x, y, w, h);

La fonction gb.display.fillRect permet de tracer un rectangle. Vous remarquerez qu'elle a plusieurs paramètres, séparés par des virgules , il est important d'avoir le bon nombre de paramètres et dans le bon ordre. Encore une fois, tout est détaillé dans la Référence, mais je vous explique rapidement :

  • x est la coordonnée horizontale du rectangle, en partant de la gauche de l'écran. Dans notre cas, counter.
  • y est la coordonnée verticale du rectangle, en partant du haut de l'écran. Dans notre cas, 8, soit 8 pixels.
  • w est la largeur du rectangle en pixels, dans notre cas 2
  • h est la hauteur du rectangle en pixels, dans notre cas 4

Il vous reste donc à ajouter la fonctionnalité des différents boutons, et surtout personnaliser votre compteur ! Pourquoi pas changer la position, la taille et la couleur du rectangle ? Ou changer l'opération pour multiplier et diviser par 2 au lieu de faire +1 et -1 ? Attention de partir de 1 dans ce cas, car 0 * 2 = 0 hehe

Partagez vos créations sur les réseaux avec #gamebuino #tallycounter , on vous suit de près ;)

Remarques sur le C/C++

Un ordinateur (comme votre Gamebuino) peut exécuter des instructions très rapidement, mais il les fait bêtement. Il va suivre tout ce que vous lui dites à la lettre, littéralement. Donc la syntaxe et la logique de chaque instruction est assez stricte. Il y a deux catégories d'erreurs: les erreurs de syntaxe et les erreurs de logiques. Les erreurs de syntaxe sont détectées lors de la compilation, et donc vous ne pourrez pas charger votre programme. Les erreurs de logique ne seront pas détectées, donc votre programme compilera et votre Gamebuino l'exécutera. Mais le programme ne fera pas ce que vous vouliez.

Pour réparer les erreurs de syntaxe, on peut s'aider du texte en rouge qui nous est fournis lors de la compilation. Voici quelques exemples récurrents:

Les accolades { }

C'est une erreur qu'on retrouve beaucoup chez les débutants. Les accolades viennent toujours par paires. Il se peut que vous en oubliez une ou que vous en mettez une de trop, dans les deux cas, le compilateur ne sera pas content car il y aura une accolade qui est seule :( Pour vous aidez, mettez votre curseur sur une accolade ouvrante, l'accolade qui la ferme sera encadrée automatiquement (et vise-versa). Rappel: les if et les fonctions doivent avoir des accolades.

Le point-virgule ;


Chaque instruction doit finir avec un point-virgule. Cette erreur est souvent facilement réparable.

Si vous bloquez sur une erreur et que vous n'arrivez pas à la résoudre, venez demander un coup de main sur discord ;)


Exemple de solution

Parmi l'infinité de compteurs possible, voici le notre pour vous inspirer!

#include <Gamebuino-Meta.h>

int counter = 0;

void setup() { gb.begin(); }

void loop() { while (!gb.update()); gb.display.clear();

if(gb.buttons.pressed(BUTTON_UP)){ counter = counter + 1; gb.sound.playOK(); }

if(gb.buttons.pressed(BUTTON_DOWN)){ counter = counter - 1; gb.sound.playCancel(); }

if(gb.buttons.pressed(BUTTON_MENU)){ counter = 0; gb.sound.playTick(); }

gb.display.setColor(BROWN); gb.display.fillRect(0, 0, counter, gb.display.height());

gb.display.setColor(WHITE); gb.display.setFontSize(4); gb.display.setCursor(8,8); gb.display.print(counter); }



Vous êtes maintenant prêts à débuter votre jeu de Pong avec l'atelier suivant !

Atelier suivant

Par Aurélien Rodot, modifié par Julien Giovinazzo

Voir la création

Nux

NEW il y a 6 ans

Bien mieux que l'ancien. La nouvelle structure des Tuto avec les prérequis au début et une solution original et coloré à la fin est aussi bien pensé.

STUDIOCRAFTapps

NEW il y a 6 ans

Je crois que les type int sont en fait des uint64_t et non des int32_t comme il était sur le CPU de la Gamebuino Classic donc "On peut donc y stocker un nombre sans virgule, positif ou négatif." n'est pas vrai.

Basé selon mes experience personnel lorsque j'ai adapté mon jeu vers la META

Nan finalement les int ce n'est pas usigned

Lemmy

NEW il y a 6 ans

Salut tout le monde!  

J'aimerai creuser un peu l'idée du compteur et, par exemple, faire en sorte que le nombre à l'écran s'allume vert quand on appuie sur "haut" et rouge quand on appuie sur "bas"... je ne sais pas trop comment faire je me suis dit que ça serait facile mais en fait ça ne l'est pas (pour moi -_-).


#include <Gamebuino-Meta.h>

int counter = 0;

void setup() {
   gb.begin();
}

void loop() {
  while (!gb.update());
  gb.display.clear();

  if (gb.buttons.pressed(BUTTON_UP)) {
    counter = counter + 1;
    gb.display.setColor(GREEN);
    gb.display.print(counter);
    gb.sound.playOK();
    
  }

  if (gb.buttons.pressed(BUTTON_DOWN)) {
    counter = counter - 1;

    gb.display.setColor(RED);
    gb.display.print(counter);
    gb.sound.playCancel();
    
  }

  if (gb.buttons.pressed(BUTTON_MENU)) {
    counter = 0;
    gb.sound.playTick();
  }

  gb.display.setColor(BROWN);
  gb.display.fillRect(0, 0, counter, gb.display.height());

  gb.display.setColor(WHITE);
  gb.display.setFontSize(4);
  gb.display.setCursor(8,8);
  gb.display.print(counter);
}


Le problème ici c'est que ça me l'affiche en vert ou rouge mais en petit dans le coin supérieur gauche. (normal vu que je n'ai précisé ni la taille ni l'emplacement mais si je le fait ça ne fonctionne pas..  J'ai en fait l'impression que l'affichage du compteur (en vert ou rouge) passe "derrière" le compteur blanc ainsi que le rectangle marron. Faut-il dire "d'enlever" le compteur blanc le temps que l'autre est affiché ou quelque chose comme ça ?

geed

il y a 6 ans

C'est EXACTEMENT ça, imagine que la console affiche les choses dans l'ordre où tu lui demandes. Dans ton programmes tu changes la couleur AVANT de lui demander d'afficher ton compteur en blanc. Du coup, elle le change bien de couleur, mais le ré-affiche par dessus en blanc.


Perso je conditionnerai l'affichage du compteur.

C'est à dire que d'abord je fais mes calculs, puis dessine le "fond" et enfin je lui demanderai quelque chose du genre :

Si la précédente valeur est :

  • inférieure à la nouvelle, alors sélectionne le  vert
  • supérieure à la nouvelle, alors  sélectionne le rouge
  • identique, alors  sélectionne le blanc


Je te laisse méditer ces pistes, voir commencer à imaginer de petites fonctions pour le faire.

Perso je suis aussi débutant en programmation et je fonctionne comme ça : 1) je divise le problème en petits problèmes faciles 2) je code des petites fonctions qui les résolvent 3) j'assemble le tout :p

clement

il y a 6 ans

je rajouterais que ton code est executer 25X par seconde. ton compteur vert ou rouge sera afficher uniquement 1/25 X du coup presque invisible.

Tu dois creer une variable pour sauvegarder la couleur courante de ton compteur 

geed

NEW il y a 6 ans

Lemmy Lemmy

C'est EXACTEMENT ça, imagine que la console affiche les choses dans l'ordre où tu lui demandes. Dans ton programmes tu changes la couleur AVANT de lui demander d'afficher ton compteur en blanc. Du coup, elle le change bien de couleur, mais le ré-affiche par dessus en blanc.


Perso je conditionnerai l'affichage du compteur.

C'est à dire que d'abord je fais mes calculs, puis dessine le "fond" et enfin je lui demanderai quelque chose du genre :

Si la précédente valeur est :

  • inférieure à la nouvelle, alors sélectionne le  vert
  • supérieure à la nouvelle, alors  sélectionne le rouge
  • identique, alors  sélectionne le blanc


Je te laisse méditer ces pistes, voir commencer à imaginer de petites fonctions pour le faire.

Perso je suis aussi débutant en programmation et je fonctionne comme ça : 1) je divise le problème en petits problèmes faciles 2) je code des petites fonctions qui les résolvent 3) j'assemble le tout :p

clement

NEW il y a 6 ans

Lemmy Lemmy

je rajouterais que ton code est executer 25X par seconde. ton compteur vert ou rouge sera afficher uniquement 1/25 X du coup presque invisible.

Tu dois creer une variable pour sauvegarder la couleur courante de ton compteur 

Lemmy

NEW il y a 6 ans

Geed ton enthousiasme fait plaisir à voir ! :D Je vois et vais essayer de partir dans ce sens là. Je vous retransmettrais mon nouveau code :)

Et Clément ce que tu dis j'y ai pensé aussi,1/25s c'est pas si pire, je veux vraiment que ça clignote mais si je peux le faire durer 2/25s voir 3/25s ça peut-être vraiment cool mais la... ça dépasse tout entendement pour mon niveau ! :)

Lemmy

NEW il y a 6 ans

Alors.. j'ai le bon affichage, à la bonne taille, etc mais ça s'affiche à côté de la valeur "blanche" du compteur. J'ai pas suivi le fonctionnement que tu m'a proposé Geed parce que j'avoue que je sais pas trop comment m'y prendre.. Dois-je continuer sur cette lancée ou aborder d'une autre manière ?

Si je continue sur ce que j'ai mit y a-t-il une solution de demander d'afficher la valeur verte ou rouge à la place de la blanche? Je ne sais pas trop comment faire... 


#include <Gamebuino-Meta.h>

int counter = 0;

void setup() {
   gb.begin();
}

void loop() {
  while (!gb.update());
  gb.display.clear();

  if (gb.buttons.pressed(BUTTON_UP)) {
    counter = counter + 1;
    gb.sound.playOK();
    
  }

  if (gb.buttons.pressed(BUTTON_DOWN)) {
    counter = counter - 1;
    gb.sound.playCancel();
    
  }

  if (gb.buttons.pressed(BUTTON_MENU)) {
    counter = 0;
    gb.sound.playTick();
  }

  gb.display.setColor(BROWN);
  gb.display.fillRect(0, 0, counter, gb.display.height());

  gb.display.setColor(WHITE);
  gb.display.setFontSize(4);
  gb.display.setCursor(8,8);
  gb.display.print(counter);


  if (gb.buttons.pressed(BUTTON_DOWN)) {
  gb.display.setColor(RED);
  gb.display.print(counter);

}

  if (gb.buttons.pressed(BUTTON_UP)) {
  gb.display.setColor(GREEN);
  gb.display.print(counter);

}
}

clement

NEW il y a 6 ans

en fait tu n a pas besoin de reecrire le counter.

l idee c est au moment ou tu choisi la couleur ( a la ligne gb.display.setColor(WHITE);) tu doit choisir entre le rouge le vert ou le blanc

donc en mata code : 


si mon bouton haut est appuyer
     je choisi le vert
sinon si mon bouton bas est appuyer
    je choisi le rouge
sinon 
   je choisi le blanc


Pour cela tu doit te pencher sur le else  je ne sais pas si il y a des exemple dans les tuto Gamebuino mais tu trouvera facilement comment ca marche sur google.




Aurélien Rodot

il y a 6 ans

Bientôt, bientôt, je suis justement en train d'écrire la suite :)

Mais ça fait plaisir de voir que c'est utilisé, que certains vont au delà et que tout le monde s'entraide. Keep it up ! :D

Lemmy

NEW il y a 6 ans

Ça ne marche pas, je suis à deux doigts d'aller chercher une masse afin de mieux faire comprendre à mon mac ce que je veux faire.. XD


J'ai été obligé de réécrire tout le conter pour qu'il apparaisse.

Si je met "if..." "else..." "else..." pour le deuxième "else" il me dit que ce n'est pas correct si il n'y a pas de "if" avant. Et avec ce code là quand j'appuie sur "haut" je vois le compteur qui clignote mais c'est trop rapide.. Impossible de dire s'il s'affiche en vert (il faut que je rallonge le temps d'affichage mais je ne sais pas comment) et par contre quand j'appuie sur "bas" le compteur change mais ne clignote pas.

Au moins il y a déjà l'affichage en vert qui fonctionne (peut-être) on va dire que c'est une avancée!

Voila ce que j'ai fait:

#include <Gamebuino-Meta.h>

int counter = 0;

void setup() {
   gb.begin();
}

void loop() {
  while (!gb.update());
  gb.display.clear();

  if (gb.buttons.pressed(BUTTON_UP)) {
    counter = counter + 1;
    gb.sound.playOK();
    
  }

  if (gb.buttons.pressed(BUTTON_DOWN)) {
    counter = counter - 1;
    gb.sound.playCancel();
    
  }d

  if (gb.buttons.pressed(BUTTON_MENU)) {
    counter = 0;
    gb.sound.playTick();
  }

  gb.display.setColor(BROWN);
  gb.display.fillRect(0, 0, counter, gb.display.height());

  if (gb.buttons.pressed(BUTTON_DOWN)) {
  gb.display.setColor(RED);
  gb.display.setFontSize(4);
  gb.display.setCursor(8,8);
  gb.display.print(counter);

}

  if (gb.buttons.pressed(BUTTON_UP)) {
  gb.display.setColor(GREEN);
  gb.display.setFontSize(4);
  gb.display.setCursor(8,8);
  gb.display.print(counter);

}
  else (gb.display.setColor(WHITE));
  gb.display.setFontSize(4);
  gb.display.setCursor(8,8);
  gb.display.print(counter);


}

geed

il y a 6 ans

C'est juste un problème de syntaxe ! Pas besoin de sortir la masse :)

regarde du côté des exemple sur l'arduino IDE, section CONTROL, tu verras que le else à une structure du type if (machin) { alors } else { bidule }

https://www.arduino.cc/reference/en/


Moi à ta place, je contournerai le problème, peut être avec une deuxième variable qui passe à 1 2 ou 3 en fonction de ce que tu fais. Et en fonction de la valeur de cette variable, tu changes l'affichages. Par exemple :)

Regarde aussi du côté de la fonction Switch (bidule) {


Et bon courage ! Ne décroche pas !



clement

il y a 6 ans

oui tu ne peux pas mettre de else sur un seul if...

mais tu peux remetre un if dans un else 


Le switch que propose geed peux etre une bonne solution.


pour evité des problèmes a ton mac voici la syntax qui fonctionne du if / else qui fonctionnera pour ton cas. reste plus qu a mettre les bonne conditions dedans 

if() {
} else if () {
} else {
}  

Aurélien Rodot

NEW il y a 6 ans

clement clement

Bientôt, bientôt, je suis justement en train d'écrire la suite :)

Mais ça fait plaisir de voir que c'est utilisé, que certains vont au delà et que tout le monde s'entraide. Keep it up ! :D

geed

NEW il y a 6 ans

Lemmy Lemmy

C'est juste un problème de syntaxe ! Pas besoin de sortir la masse :)

regarde du côté des exemple sur l'arduino IDE, section CONTROL, tu verras que le else à une structure du type if (machin) { alors } else { bidule }

https://www.arduino.cc/reference/en/


Moi à ta place, je contournerai le problème, peut être avec une deuxième variable qui passe à 1 2 ou 3 en fonction de ce que tu fais. Et en fonction de la valeur de cette variable, tu changes l'affichages. Par exemple :)

Regarde aussi du côté de la fonction Switch (bidule) {


Et bon courage ! Ne décroche pas !



clement

NEW il y a 6 ans

Lemmy Lemmy

oui tu ne peux pas mettre de else sur un seul if...

mais tu peux remetre un if dans un else 


Le switch que propose geed peux etre une bonne solution.


pour evité des problèmes a ton mac voici la syntax qui fonctionne du if / else qui fonctionnera pour ton cas. reste plus qu a mettre les bonne conditions dedans 

if() {
} else if () {
} else {
}  

Lemmy

NEW il y a 6 ans

Merci, je vais essayer d'avancer la dessus ! :)


Edit:

Après une semaine sans toucher ma Gamebuino faute de temps :( j'ai suivi ton conseil Clement, et, même si je ne sais pas pourquoi ça fonctionne maintenant ! =)


#include <Gamebuino-Meta.h>

int counter = 0;

void setup() {
   gb.begin();
}

void loop() {
  while (!gb.update());
  gb.display.clear();

  if (gb.buttons.pressed(BUTTON_UP)) {
    counter = counter + 1;
    gb.sound.playOK();
    
  }

  if (gb.buttons.pressed(BUTTON_DOWN)) {
    counter = counter - 1;
    gb.sound.playCancel();
    
  }


if(gb.buttons.pressed(BUTTON_MENU)) {
    counter = 0;
    gb.sound.playTick();
  }

  gb.display.setColor(BROWN);
  gb.display.fillRect(0, 0, counter, gb.display.height());

  if (gb.buttons.pressed(BUTTON_DOWN)) {
  gb.display.setColor(RED);
  gb.display.setFontSize(4);
  gb.display.setCursor(8,8);
  gb.display.print(counter);

} 
  
  else if (gb.buttons.pressed(BUTTON_UP)) {
  gb.display.setColor(GREEN);
  gb.display.setFontSize(4);
  gb.display.setCursor(8,8);
  gb.display.print(counter);

}
  
  else {gb.display.setColor(WHITE));
  gb.display.setFontSize(4);
  gb.display.setCursor(8,8);
  gb.display.print(counter);


}


J'aimerais encore faire quelques modifications comme par exemple rallonger la durée de couleur rouge ou verte mais je ne sais pas comment..

et aussi j'aimerai ajouter un "flash" mais je ne connais pas la "fonction" ?? pour allumer les led "gb.display.lesledcestjoliquandcestallumé" par exemple.. :)


Vous avez déjà été formidables avec tous vos conseils mais j'en veux plus !! 

Nicolas

NEW il y a 6 ans

Hello ! Super tuto :) 

Au début il est écrit "Lorsque l'on éteint la console, la valeur est perdue." Comment faire justement pour garder en mémoire la valeur ? J'ai bien envie de faire un compteur qui peut me servir dans le temps et donc ne pas perdre la valeur ;-) 

J'ai été regarder dans la référence, et j'ai vu qu'il y avait une rubrique "save" :

gb.save.config  
gb.save.get 
gb.save.set  
gb.save.del

Merci pour vos conseils !

Sorunome

il y a 6 ans

Yes, you save values using the gb.save stuff, that will actually store the values on the micro SD card. You can find more on how to do that here: https://gamebuino.com/creations/gamebuino-save-format

Sorunome

NEW il y a 6 ans

Nicolas Nicolas

Yes, you save values using the gb.save stuff, that will actually store the values on the micro SD card. You can find more on how to do that here: https://gamebuino.com/creations/gamebuino-save-format

Nicolas

il y a 6 ans

Merci !

Je viens de faire un test et je pense que je ne vois pas bien comment sauvegarder la valeur avec gb.save

Voici mon code :

#include <Gamebuino-Meta.h>

int compteur = 0;


void setup() {
  gb.begin();

}

void loop() {
  while (!gb.update());
  gb.display.clear();



  if (gb.buttons.pressed(BUTTON_UP)) {  
    compteur = compteur + 1;    
    gb.sound.playOK(); 
  } 


  gb.display.print(compteur);

  gb.save.get(compteur);

}

J'ai bien ajouté gb.save.get avec la variable "compteur".

Merci pour le coup de pouce !