Structurer les objets de votre programme
Vous avez ajouté votre premier adversaire en lui donnant de l'intelligence artificielle, le jeu est jouable alors commençons à nous structurer pour le prochain qui sera plus compliqué.
Durée : 30 minutes (et plus si affinité)
Niveau : débutant (mais bon plus tant que ça déjà)
Prérequis :
- Avoir une Gamebuino META
- Avoir fait l'atelier Installation de la Gamebuino META
- Avoir fait les ateliers hello, world, compteur d'invités, balle rebondissante, Pong (deux joueurs) et Artifical intelligence (Pong); Tap tap
Dans l'atelier précédent, Artificial intelligence (Pong), vous avez ajouté un adversaire à votre jeu en lui programmant un comportement. Nous avions également rajouté une seconde raquette qui avait les mêmes propriétés que la première mais avec des valeurs différentes.
Avant de compliquer un peu le programme, nous allons voir une autre façon de coder ses propriétés d’un objet : les structures
Les structures
Vous pouvez créer vos propres types de variables. Des « types de variables personnalisés » permettant de de s’y retrouver plus facilement quand on cherche à faire des programmes plus complexes.
En effet dans les tutoriaux, on a bien pris soin d’utiliser des noms parlant comme balle_posX ou balle_posY, mais une autre solution consiste à utiliser un « objet » balle ayant des propriétés définies.
Définir une structure
Une structure est un assemblage de variables qui peuvent avoir différents types : long, char, int, double, …
Une définition de structure commence par le mot-clé struct, suivi du nom de votre structure (par exemple s_balle, ou s_raquette).
On peut également adopter des règles de nommage pour ces structures. Par exemple, on peut choisir de mettre la première lettre en majuscule pour pouvoir faire la différence ou lui mettre un préfixe (par exemple s_).
Après le nom de votre structure, vous ouvrez les accolades et les fermez plus loin, comme pour une fonction.
Attention, ici c'est particulier : vous DEVEZ mettre un point-virgule après l'accolade fermante.
Vous ajoutez ensuite les variables dont est composée votre structure.
Faisons un exemple complet :
Pour la balle, nous utilisions 5 variables :
// Caractéristiques de la balle int balle_posX = 20; int balle_posY = 20; int balle_speedX = 1; int balle_speedY = 1; int balle_taille = 3;
Nous allons les transformer en structure, nous allons donc définir son nom en tant que s_balle et y mettre 5 variables de type entier : posX, posY, vitesseX, vitesseY et taille, ce qui nous donne le code suivant :
// Définition des structures balles et raquette struct s_balle{int posX; int posY; int vitesseX; int vitesseY; int taille;};
Comme vous le voyez, la création d'un type de variable personnalisé n'est pas bien complexe. Toutes les structures que vous verrez sont en fait des « assemblages » de variables de types définis (long, int, double, etc…)
OK, on a défini une structure mais bon on n’a toujours pas de valeur et pour cause, on doit maintenant définir une variable de ce type que l’on pourra alors initialiser, mais voyons ça plus en détail…
Utiliser une structure
Maintenant que notre structure s_balle est définie, on va pouvoir l'utiliser en créant une variable de ce type :
// Définition des objets utilisant les structures définies s_balle balle;
Nous avons ainsi créé une variable balle de type s_balle. Cette variable est automatiquement composée de cinq sous-variables : posX, posY, vitesseX, vitesseY et taille (respectivement son abscisse, son ordonnée, sa vitesse latérale, sa vitesse horizontale et sa taille en pixels).
Maintenant que notre variable balle est créée, nous voulons modifier ses coordonnées.
Comment accéder aux variable posX et posY de la variable balle?
Comme ceci :
// Caractéristiques de la balle balle.posX = 20; balle.posY = 20;
On a ainsi modifié balle, en lui donnant une abscisse de 20 et une ordonnée de 20.
Pour accéder donc à chaque composante de la structure, vous devez écrire :
variable.nomDeLaComposante
Le point sert de séparation entre la variable et la composante à laquelle on souhaite accéder.
Pour les structures comme pour les variables, l'initialisation peut également se faire un peu comme pour un tableau en enchainant entre accolades les valeurs des composantes, séparées par des virgules dans l’ordre de leur déclaration.
Pour la balle, cela nous donnerait donc :
// Définition des objets utilisant les structures définies s_balle balle = {20, 20, 1, 1, 3};
Cela définira, dans l'ordre, de déclaration les composantes de l’objet, c’est-à-dire posX, posY, vitesseX, vitesseY et taille.
Synthèse avec le programme Pong
A vous de jouer: Essayez d’utiliser ce que l’on vient de voir pour déclarer 1 structure raquette et de l'utiliser pour la raquette gauche et la raquette de droite.
Solution
Note: La solution utilise aussi les constantes vues dans le tutoriel: Tap tap
#include
// Définition des constantes
#define EspaceBordRaquette 10
#define HauteurRaquette 10
#define LargeurRaquette 3
#define MargeInitialeBalleX 20
#define MargeInitialeBalleY 20
// Définition des structures balles et raquette
struct s_balle{int posX; int posY; int vitesseX; int vitesseY; int taille;};
struct s_raquette{int posX; int posY; int largeur; int hauteur; int vitesse;};
// Définition des objets utilisant les structures définies
s_balle balle = {MargeInitialeBalleX,MargeInitialeBalleY,1,1,3};
s_raquette raquetteAGauche = {EspaceBordRaquette,((gb.display.height()-HauteurRaquette) / 2),LargeurRaquette,HauteurRaquette,0};
s_raquette raquetteADroite = {(gb.display.width() - EspaceBordRaquette - LargeurRaquette),((gb.display.height()-HauteurRaquette) / 2),LargeurRaquette,HauteurRaquette,0};
// Scores
int scoreGauche; // Score du joueur 1
int scoreDroite; // Score du joueur 2
int difficulte = 3; // Niveau de difficulté. 3 = FACILE et 2 = DIFFICILE
void setup() {
gb.begin();
}
void loop() {
while (!gb.update());
gb.display.clear();
// Changement de difficulté
if (gb.buttons.pressed(BUTTON_MENU)) {
if (difficulte == 3) { // Facile
difficulte = 2; // Changer de difficulté
}
else { // Difficile
difficulte = 3; // Changer de difficulté
}
}
// MAJ raquetteAGauche
if (gb.buttons.repeat(BUTTON_UP, 0)) {
raquetteAGauche.posY = raquetteAGauche.posY - 1;
}
if (gb.buttons.repeat(BUTTON_DOWN, 0)) {
raquetteAGauche.posY = raquetteAGauche.posY + 1;
}
// MAJ raquetteADroite - Intelligence Artificielle
if (balle.posY > raquetteADroite.posY + raquette_hauteur / 2 && random(0, difficulte) == 1) {
raquetteADroite.vitesse = 2;
} else if (balle.posY < raquetteADroite.posY + raquette_hauteur / 2 && random(0, difficulte) == 1) {
raquetteADroite.vitesse = -2;
}
raquetteADroite.posY = raquetteADroite.posY + raquetteADroite.vitesse; // Mettre à jour la position de la raquetteADroite
// MAJ balle
balle.posX = balle.posX + balle.vitesseX;
balle.posY = balle.posY + balle.vitesseY;
// Collisions avec les murs (haut et bas)
if (balle.posY < 0) {
balle.vitesseY = 1;
}
if (balle.posY > gb.display.height() - balle_taille) {
balle.vitesseY = -1;
}
// Collision balle/raquetteAGauche
if ( (balle.posX == raquetteAGauche.posX + raquette_largeur)
&& (balle.posY + balle_taille >= raquetteAGauche.posY)
&& (balle.posY <= raquetteAGauche.posY + raquette_hauteur) ) {
balle.vitesseX = 1;
}
// Collision balle/raquetteADroite
if ( (balle.posX + balle_taille == raquetteADroite.posX)
&& (balle.posY + balle_taille >= raquetteADroite.posY)
&& (balle.posY <= raquetteADroite.posY + raquette_hauteur) ) {
balle.vitesseX = -1;
}
// Vérifier si la balle est sortie de l'écran
if (balle.posX < 0) {
// Replacer la balle sur l'écran
balle.posX = MargeInitialeBalleX;
balle.posY = random(MargeInitialeBalleY, gb.display.height() - MargeInitialeBalleY); // Position aléatoire au centre de l'écran
balle.vitesseX = 1;
if (random(0, 2) == 1) { // 50% du temps
balle.vitesseY = 1;
}
else { // 50% du temps
balle.vitesseY = -1;
}
// incrémenter le score du joueur 2
scoreDroite = scoreDroite + 1;
}
if (balle.posX > gb.display.width()) {
// Replacer la balle sur l'écran
balle.posX = MargeInitialeBalleX;
balle.posY = random(MargeInitialeBalleY, gb.display.height() - MargeInitialeBalleY); // Position aléatoire au centre de l'écran
balle.vitesseX = 1;
if (random(0, 2) == 1) { // 50% du temps
balle.vitesseY = 1;
}
else { // 50% du temps
balle.vitesseY = -1;
}
// incrémenter le score du joueur 1
scoreGauche = scoreGauche + 1;
}
// Afficher la balle
gb.display.fillRect(balle.posX, balle.posY, balle_taille, balle_taille);
// Afficher la raquetteAGauche
gb.display.fillRect(raquetteAGauche.posX, raquetteAGauche.posY, raquetteAGauche.largeur, raquetteAGauche.hauteur);
// Afficher la raquetteADroite
gb.display.fillRect(raquetteADroite.posX, raquetteADroite.posY, raquetteADroite.largeur, raquetteADroite.hauteur);
// Afficher les scores
gb.display.setCursor(35, 5);
gb.display.print(scoreGauche);
gb.display.setCursor(42, 5);
gb.display.print(scoreDroite);
// Afficher la difficulté
gb.display.setCursor(33, gb.display.height() - 5);
if (difficulte == 3) {
gb.display.print("Facile");
}
else {
gb.display.print("Difficile");
}
}