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