Balle rebondissante

Étape 3
Étape terminée ?

Donnez vie à votre jeu avec une balle qui rebondit contre les bords de l'écran

  • Conditions "If else"
  • Utiliser les variables pour créer le mouvement
  • Vérifier les collisions
  • Faire rebondir la balle !

Cette fois ça prend vie, votre programme bouge tout seul ! Les prémices de votre jeu de raquettes sont là.

Boïng boïng, ça rebondit de partout

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

A l'étape précédente vous avez fait un compteur que vous pouviez réinitialiser, incrémenter ou décrémenter. Vous stockiez sa valeur dans une variable que l'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 transformer notre rectangle pour en faire une balle rebondissante.

Aller de l'avant

Dans le cas de notre balle rebondissante, il sera 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.


À propos de l'écran

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 (getWidth() - 1, getHeight() - 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 à getWidth() - 1. De la même manière, les pixels du bas ont une coordonnée Y de getHeight() - 1.

Remarque : L'écran fait 160 pixels de large par 128 pixels de haut. Vous pouvez vérifier la largeur avec text(getWidth(), 2,2); ou en comptant ;). Cependant, même si vous connaissez les dimensions de l'écran, il ne faut pas écrire 179 là où on peut mettre getWidth(), 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 derect(). Voici sa structure (que l'on a déjà vu) :

rect(ix, y, largeur, hauteur);

Ce qui donne un schéma de ce type pour: rect(28,15,25,60);

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 :)

Garder la balle en vue

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...

  • Comment faire pour que la balle aille à gauche ?
  • Comment savoir quand on a atteint le bord de l'écran ?

Essayez de trouver dans un premier temps et essayez de faire le code pour y arriver avant que Je vous donne la solution. 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 à getWidth() - 1. Une valeur de 0 correspond au bord gauche de l'écran et une valeur de getWidth() - 1 correspond au bord droit.

Vous avez maintenant tous les éléments pour faire rebondir la balle de gauche à droite :)

Si vous bloquez, ou après que vous ayez trouvé votre solution, lisez la solution que je vous donne. Ce n'est pas la bonne solution, c'est une solution qui fonctionne parmi d'autre. Si la vautre vous convient, c'est parfait, c'est la votre et elle prouve

let positionX = 32;
let speedX = 1;


function init() {
    setFont(R.fontKarateka); 
}

function update(time) {
    positionX = positionX + speedX;
    if(positionX < 0){
				// Si la balle atteint ou dépasse le bord gauche alors on repart à droite
        speedX = 1;
    } else if(positionX > (getWidth() - 4)){
				// Si la balle atteint ou dépasse le bord droit  alors on repart à gauche
				// Note: on retire 4 car le bord droit de la balle est 4 pixels après sa position
        speedX = -1;
    }
}

function render() {
    setPen(0,0,0);
    clear();
    setPen(255,255,255); // White
    text("positionX: " + positionX, 0, 2); 
    text("speedX: " + speedX, 95,2);
    setPen(200,150,100); // Gamebuino Brown
    rect(positionX, 32, 4, 4);
}

À vous de jouer !

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 getHeight() qui donne la hauteur de l'écran.

Exemple de solution

Si vous êtes en panne d'inspiration, voilà ce qu'on a fait de notre côté :)

let positionX = 32;
let positionY = 32;
let speedX = 2;
let speedY = 1;
let ballSize = 8;

function init() {
    setFont(R.fontKarateka); 
}

function update(time) {

    // gère le déplacement en X
    positionX = positionX + speedX;
    // Si la balle atteint ou dépasse le bord gauche
    if(positionX < 0){
        // On part à droite
        speedX = -speedX;
    }

    if(positionX > (getWidth() - ballSize)){
		// Si la balle atteint ou dépasse le bord droit on repart à gauche
		// Note: on retire 4 car le bord droit de la balle est 4 pixels après sa position
		speedX = -speedX;
    }
		
		// gère la position en Y
		positionY = positionY + speedY;
    
    if(positionY < 0){
		// Si la balle atteint ou dépasse le bord haut
		// On part vers le bas
		speedY = -speedY;
    } else if(positionY > (getHeight() - ballSize)){
	    // Si la balle atteint ou dépasse le bord droit, on repart à gauche
		// Note: on retire 4 car le bord droit de la balle est 4 pixels après sa position
		speedY = -speedY;   
    }
}

function render() {
    setPen(0,0,0);
    clear();
    setPen(255,255,255); // White
    text("positionX: " + positionX, 0, 2); 
    text("speedX: " + speedX, 95,2);
    text("positionY: " + positionY, 0, 15); 
    text("speedY: " + speedY, 95,15);
    setPen(200,150,100); // Gamebuino Brown
    rect(positionX, positionY, ballSize, ballSize);
}

Étapes