X-B-1. Support de travail▲
Cette fois-ci on doit travailler sur la version finale du jeu. (Sachez que dans les versions corrigées des différentes classes, tous les caractères accentués auront été remplacés.)
Je vous repasse donc les fichiers de la version finale du jeu de ping-pong, tel qu'il a été défini à la fin du chapitre (sans les accents).
package support_travail_exercice_2;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public class TableVertePingPong extends JPanel
implements ConstantesDuJeu {
private JLabel label;
private int raquetteOrdinateur_Y =
RAQUETTE_ORDINATEUR_Y_DEPART;
private int raquetteEnfant_Y = RAQUETTE_ENFANT_Y_DEPART;
private int balle_X = BALLE_X_DEPART;
private int balle_Y = BALLE_Y_DEPART;
Dimension taillePreferee = new
Dimension(LARGEUR_TABLE, HAUTEUR_TABLE);
public Dimension getPreferredSize() {
return taillePreferee;
}
TableVertePingPong() {
MoteurJeuPingPong moteurJeu =
new MoteurJeuPingPong(this);
addMouseMotionListener(moteurJeu);
addKeyListener(moteurJeu);
}
void ajouteAuCadre(Container conteneur) {
conteneur.setLayout(new BoxLayout(conteneur,
BoxLayout.Y_AXIS));
conteneur.add(this);
label = new JLabel(
"Taper N pour une nouvelle partie, S pour servir" +
" ou Q pour quitter");
conteneur.add(label);
}
public void paintComponent(Graphics contexteGraphique) {
super.paintComponent(contexteGraphique);
contexteGraphique.setColor(Color.GREEN);
contexteGraphique.fillRect(
0, 0, LARGEUR_TABLE, HAUTEUR_TABLE);
contexteGraphique.setColor(Color.yellow);
contexteGraphique.fillRect(
RAQUETTE_ENFANT_X,
raquetteEnfant_Y,
LARGEUR_RAQUETTE, LONGUEUR_RAQUETTE);
contexteGraphique.setColor(Color.blue);
contexteGraphique.fillRect(RAQUETTE_ORDINATEUR_X,
raquetteOrdinateur_Y,
LARGEUR_RAQUETTE, LONGUEUR_RAQUETTE);
contexteGraphique.setColor(Color.red);
contexteGraphique.fillOval(balle_X, balle_Y, 10, 10);
contexteGraphique.setColor(Color.white);
contexteGraphique.drawRect(10, 10, 300, 200);
contexteGraphique.drawLine(160, 10, 160, 210);
requestFocus();
}
public void positionnerRaquetteEnfant_Y(int y) {
this.raquetteEnfant_Y = y;
repaint();
}
public int coordonneeRaquetteEnfant_Y() {
return raquetteEnfant_Y;
}
public void positionnerRaquetteOrdinateur_Y(int y) {
this.raquetteOrdinateur_Y = y;
repaint();
}
public void affecterTexteMessage(String texte) {
label.setText(texte);
repaint();
}
public void positionnerBalle(int x, int y) {
balle_X = x;
balle_Y = y;
repaint();
}
public static void main(String[] args) {
JFrame monCadre = new JFrame("Table verte de ping-pong");
monCadre.setDefaultCloseOperation(
WindowConstants.EXIT_ON_CLOSE);
TableVertePingPong table = new TableVertePingPong();
table.ajouteAuCadre(monCadre.getContentPane());
monCadre.setBounds(0, 0, LARGEUR_TABLE + 5,
HAUTEUR_TABLE + 40);
monCadre.setVisible(true);
}
}
package support_travail_exercice_2;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
public class MoteurJeuPingPong implements Runnable,
MouseMotionListener, KeyListener, ConstantesDuJeu {
private TableVertePingPong table;
private int raquetteEnfant_Y = RAQUETTE_ENFANT_Y_DEPART;
private int raquetteOrdinateur_Y =
RAQUETTE_ORDINATEUR_Y_DEPART;
private int scoreEnfant;
private int scoreOrdinateur;
private int balle_X;
private int balle_Y;
private boolean deplacementGauche = true;
private boolean balleServie = false;
private int deplacementVertical;
public MoteurJeuPingPong(TableVertePingPong tableVerte) {
table = tableVerte;
Thread travailleur = new Thread(this);
travailleur.start();
}
public void mouseDragged(MouseEvent evenement) {
}
public void mouseMoved(MouseEvent evenement) {
int souris_Y = evenement.getY();
if (souris_Y < raquetteEnfant_Y &&
raquetteEnfant_Y > HAUT_TABLE) {
raquetteEnfant_Y -= INCREMENT_RAQUETTE;
} else if (raquetteEnfant_Y < BAS_TABLE) {
raquetteEnfant_Y += INCREMENT_RAQUETTE;
}
table.positionnerRaquetteEnfant_Y(raquetteEnfant_Y);
}
public void keyPressed(KeyEvent evenement) {
char touche = evenement.getKeyChar();
if ('n' == touche || 'N' == touche) {
demarrerNouvellePartie();
} else if ('q' == touche || 'Q' == touche) {
terminerJeu();
} else if ('s' == touche || 'S' == touche) {
serviceEnfant();
}
}
public void keyReleased(KeyEvent evenement) {}
public void keyTyped(KeyEvent evenement) {}
public void demarrerNouvellePartie() {
scoreOrdinateur = 0;
scoreEnfant = 0;
table.affecterTexteMessage("Scores - Ordinateur : 0"
+ "Enfant : 0");
serviceEnfant();
}
public void terminerJeu(){
System.exit(0);
}
public void run() {
boolean rebondPossible = false;
while (true) {
if (balleServie) {
if (deplacementGauche && balle_X > BALLE_X_MIN) {
rebondPossible = (balle_Y >= raquetteOrdinateur_Y
&& balle_Y < (raquetteOrdinateur_Y +
LONGUEUR_RAQUETTE) ? true : false);
balle_X -= INCREMENT_BALLE;
balle_Y -= deplacementVertical;
table.positionnerBalle(balle_X, balle_Y);
if (balle_X <= RAQUETTE_ORDINATEUR_X
&& rebondPossible) {
deplacementGauche = false;
}
}
if (!deplacementGauche && balle_X <= BALLE_X_MAX) {
rebondPossible = (balle_Y >= raquetteEnfant_Y &&
balle_Y < (raquetteEnfant_Y +
LONGUEUR_RAQUETTE) ? true : false);
balle_X += INCREMENT_BALLE;
table.positionnerBalle(balle_X, balle_Y);
if (balle_X >= RAQUETTE_ENFANT_X &&
rebondPossible) {
deplacementGauche = true;
}
}
if (raquetteOrdinateur_Y < balle_Y
&& raquetteOrdinateur_Y < BAS_TABLE) {
raquetteOrdinateur_Y += INCREMENT_RAQUETTE;
} else if (raquetteOrdinateur_Y > HAUT_TABLE) {
raquetteOrdinateur_Y -= INCREMENT_RAQUETTE;
}
table.positionnerRaquetteOrdinateur_Y(
raquetteOrdinateur_Y);
try {
Thread.sleep(DUREE_SOMMEIL);
} catch (InterruptedException exception) {
exception.printStackTrace();
}
if (balleSurLaTable()) {
if (balle_X > BALLE_X_MAX ) {
scoreOrdinateur++;
afficherScore();
} else if (balle_X < BALLE_X_MIN) {
scoreEnfant++;
afficherScore();
}
}
}
}
}
private void serviceEnfant() {
balleServie = true;
balle_X = RAQUETTE_ENFANT_X - 1;
balle_Y = raquetteEnfant_Y;
if (balle_Y > HAUTEUR_TABLE / 2) {
deplacementVertical = -1;
} else {
deplacementVertical = 1;
}
table.positionnerBalle(balle_X, balle_Y);
table.positionnerRaquetteEnfant_Y(raquetteEnfant_Y);
}
private void afficherScore() {
balleServie = false;
if (scoreOrdinateur == SCORE_GAGNANT) {
table.affecterTexteMessage("L'ordinateur a gagne ! " +
scoreOrdinateur +
" : " + scoreEnfant);
} else if (scoreEnfant == SCORE_GAGNANT) {
table.affecterTexteMessage ("Tu as gagne ! "+
scoreEnfant +
" : " + scoreOrdinateur);
} else {
table.affecterTexteMessage ("Ordinateur : "+
scoreOrdinateur +
" Enfant: " + scoreEnfant);
}
}
private boolean balleSurLaTable() {
if (balle_Y >= BALLE_Y_MIN && balle_Y <= BALLE_Y_MAX) {
return true;
} else {
return false;
}
}
}
package support_travail_exercice_2;
public interface ConstantesDuJeu {
public final int LARGEUR_TABLE = 320;
public final int HAUTEUR_TABLE = 220;
public final int HAUT_TABLE = 12;
public final int BAS_TABLE = 180;
public final int INCREMENT_BALLE = 4;
public final int BALLE_X_MIN = 1 + INCREMENT_BALLE;
public final int BALLE_Y_MIN = 1 + INCREMENT_BALLE;
public final int BALLE_X_MAX =
LARGEUR_TABLE - INCREMENT_BALLE;
public final int BALLE_Y_MAX =
HAUTEUR_TABLE - INCREMENT_BALLE;
public final int BALLE_X_DEPART = LARGEUR_TABLE / 2;
public final int BALLE_Y_DEPART = HAUTEUR_TABLE / 2;
public final int RAQUETTE_ENFANT_X = 300;
public final int RAQUETTE_ENFANT_Y_DEPART = 100;
public final int RAQUETTE_ORDINATEUR_X = 15;
public final int RAQUETTE_ORDINATEUR_Y_DEPART = 100;
public final int INCREMENT_RAQUETTE = 2;
public final int LONGUEUR_RAQUETTE = 30;
public final int LARGEUR_RAQUETTE = 5;
public final int SCORE_GAGNANT = 21;
public final int DUREE_SOMMEIL = 10;
}
X-B-2. Correction possible▲
Cet exercice ne présente pas de difficulté particulière.
Une manière simple de procéder consiste à vérifier, au moment où l'utilisateur appuie sur la touche S (que ce soit en minuscule ou en majuscule), que les scores du joueur et de l'ordinateur sont inférieurs au score gagnant. Et l'on sait que c'est dans la méthode keyPressed de la classe MoteurJeuPingPong qu'est effectuée la gestion des touches.
Enfin par prudence on peut déplacer l'étape 4 de la méthode run(), celle qui consiste à faire sommeiller le Thread, juste en dehors de la condition if (balleServie). Donc juste au début de la boucle while(true). De cette manière, si le service n'a pas été effectué, on sera quand même en mesure de faire le Thread se reposer un peu et éviter qu'il ne bloque tout.
Voici donc la nouvelle version de MoteurJeuPingPong.java :
MoteurJeuPingPong amélioré
package exercice2;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
public class MoteurJeuPingPong implements Runnable,
MouseMotionListener, KeyListener, ConstantesDuJeu {
private TableVertePingPong table;
private int raquetteEnfant_Y = RAQUETTE_ENFANT_Y_DEPART;
private int raquetteOrdinateur_Y =
RAQUETTE_ORDINATEUR_Y_DEPART;
private int scoreEnfant;
private int scoreOrdinateur;
private int balle_X;
private int balle_Y;
private boolean deplacementGauche = true;
private boolean balleServie = false;
private int deplacementVertical;
public MoteurJeuPingPong(TableVertePingPong tableVerte) {
table = tableVerte;
Thread travailleur = new Thread(this);
travailleur.start();
}
public void mouseDragged(MouseEvent evenement) {
}
public void mouseMoved(MouseEvent evenement) {
int souris_Y = evenement.getY();
if (souris_Y < raquetteEnfant_Y &&
raquetteEnfant_Y > HAUT_TABLE) {
raquetteEnfant_Y -= INCREMENT_RAQUETTE;
} else if (raquetteEnfant_Y < BAS_TABLE) {
raquetteEnfant_Y += INCREMENT_RAQUETTE;
}
table.positionnerRaquetteEnfant_Y(raquetteEnfant_Y);
}
public void keyPressed(KeyEvent evenement) {
char touche = evenement.getKeyChar();
if ('n' == touche || 'N' == touche) {
demarrerNouvellePartie();
} else if ('q' == touche || 'Q' == touche) {
terminerJeu();
} else if ('s' == touche || 'S' == touche) {
if (scoreEnfant < SCORE_GAGNANT && scoreOrdinateur < SCORE_GAGNANT){
serviceEnfant();
}
}
}
public void keyReleased(KeyEvent evenement) {}
public void keyTyped(KeyEvent evenement) {}
public void demarrerNouvellePartie() {
scoreOrdinateur = 0;
scoreEnfant = 0;
table.affecterTexteMessage("Scores - Ordinateur : 0"
+ " Enfant : 0");
serviceEnfant();
}
public void terminerJeu(){
System.exit(0);
}
public void run() {
boolean rebondPossible = false;
while (true) {
try {
Thread.sleep(DUREE_SOMMEIL);
} catch (InterruptedException exception) {
exception.printStackTrace();
}
if (balleServie) {
if (deplacementGauche && balle_X > BALLE_X_MIN) {
rebondPossible = (balle_Y >= raquetteOrdinateur_Y
&& balle_Y < (raquetteOrdinateur_Y +
LONGUEUR_RAQUETTE) ? true : false);
balle_X -= INCREMENT_BALLE;
balle_Y -= deplacementVertical;
table.positionnerBalle(balle_X, balle_Y);
if (balle_X <= RAQUETTE_ORDINATEUR_X
&& rebondPossible) {
deplacementGauche = false;
}
}
if (!deplacementGauche && balle_X <= BALLE_X_MAX) {
rebondPossible = (balle_Y >= raquetteEnfant_Y &&
balle_Y < (raquetteEnfant_Y +
LONGUEUR_RAQUETTE) ? true : false);
balle_X += INCREMENT_BALLE;
table.positionnerBalle(balle_X, balle_Y);
if (balle_X >= RAQUETTE_ENFANT_X &&
rebondPossible) {
deplacementGauche = true;
}
}
if (raquetteOrdinateur_Y < balle_Y
&& raquetteOrdinateur_Y < BAS_TABLE) {
raquetteOrdinateur_Y += INCREMENT_RAQUETTE;
} else if (raquetteOrdinateur_Y > HAUT_TABLE) {
raquetteOrdinateur_Y -= INCREMENT_RAQUETTE;
}
table.positionnerRaquetteOrdinateur_Y(
raquetteOrdinateur_Y);
if (balleSurLaTable()) {
if (balle_X > BALLE_X_MAX ) {
scoreOrdinateur++;
afficherScore();
} else if (balle_X < BALLE_X_MIN) {
scoreEnfant++;
afficherScore();
}
}
}
}
}
private void serviceEnfant() {
balleServie = true;
balle_X = RAQUETTE_ENFANT_X - 1;
balle_Y = raquetteEnfant_Y;
if (balle_Y > HAUTEUR_TABLE / 2) {
deplacementVertical = -1;
} else {
deplacementVertical = 1;
}
table.positionnerBalle(balle_X, balle_Y);
table.positionnerRaquetteEnfant_Y(raquetteEnfant_Y);
}
private void afficherScore() {
balleServie = false;
if (scoreOrdinateur == SCORE_GAGNANT) {
table.affecterTexteMessage("L'ordinateur a gagne ! " +
scoreOrdinateur +
" : " + scoreEnfant);
} else if (scoreEnfant == SCORE_GAGNANT) {
table.affecterTexteMessage ("Tu as gagne ! "+
scoreEnfant +
" : " + scoreOrdinateur);
} else {
table.affecterTexteMessage ("Ordinateur : "+
scoreOrdinateur +
" Enfant : " + scoreEnfant);
}
}
private boolean balleSurLaTable() {
if (balle_Y >= BALLE_Y_MIN && balle_Y <= BALLE_Y_MAX) {
return true;
} else {
return false;
}
}
}
On peut s'y prendre de plusieurs manières pour ajuster le niveau de jeu. Ici, nous nous contenterons d'ajuster la vitesse de déplacement de la raquette du joueur en fonction du niveau.
Pour cela, la formule suivante est utilisée :
incrémentRaquetteJoueur = INCREMENT_RAQUETTE + 20 ? 2*niveauJoueur
Si l'on prend la valeur 2 pour INCREMENT_RAQUETTE, on aura notamment les valeurs suivantes :
| niveauJoueur |
incrementRaquetteJoueur |
| 1 |
20 |
| 5 |
12 |
| 10 |
2 |
Ainsi, la vitesse sera la plus élevée pour le niveau 1 et la plus faible pour le niveau 10.
Dans le fichier ConstantesDeJeu, on élargit la hauteur du composant table verte, afin d'y ajouter un nouveau panneau pour le choix du niveau. Mais on y définit aussi les niveaux minimum et maximum.
package ex_malins_1;
public interface ConstantesDuJeu {
public final int LARGEUR_TABLE = 320;
public final int HAUTEUR_TABLE = 260;
public final int HAUT_TABLE = 12;
public final int BAS_TABLE = 180;
public final int INCREMENT_BALLE = 4;
public final int BALLE_X_MIN = 1 + INCREMENT_BALLE;
public final int BALLE_Y_MIN = 1 + INCREMENT_BALLE;
public final int BALLE_X_MAX =
LARGEUR_TABLE - INCREMENT_BALLE;
public final int BALLE_Y_MAX =
HAUTEUR_TABLE - INCREMENT_BALLE;
public final int BALLE_X_DEPART = LARGEUR_TABLE / 2;
public final int BALLE_Y_DEPART = HAUTEUR_TABLE / 2;
public final int RAQUETTE_ENFANT_X = 300;
public final int RAQUETTE_ENFANT_Y_DEPART = 100;
public final int RAQUETTE_ORDINATEUR_X = 15;
public final int RAQUETTE_ORDINATEUR_Y_DEPART = 100;
public final int INCREMENT_RAQUETTE = 2;
public final int LONGUEUR_RAQUETTE = 30;
public final int LARGEUR_RAQUETTE = 5;
public final int SCORE_GAGNANT = 21;
public final int DUREE_SOMMEIL = 10;
public final int NIVEAU_MIN = 1;
public final int NIVEAU_MAX = 10;
}
On peut ajouter une méthode publique fixerNiveauDeJeu() dans la classe MoteurDeJeu afin de permettre à la classe TableVertePingPong de le modifier.
Dans la classe TableVertePingPong, on va ajouter une JComboBox permettant de choisir le niveau. On implémente l'interface ItemListener dans la classe TableVertePingPong afin de réagir au choix d'un élément de la JComboBox. Elle se compose de la méthode unique itemStateChanged().
Vous remarquerez l'appel à
où i est de type int. Ceci permet simplement de convertir un entier en chaîne de caractères. La méthode valueof est aussi surchargée pour accepter un boolean, un char...
Enfin, une précaution est prise, dans la méthode itemStateChanged(), pour vérifier que l'on réponde bien à un évènement de sélection et non de désélection : car quand on choisit un élément, l'écouteur de type ItemListener réagit deux fois consécutives. L'une pour la désélection de l'élément précédent et l'autre pour la sélection du nouvel élément. Ceci par le biais du code suivant :
if (event.getStateChange() == ItemEvent.SELECTED) {
où event est le paramètre de la méthode itemStateChanged().
Voici le code de la nouvelle version de TableVertePingPong.java :
package ex_malins_1;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.BoxLayout;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public class TableVertePingPong extends JPanel
implements ConstantesDuJeu, ItemListener {
private MoteurJeuPingPong moteurJeu;
private JLabel label;
private int raquetteOrdinateur_Y =
RAQUETTE_ORDINATEUR_Y_DEPART;
private int raquetteEnfant_Y = RAQUETTE_ENFANT_Y_DEPART;
private int balle_X = BALLE_X_DEPART;
private int balle_Y = BALLE_Y_DEPART;
Dimension taillePreferee = new
Dimension(LARGEUR_TABLE, HAUTEUR_TABLE);
public Dimension getPreferredSize() {
return taillePreferee;
}
TableVertePingPong() {
moteurJeu =
new MoteurJeuPingPong(this);
addMouseMotionListener(moteurJeu);
addKeyListener(moteurJeu);
}
void ajouteAuCadre(Container conteneur) {
conteneur.setLayout(new BoxLayout(conteneur,
BoxLayout.Y_AXIS));
conteneur.add(this);
label = new JLabel(
"Taper N pour une nouvelle partie, S pour servir" +
" ou Q pour quitter");
conteneur.add(label);
JPanel panneauChoixNiveau = new JPanel();
panneauChoixNiveau.setLayout(new FlowLayout());
panneauChoixNiveau.add(new JLabel("Niveau"));
JComboBox controleNiveaux = new JComboBox();
int i;
for(i = NIVEAU_MIN; i <= NIVEAU_MAX; i++){
controleNiveaux.addItem(String.valueOf(i));
}
controleNiveaux.addItemListener(this);
panneauChoixNiveau.add(controleNiveaux);
conteneur.add(panneauChoixNiveau);
}
public void paintComponent(Graphics contexteGraphique) {
super.paintComponent(contexteGraphique);
contexteGraphique.setColor(Color.GREEN);
contexteGraphique.fillRect(
0, 0, LARGEUR_TABLE, HAUTEUR_TABLE);
contexteGraphique.setColor(Color.yellow);
contexteGraphique.fillRect(
RAQUETTE_ENFANT_X,
raquetteEnfant_Y,
LARGEUR_RAQUETTE, LONGUEUR_RAQUETTE);
contexteGraphique.setColor(Color.blue);
contexteGraphique.fillRect(RAQUETTE_ORDINATEUR_X,
raquetteOrdinateur_Y,
LARGEUR_RAQUETTE, LONGUEUR_RAQUETTE);
contexteGraphique.setColor(Color.red);
contexteGraphique.fillOval(balle_X, balle_Y, 10, 10);
contexteGraphique.setColor(Color.white);
contexteGraphique.drawRect(10, 10, 300, 200);
contexteGraphique.drawLine(160, 10, 160, 210);
requestFocus();
}
public void positionnerRaquetteEnfant_Y(int y) {
this.raquetteEnfant_Y = y;
repaint();
}
public int coordonneeRaquetteEnfant_Y() {
return raquetteEnfant_Y;
}
public void positionnerRaquetteOrdinateur_Y(int y) {
this.raquetteOrdinateur_Y = y;
repaint();
}
public void affecterTexteMessage(String texte) {
label.setText(texte);
repaint();
}
public void positionnerBalle(int x, int y) {
balle_X = x;
balle_Y = y;
repaint();
}
public static void main(String[] args) {
JFrame monCadre = new JFrame("Table verte de ping-pong");
monCadre.setDefaultCloseOperation(
WindowConstants.EXIT_ON_CLOSE);
TableVertePingPong table = new TableVertePingPong();
table.ajouteAuCadre(monCadre.getContentPane());
monCadre.setBounds(0, 0, LARGEUR_TABLE + 5,
HAUTEUR_TABLE + 40);
monCadre.setVisible(true);
}
public void itemStateChanged(ItemEvent event) {
if (event.getStateChange() == ItemEvent.SELECTED) {
String niveauChoisi = (String) event.getItem();
moteurJeu.fixerNiveauDeJeu(Integer.valueOf(niveauChoisi));
}
}
}
Voici la nouvelle version de MoteurJeuPingPong.java :
package ex_malins_1;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
public class MoteurJeuPingPong implements Runnable,
MouseMotionListener, KeyListener, ConstantesDuJeu {
private TableVertePingPong table;
private int raquetteEnfant_Y = RAQUETTE_ENFANT_Y_DEPART;
private int raquetteOrdinateur_Y =
RAQUETTE_ORDINATEUR_Y_DEPART;
private int scoreEnfant;
private int scoreOrdinateur;
private int balle_X;
private int balle_Y;
private boolean deplacementGauche = true;
private boolean balleServie = false;
private int deplacementVertical;
private int niveauDeJeu = 10;
public MoteurJeuPingPong(TableVertePingPong tableVerte) {
table = tableVerte;
Thread travailleur = new Thread(this);
travailleur.start();
}
public void mouseDragged(MouseEvent evenement) {
}
public void mouseMoved(MouseEvent evenement) {
int souris_Y = evenement.getY();
if (souris_Y < raquetteEnfant_Y &&
raquetteEnfant_Y > HAUT_TABLE) {
raquetteEnfant_Y -= INCREMENT_RAQUETTE + 20 - 2*niveauDeJeu;
} else if (raquetteEnfant_Y < BAS_TABLE) {
raquetteEnfant_Y += INCREMENT_RAQUETTE + 20 - 2*niveauDeJeu;
}
table.positionnerRaquetteEnfant_Y(raquetteEnfant_Y);
}
public void keyPressed(KeyEvent evenement) {
char touche = evenement.getKeyChar();
if ('n' == touche || 'N' == touche) {
demarrerNouvellePartie();
} else if ('q' == touche || 'Q' == touche) {
terminerJeu();
} else if ('s' == touche || 'S' == touche) {
if (scoreEnfant < SCORE_GAGNANT && scoreOrdinateur < SCORE_GAGNANT){
serviceEnfant();
}
}
}
public void keyReleased(KeyEvent evenement) {}
public void keyTyped(KeyEvent evenement) {}
public void demarrerNouvellePartie() {
scoreOrdinateur = 0;
scoreEnfant = 0;
table.affecterTexteMessage("Scores - Ordinateur : 0"
+ " Enfant : 0");
serviceEnfant();
}
public void terminerJeu(){
System.exit(0);
}
public void run() {
boolean rebondPossible = false;
while (true) {
try {
Thread.sleep(DUREE_SOMMEIL);
} catch (InterruptedException exception) {
exception.printStackTrace();
}
if (balleServie) {
if (deplacementGauche && balle_X > BALLE_X_MIN) {
rebondPossible = (balle_Y >= raquetteOrdinateur_Y
&& balle_Y < (raquetteOrdinateur_Y +
LONGUEUR_RAQUETTE) ? true : false);
balle_X -= INCREMENT_BALLE;
balle_Y -= deplacementVertical;
table.positionnerBalle(balle_X, balle_Y);
if (balle_X <= RAQUETTE_ORDINATEUR_X
&& rebondPossible) {
deplacementGauche = false;
}
}
if (!deplacementGauche && balle_X <= BALLE_X_MAX) {
rebondPossible = (balle_Y >= raquetteEnfant_Y &&
balle_Y < (raquetteEnfant_Y +
LONGUEUR_RAQUETTE) ? true : false);
balle_X += INCREMENT_BALLE;
table.positionnerBalle(balle_X, balle_Y);
if (balle_X >= RAQUETTE_ENFANT_X &&
rebondPossible) {
deplacementGauche = true;
}
}
if (raquetteOrdinateur_Y < balle_Y
&& raquetteOrdinateur_Y < BAS_TABLE) {
raquetteOrdinateur_Y += INCREMENT_RAQUETTE;
} else if (raquetteOrdinateur_Y > HAUT_TABLE) {
raquetteOrdinateur_Y -= INCREMENT_RAQUETTE;
}
table.positionnerRaquetteOrdinateur_Y(
raquetteOrdinateur_Y);
if (balleSurLaTable()) {
if (balle_X > BALLE_X_MAX ) {
scoreOrdinateur++;
afficherScore();
} else if (balle_X < BALLE_X_MIN) {
scoreEnfant++;
afficherScore();
}
}
}
}
}
public void fixerNiveauDeJeu(int niveauDeJeu){
niveauDeJeu = niveauDeJeu < 1 ? 1 : niveauDeJeu;
niveauDeJeu = niveauDeJeu > 10 ? 10 : niveauDeJeu;
this.niveauDeJeu = niveauDeJeu;
}
private void serviceEnfant() {
balleServie = true;
balle_X = RAQUETTE_ENFANT_X - 1;
balle_Y = raquetteEnfant_Y;
if (balle_Y > HAUTEUR_TABLE / 2) {
deplacementVertical = -1;
} else {
deplacementVertical = 1;
}
table.positionnerBalle(balle_X, balle_Y);
table.positionnerRaquetteEnfant_Y(raquetteEnfant_Y);
}
private void afficherScore() {
balleServie = false;
if (scoreOrdinateur == SCORE_GAGNANT) {
table.affecterTexteMessage("L'ordinateur a gagne ! " +
scoreOrdinateur +
" : " + scoreEnfant);
} else if (scoreEnfant == SCORE_GAGNANT) {
table.affecterTexteMessage ("Tu as gagne ! "+
scoreEnfant +
" : " + scoreOrdinateur);
} else {
table.affecterTexteMessage ("Ordinateur : "+
scoreOrdinateur +
" Enfant : " + scoreEnfant);
}
}
private boolean balleSurLaTable() {
if (balle_Y >= BALLE_Y_MIN && balle_Y <= BALLE_Y_MAX) {
return true;
} else {
return false;
}
}
}
Une dernière remarque. J'ai utilisé l'opérateur ternaire pour affecter la variable niveauDeJeu :
niveauDeJeu = niveauDeJeu < 1 ? 1 : niveauDeJeu
Il vous a été expliqué dans le livre. Plus précisément, dans le code de la version finale du jeu de ping pong (Chapitre 11, section "Fin du jeu ping-pong"). Il est utilisé au début de la méthode run() de la classe MoteurJeuPingPong et l'auteur nous en explique le fonctionnement juste avant le code. Pour rappel cet opérateur permet "d'économiser" l'utilisation d'une structure if/else.
Pour résoudre cet exercice, il convient d'abord de se poser les questions suivantes :
- où se situe le milieu de la table ?
- où doit-on modifier le code afin de gérer le rebond ?
Pour répondre à la première question, nous allons déclarer une nouvelle constante : HAUTEUR_MILIEU_TABLE. Nous avons :
HAUTEUR_MILIEU_TABLE = (BAS_TABLE ? HAUT_TABLE) / 2
Voici donc la nouvelle version du fichier ConstantesDuJeu.java :
package ex_malins_2;
public interface ConstantesDuJeu {
public final int LARGEUR_TABLE = 320;
public final int HAUTEUR_TABLE = 260;
public final int HAUT_TABLE = 12;
public final int BAS_TABLE = 180;
public final int MILIEU_HAUTEUR_TABLE = (BAS_TABLE - HAUT_TABLE) / 2;
public final int INCREMENT_BALLE = 4;
public final int BALLE_X_MIN = 1 + INCREMENT_BALLE;
public final int BALLE_Y_MIN = 1 + INCREMENT_BALLE;
public final int BALLE_X_MAX =
LARGEUR_TABLE - INCREMENT_BALLE;
public final int BALLE_Y_MAX =
HAUTEUR_TABLE - INCREMENT_BALLE;
public final int BALLE_X_DEPART = LARGEUR_TABLE / 2;
public final int BALLE_Y_DEPART = HAUTEUR_TABLE / 2;
public final int RAQUETTE_ENFANT_X = 300;
public final int RAQUETTE_ENFANT_Y_DEPART = 100;
public final int RAQUETTE_ORDINATEUR_X = 15;
public final int RAQUETTE_ORDINATEUR_Y_DEPART = 100;
public final int INCREMENT_RAQUETTE = 2;
public final int LONGUEUR_RAQUETTE = 30;
public final int LARGEUR_RAQUETTE = 5;
public final int SCORE_GAGNANT = 21;
public final int DUREE_SOMMEIL = 10;
public final int NIVEAU_MIN = 1;
public final int NIVEAU_MAX = 10;
}
Quant à la gestion du rebond sur la raquette enfant, il fallait regarder dans la méthode run() de la classe MoteurJeuPingPong.java, étape 2. Pourquoi l'étape 2 ? Tout simplement parce que c'est lorsque que la balle se déplace vers la droite qu'elle est susceptible de rebondir sur la raquette de l'enfant.
Section de code pertinente
Sélectionnez
if (!deplacementGauche && balle_X <= BALLE_X_MAX) {
rebondPossible = (balle_Y >= raquetteEnfant_Y &&
balle_Y < (raquetteEnfant_Y +
LONGUEUR_RAQUETTE) ? true : false);
balle_X += INCREMENT_BALLE;
table.positionnerBalle(balle_X, balle_Y);
if (balle_X >= RAQUETTE_ENFANT_X &&
rebondPossible) {
deplacementGauche = true;
}
}
Pour l'instant, le code se contente de renvoyer la balle dans la direction verticale qui a été donnée lors du service de l'enfant (cette variable n'est modifiée nulle part ailleurs que dans la méthode serviceEnfant()). Or, il faut que la direction change en fonction de la position de raquette_Y.
Nous allons donc ajouter un test if(), pour voir si la raquette de l'enfant se situe au-dessus du milieu de l'écran et modifier la direction verticale de la balle en conséquence.
if (!deplacementGauche && balle_X <= BALLE_X_MAX) {
rebondPossible = (balle_Y >= raquetteEnfant_Y &&
balle_Y < (raquetteEnfant_Y +
LONGUEUR_RAQUETTE) ? true : false);
balle_X += INCREMENT_BALLE;
table.positionnerBalle(balle_X, balle_Y);
if (balle_X >= RAQUETTE_ENFANT_X &&
rebondPossible) {
if (raquetteEnfant_Y < MILIEU_HAUTEUR_TABLE){
deplacementVertical = -1;
}
else {
deplacementVertical = 1;
}
deplacementGauche = true;
}
}
Voici donc le code complet de la nouvelle version de MoteurJeuPingPong.java :
package ex_malins_2;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
public class MoteurJeuPingPong implements Runnable,
MouseMotionListener, KeyListener, ConstantesDuJeu {
private TableVertePingPong table;
private int raquetteEnfant_Y = RAQUETTE_ENFANT_Y_DEPART;
private int raquetteOrdinateur_Y =
RAQUETTE_ORDINATEUR_Y_DEPART;
private int scoreEnfant;
private int scoreOrdinateur;
private int balle_X;
private int balle_Y;
private boolean deplacementGauche = true;
private boolean balleServie = false;
private int deplacementVertical;
private int niveauDeJeu = 10;
public MoteurJeuPingPong(TableVertePingPong tableVerte) {
table = tableVerte;
Thread travailleur = new Thread(this);
travailleur.start();
}
public void mouseDragged(MouseEvent evenement) {
}
public void mouseMoved(MouseEvent evenement) {
int souris_Y = evenement.getY();
if (souris_Y < raquetteEnfant_Y &&
raquetteEnfant_Y > HAUT_TABLE) {
raquetteEnfant_Y -= INCREMENT_RAQUETTE + 20 - 2*niveauDeJeu;
} else if (raquetteEnfant_Y < BAS_TABLE) {
raquetteEnfant_Y += INCREMENT_RAQUETTE + 20 - 2*niveauDeJeu;
}
table.positionnerRaquetteEnfant_Y(raquetteEnfant_Y);
}
public void keyPressed(KeyEvent evenement) {
char touche = evenement.getKeyChar();
if ('n' == touche || 'N' == touche) {
demarrerNouvellePartie();
} else if ('q' == touche || 'Q' == touche) {
terminerJeu();
} else if ('s' == touche || 'S' == touche) {
if (scoreEnfant < SCORE_GAGNANT && scoreOrdinateur < SCORE_GAGNANT){
serviceEnfant();
}
}
}
public void keyReleased(KeyEvent evenement) {}
public void keyTyped(KeyEvent evenement) {}
public void demarrerNouvellePartie() {
scoreOrdinateur = 0;
scoreEnfant = 0;
table.affecterTexteMessage("Scores - Ordinateur : 0"
+ " Enfant : 0");
serviceEnfant();
}
public void terminerJeu(){
System.exit(0);
}
public void run() {
boolean rebondPossible = false;
while (true) {
try {
Thread.sleep(DUREE_SOMMEIL);
} catch (InterruptedException exception) {
exception.printStackTrace();
}
if (balleServie) {
if (deplacementGauche && balle_X > BALLE_X_MIN) {
rebondPossible = (balle_Y >= raquetteOrdinateur_Y
&& balle_Y < (raquetteOrdinateur_Y +
LONGUEUR_RAQUETTE) ? true : false);
balle_X -= INCREMENT_BALLE;
balle_Y -= deplacementVertical;
table.positionnerBalle(balle_X, balle_Y);
if (balle_X <= RAQUETTE_ORDINATEUR_X
&& rebondPossible) {
deplacementGauche = false;
}
}
if (!deplacementGauche && balle_X <= BALLE_X_MAX) {
rebondPossible = (balle_Y >= raquetteEnfant_Y &&
balle_Y < (raquetteEnfant_Y +
LONGUEUR_RAQUETTE) ? true : false);
balle_X += INCREMENT_BALLE;
table.positionnerBalle(balle_X, balle_Y);
if (balle_X >= RAQUETTE_ENFANT_X &&
rebondPossible) {
if (raquetteEnfant_Y < MILIEU_HAUTEUR_TABLE){
deplacementVertical = -1;
}
else {
deplacementVertical = 1;
}
deplacementGauche = true;
}
}
if (raquetteOrdinateur_Y < balle_Y
&& raquetteOrdinateur_Y < BAS_TABLE) {
raquetteOrdinateur_Y += INCREMENT_RAQUETTE;
} else if (raquetteOrdinateur_Y > HAUT_TABLE) {
raquetteOrdinateur_Y -= INCREMENT_RAQUETTE;
}
table.positionnerRaquetteOrdinateur_Y(
raquetteOrdinateur_Y);
if (balleSurLaTable()) {
if (balle_X > BALLE_X_MAX ) {
scoreOrdinateur++;
afficherScore();
} else if (balle_X < BALLE_X_MIN) {
scoreEnfant++;
afficherScore();
}
}
}
}
}
public void fixerNiveauDeJeu(int niveauDeJeu){
niveauDeJeu = niveauDeJeu < 1 ? 1 : niveauDeJeu;
niveauDeJeu = niveauDeJeu > 10 ? 10 : niveauDeJeu;
this.niveauDeJeu = niveauDeJeu;
}
private void serviceEnfant() {
balleServie = true;
balle_X = RAQUETTE_ENFANT_X - 1;
balle_Y = raquetteEnfant_Y;
if (raquetteEnfant_Y > HAUTEUR_TABLE / 2) {
deplacementVertical = +1;
} else {
deplacementVertical = -1;
}
table.positionnerBalle(balle_X, balle_Y);
table.positionnerRaquetteEnfant_Y(raquetteEnfant_Y);
}
private void afficherScore() {
balleServie = false;
if (scoreOrdinateur == SCORE_GAGNANT) {
table.affecterTexteMessage("L'ordinateur a gagne ! " +
scoreOrdinateur +
" : " + scoreEnfant);
} else if (scoreEnfant == SCORE_GAGNANT) {
table.affecterTexteMessage ("Tu as gagne ! "+
scoreEnfant +
" : " + scoreOrdinateur);
} else {
table.affecterTexteMessage ("Ordinateur : "+
scoreOrdinateur +
" Enfant : " + scoreEnfant);
}
}
private boolean balleSurLaTable() {
if (balle_Y >= BALLE_Y_MIN && balle_Y <= BALLE_Y_MAX) {
return true;
} else {
return false;
}
}
}
Pour tester le package depuis Eclipse (clic droit sur son nœud → RunAs → JavaApplication), il vous faut copier la source TableVertePingPong du package de l'exercice 1 des petits malins (l'exercice précédent).