Donnez vie à votre jeu avec une balle qui rebondit contre les bords de l'écran
Cette fois ça prend vie, votre programme bouge tout seul ! Les prémices de votre jeu de raquettes sont là.
Durée 20 minutes (et plus si affinité)
A l'étape précédente vous avez fait un compteur d'invités. Vous stockiez sa valeur dans une variable de type int
qu'on avait décidé d'appelercounter
(logique !). On avait des conditions if
pour changer la valeur du compteur lorsque l'on appuyait sur les boutons. Et finalement, on affichait un rectangle dont la position dépendait de la valeur de notre variable.
Si on résume, vous faisiez bouger un rectangle à l'écran en appuyant sur les boutons. On n'est pas loin d'avoir une raquette de pong ;) Mais un Pong sans balle c'est pas bien fun, c'est pourquoi on va maintenant faire une balle rebondissante.
Dans le cas de notre balle rebondissante, il serait plus approprié d'appeler la variable positionX
que counter
, pour mieux refléter ce à quoi elle sert : stocker la position de la balle suivant l'axe horizontal X. On en profite pour ajouter une variable speedX
qui va servir à stocker la vitesse horizontale de la balle.
Ensuite, la balle va avancer d'elle-même, pas besoin de condition if
avec les boutons. On aurait donc quelque chose comme ça.
#include <Gamebuino-Meta.h>
int positionX = 32;
int speedX = 1;
void setup() {
gb.begin();
}
void loop() {
while (!gb.update());
gb.display.clear();
positionX = positionX + speedX;
gb.display.print("positionX: ");
gb.display.print(positionX);
gb.display.print("\nspeedX: ");
gb.display.print(speedX);
gb.display.fillRect(positionX, 32, 4, 4);
}
Quand vous avez appris à utiliser un graphique, vous avez sûrement vu quelque chose comme ça, où le centre est là où X et Y sont nuls, et les X et Y grandissent quand on se déplace vers le haut et vers la droite. Mais pour les écrans, ça ne marche pas tout à fait comme ça.
Les coordonnées sur l'écran de la Gamebuino META, comme n'importe quel autre écran, commencent en haut à gauche. En plus, les valeurs selon l'axe Y augmentent quand on descend (selon l'axe X, les valeurs augmentent vers la droite, comme sur un graphique classique).
Donc le coin à l'opposé - en bas à droite - a pour coordonnées (gb.display.width() - 1, gb.display.height() - 1
).
Mais pourquoi est ce qu'on a soustrait 1 pour obtenir le coin en bas à droite ? C'est parce que le premier pixel (en haut à gauche) est en position (0, 0), et non en position (1, 1). Pour mieux comprendre pourquoi ce fait change tout, imaginons que notre écran avait seulement 4 pixels et que le premier avait comme coordonnée 0. Dans ce cas, quel serait la coordonnée du 4ème (dernier) pixel?
Ici, on voit facilement que le dernier pixel a une coordonnée de 3, et non de 4. Eh bien la même chose se passe avec l'écran de la Gamebuino ! Les pixels de droite ont une coordonnée X égale à gb.display.width() - 1
. De la même manière, les pixels du bas ont une coordonnée Y de gb.display.height() - 1
.
Remarque : L'écran fait 80 pixels de large par 64 pixels de haut. Vous pouvez vérifier la largeur avec gb.display.print(gb.display.width());
ou en comptant ;). Cependant, même si vous connaissez les dimensions de l'écran, il ne faut pas écrire 80
là où on peut mettre gb.display.width()
, car c'est moins explicite et est une sorte d'offuscation légère.
Puisque nous parlons de l'écran de positionnement, j'en profite pour approfondir l'utilisation degb.display.drawRect()
. Voici sa structure (que l'on a déjà vu) :
gb.display.drawRect(int x, int y, int largeur, int hauteur);
Tout comme l'écran, les X
et y
sont passés par paramètres. Ce sont les coordonnées du coin en haut à gauche de notre rectangle. Donc on peut calculer la position de l'angle en bas à droite, et on obtient (x + largeur - 1, y + hauteur - 1
).
Maintenant que nous avons vu tout ça, essayez d'afficher la balle plus haute sur l'écran. Essayez aussi de l'afficher tout en bas de l'écran :)
Essayons notre petit jeu et voyons ce qu'il se passe... Hé, mais la balle ne s'arrête pas ! Normal, on n'a mis aucune condition. Elle continue donc d'avancer, même en dehors de l'écran. Comment est-ce qu'on pourrait faire pour corriger ça ? Voilà la logique à avoir, en pseudo-code:
Si la balle atteint le bord droit
Alors aller à gauche
Si la balle atteint le bord gauche
Alors aller à droite
Deux questions se posent alors...
Je vais vous donner la solution, mais vous devriez essayer d'y réfléchir un peu avant de regarder.
Quelques indices : essayez de jouer avec la valeur de speedX
pour faire varier la vitesse.
Qu'est ce qui se passe avec une vitesse de 2, de 3 ? Une vitesse négative ?
Maintenant que vous avez trouvé le truc pour faire aller la balle à gauche (n'est-ce pas ?), vous n'avez plus qu'à détecter quand positionX
atteint le bord de l'écran. Les coordonnées horizontales en X peuvent varier de0
à gb.display.width()
. Une valeur de 0 correspond au bord gauche de l'écran et une valeur de gb.display.width()
correspond au bord droit.
Vous avez maintenant tous les éléments pour faire rebondir la balle de gauche à droite :)
Si vous bloquez, voilà un coup de pouce.
#include <Gamebuino-Meta.h>
int positionX = 32;
int speedX = 1;
void setup() {
gb.begin();
}
void loop() {
while (!gb.update());
gb.display.clear();
positionX = positionX + speedX;
// Si la balle atteint ou dépasse le bord gauche
if(positionX < 0){
// On part à droite
speedX = 1;
}
// Si la balle atteint ou dépasse le bord droit
if(positionX > gb.display.width()){
// On part à gauche
speedX = -1;
}
gb.display.print("positionX: ");
gb.display.print(positionX);
gb.display.print("\nspeedX: ");
gb.display.print(speedX);
gb.display.fillRect(positionX, 32, 4, 4);
}
Si la balle ne bouge qu'à l'horizontal, ça ne va pas être très excitant comme partie de Pong. Pourquoi ne pas créer de nouvelles variables positionY
et speedY
pour permettre à la balle de bouger verticalement ? Il faudra aussi des conditions pour détecter le bord de l'écran, cette fois avec gb.display.height()
qui donne la hauteur de l'écran.
Faites nous rêver sur les réseaux sociaux avec #gamebuino #bouncingball , on vous suit de près ;)
Si vous êtes en panne d'inspiration, voilà ce qu'on a fait de notre côté :)
#include <Gamebuino-Meta.h>
int positionX = 32;
int speedX = 2;
int positionY = 32;
int speedY = 1;
int ballSize = 8;
void setup() {
gb.begin();
}
void loop() {
while (!gb.update());
gb.display.clear();
// Mise à jour de la position horizontale
positionX = positionX + speedX;
// Si la balle atteint le bord gauche
if(positionX < 0){
// On part à droite
speedX = 2;
}
// Si la balle atteint le bord droit
if(positionX > gb.display.width() - ballSize){
// On part à droite
speedX = -2;
}
// Mise à jour de la position verticale
positionY = positionY + speedY;
// Si la balle atteint le bord haut
if(positionY < 0){
// On part en bas
speedY = 1;
}
// Si la balle atteint le bord bas
if(positionY > gb.display.height() - ballSize){
// On part en haut
speedY = -1;
}
gb.display.setColor(BROWN);
gb.display.print("positionX: ");
gb.display.print(positionX);
gb.display.print("\nspeedX: ");
gb.display.print(speedX);
gb.display.print("\npositionY: ");
gb.display.print(positionY);
gb.display.print("\nspeedY: ");
gb.display.print(speedY);
gb.display.setColor(WHITE);
gb.display.fillRect(positionX, positionY, ballSize, ballSize);
}