Affichage intégré

This commit is contained in:
2025-10-08 14:55:22 +02:00
parent aef5c7f70c
commit 7d2a0a12f9
9 changed files with 182 additions and 183 deletions
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+88 -127
View File
@@ -4,29 +4,42 @@ import javax.swing.*;
import java.awt.*; import java.awt.*;
/** /**
* Classe qui représente l'interface graphique du jeu du pendu. * Classe principale qui gère l'interface graphique du jeu du pendu.
* Elle gère l'affichage du mot caché, des lettres incorrectes, des vies * <p>
* et permet de saisir des lettres. Un bouton permet de relancer le jeu. * Cette classe crée la fenêtre du jeu, affiche le mot caché, les lettres incorrectes,
* le dessin du pendu (via {@link Affiche}), et permet à l'utilisateur de saisir des lettres.
* Elle gère également la logique de mise à jour et la fin de partie.
* </p>
*
* @author
* @version 1.0
*/ */
public class Action { public class Action {
// Fenêtre principale du jeu /** Fenêtre principale du jeu. */
private JFrame gameFrame; private JFrame gameFrame;
// Labels pour afficher le mot, les lettres incorrectes et les vies /** Label affichant le mot caché avec les lettres découvertes. */
private JLabel wordLabel; private JLabel wordLabel;
private JLabel incorrectLettersLabel;
private JLabel livesLabel;
// Champ de saisie pour entrer une lettre /** Label affichant la liste des lettres incorrectes. */
private JLabel incorrectLettersLabel;
/** Champ de texte permettant à l'utilisateur d'entrer une lettre. */
private JTextField letterInputField; private JTextField letterInputField;
// Instance du jeu /** Instance du jeu, contenant la logique (mot, vies, lettres, etc.). */
private Random_word game; private Random_word game;
/** Composant graphique qui affiche le dessin du pendu. */
private Affiche affiche;
/** /**
* Constructeur de la classe Action. * Constructeur de la classe {@code Action}.
* Initialise le jeu, les composants graphiques et affiche la fenêtre. * <p>
* Initialise le jeu, crée les composants graphiques, met en place la mise en page
* et affiche la fenêtre du jeu.
* </p>
*/ */
public Action() { public Action() {
game = new Random_word(); game = new Random_word();
@@ -36,27 +49,25 @@ public class Action {
gameFrame.setVisible(true); gameFrame.setVisible(true);
} }
// ==================== Initialisation des composants ==================== // ==================== Initialisation ====================
/** /**
* Initialise tous les composants graphiques : * Initialise tous les composants graphiques (labels, champs, boutons...).
* - Fenêtre principale
* - Labels pour le mot, les vies et les lettres incorrectes
* - Champ de saisie pour entrer les lettres
*/ */
private void initializeComponents() { private void initializeComponents() {
gameFrame = new JFrame("Hanging Man"); gameFrame = new JFrame("Hanging Man");
gameFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); gameFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gameFrame.setSize(600, 400); gameFrame.setSize(700, 500);
affiche = new Affiche();
affiche.setPreferredSize(new Dimension(350, 400));
affiche.setBackground(Color.WHITE);
affiche.setOpaque(true);
wordLabel = new JLabel(game.getHiddenWord()); wordLabel = new JLabel(game.getHiddenWord());
wordLabel.setFont(new Font("Arial", Font.BOLD, 32)); wordLabel.setFont(new Font("Arial", Font.BOLD, 32));
wordLabel.setHorizontalAlignment(SwingConstants.CENTER); wordLabel.setHorizontalAlignment(SwingConstants.CENTER);
livesLabel = new JLabel("Lives: " + game.getLives());
livesLabel.setFont(new Font("Arial", Font.BOLD, 20));
livesLabel.setHorizontalAlignment(SwingConstants.CENTER);
incorrectLettersLabel = new JLabel("Incorrect letters: " + game.getIncorrectLetters()); incorrectLettersLabel = new JLabel("Incorrect letters: " + game.getIncorrectLetters());
incorrectLettersLabel.setFont(new Font("Arial", Font.PLAIN, 20)); incorrectLettersLabel.setFont(new Font("Arial", Font.PLAIN, 20));
incorrectLettersLabel.setHorizontalAlignment(SwingConstants.CENTER); incorrectLettersLabel.setHorizontalAlignment(SwingConstants.CENTER);
@@ -65,119 +76,60 @@ public class Action {
letterInputField.setFont(new Font("Arial", Font.PLAIN, 24)); letterInputField.setFont(new Font("Arial", Font.PLAIN, 24));
} }
// ==================== Layout des composants ==================== // ==================== Mise en page ====================
/** /**
* Dispose les composants dans la fenêtre principale en utilisant GridBagLayout. * Dispose les composants graphiques dans la fenêtre selon un {@link BorderLayout}.
* Sépare la fenêtre en deux parties : le haut (mot et vies) et le bas (lettres incorrectes, saisie, bouton restart)
*/ */
private void layoutComponents() { private void layoutComponents() {
JPanel mainPanel = new JPanel(new GridBagLayout()); JPanel mainPanel = new JPanel(new BorderLayout());
GridBagConstraints mainConstraints = new GridBagConstraints();
mainConstraints.gridx = 0;
mainConstraints.fill = GridBagConstraints.BOTH;
mainConstraints.insets = new Insets(5, 5, 5, 5);
JPanel topPanel = createTopPanel(); // --- panneau gauche : dessin du pendu ---
mainConstraints.gridy = 0; JPanel leftPanel = new JPanel(new BorderLayout());
mainConstraints.weighty = 3.0; leftPanel.add(affiche, BorderLayout.CENTER);
mainConstraints.weightx = 1.0; mainPanel.add(leftPanel, BorderLayout.WEST);
mainPanel.add(topPanel, mainConstraints);
JPanel bottomPanel = createBottomPanel(); // --- panneau droit : interface du jeu ---
mainConstraints.gridy = 1; JPanel rightPanel = new JPanel(new GridBagLayout());
mainConstraints.weighty = 1.0; GridBagConstraints gbc = new GridBagConstraints();
mainPanel.add(bottomPanel, mainConstraints); gbc.gridx = 0;
gbc.fill = GridBagConstraints.BOTH;
gbc.insets = new Insets(5, 5, 5, 5);
gameFrame.add(mainPanel, BorderLayout.CENTER); // Mot caché
} gbc.gridy = 0;
gbc.weighty = 1.0;
rightPanel.add(wordLabel, gbc);
/** // Lettres incorrectes
* Crée le panneau supérieur avec : gbc.gridy = 1;
* - Le label des vies (à gauche) rightPanel.add(incorrectLettersLabel, gbc);
* - Le label du mot caché (à droite)
* @return JPanel configuré pour la partie supérieure
*/
private JPanel createTopPanel() {
JPanel topPanel = new JPanel(new GridBagLayout());
// Panel pour les vies
JPanel livesPanel = new JPanel(new GridBagLayout());
GridBagConstraints livesConstraints = new GridBagConstraints();
livesConstraints.anchor = GridBagConstraints.CENTER;
livesConstraints.fill = GridBagConstraints.NONE;
livesPanel.add(livesLabel, livesConstraints);
// Panel pour le mot
JPanel wordPanel = new JPanel(new GridBagLayout());
GridBagConstraints wordConstraints = new GridBagConstraints();
wordConstraints.anchor = GridBagConstraints.CENTER;
wordConstraints.fill = GridBagConstraints.NONE;
wordPanel.add(wordLabel, wordConstraints);
// Ajout des panels dans topPanel
GridBagConstraints leftConstraints = new GridBagConstraints();
leftConstraints.gridx = 0;
leftConstraints.weightx = 0.5;
leftConstraints.weighty = 1.0;
leftConstraints.fill = GridBagConstraints.BOTH;
topPanel.add(livesPanel, leftConstraints);
GridBagConstraints rightConstraints = new GridBagConstraints();
rightConstraints.gridx = 1;
rightConstraints.weightx = 0.5;
rightConstraints.weighty = 1.0;
rightConstraints.fill = GridBagConstraints.BOTH;
topPanel.add(wordPanel, rightConstraints);
return topPanel;
}
/**
* Crée le panneau inférieur avec :
* - Le label des lettres incorrectes
* - Le champ de saisie pour entrer une lettre
* - Le bouton "Restart" en bas à droite
* @return JPanel configuré pour la partie inférieure
*/
private JPanel createBottomPanel() {
JPanel bottomPanel = new JPanel();
bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.Y_AXIS));
// Label des lettres incorrectes
incorrectLettersLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
bottomPanel.add(incorrectLettersLabel);
// Champ de saisie // Champ de saisie
JLabel promptLabel = new JLabel("Enter a letter:"); gbc.gridy = 2;
promptLabel.setFont(new Font("Arial", Font.PLAIN, 16)); JPanel inputRow = new JPanel();
promptLabel.setAlignmentX(Component.CENTER_ALIGNMENT); inputRow.add(new JLabel("Enter a letter:"));
JPanel inputRow = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 5));
inputRow.add(promptLabel);
inputRow.add(letterInputField); inputRow.add(letterInputField);
inputRow.setAlignmentX(Component.CENTER_ALIGNMENT); rightPanel.add(inputRow, gbc);
bottomPanel.add(Box.createVerticalStrut(10)); // Bouton de redémarrage
bottomPanel.add(inputRow); gbc.gridy = 3;
// Bouton "Restart" en bas à droite
JButton restartButton = new JButton("Restart"); JButton restartButton = new JButton("Restart");
restartButton.addActionListener(new PlayButtonListener(gameFrame)); restartButton.addActionListener(new PlayButtonListener(gameFrame));
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); rightPanel.add(restartButton, gbc);
buttonPanel.add(restartButton);
bottomPanel.add(Box.createVerticalStrut(10)); mainPanel.add(rightPanel, BorderLayout.CENTER);
bottomPanel.add(buttonPanel); gameFrame.add(mainPanel);
return bottomPanel;
} }
// ==================== Gestion du jeu ==================== // ==================== Gestion du jeu ====================
/** /**
* Gère la saisie d'une lettre par le joueur. * Gère la saisie d'une lettre par le joueur.
* Vérifie la validité de la lettre, met à jour l'affichage et termine le jeu si nécessaire. * <p>
* Vérifie la validité de la lettre, met à jour le jeu, l'affichage
* et teste si la partie est terminée.
* </p>
*/ */
private void handleGuess() { private void handleGuess() {
String inputText = letterInputField.getText(); String inputText = letterInputField.getText();
@@ -187,17 +139,17 @@ public class Action {
char guessedLetter = inputText.charAt(0); char guessedLetter = inputText.charAt(0);
String message = game.guessLetter(guessedLetter); String message = game.guessLetter(guessedLetter);
updateUI(); updateUI();
if (game.isGameOver()) endGame(message); if (game.isGameOver()) endGame(message);
} }
/** /**
* Vérifie si la saisie de l'utilisateur est valide : * Vérifie que la saisie de l'utilisateur est une seule lettre valide.
* - Une seule lettre *
* - Caractère alphabétique * @param inputText texte saisi dans le champ de saisie
* @param inputText texte saisi par l'utilisateur * @return {@code true} si la saisie est valide, {@code false} sinon
* @return true si la saisie est valide, false sinon
*/ */
private boolean isValidInput(String inputText) { private boolean isValidInput(String inputText) {
if (inputText.length() != 1 || !Character.isLetter(inputText.charAt(0))) { if (inputText.length() != 1 || !Character.isLetter(inputText.charAt(0))) {
@@ -208,24 +160,33 @@ public class Action {
} }
/** /**
* Met à jour l'affichage des labels : * Met à jour les éléments de l'interface graphique :
* - Mot caché * <ul>
* - Lettres incorrectes * <li>le mot affiché,</li>
* - Nombre de vies restantes * <li>les lettres incorrectes,</li>
* <li>et le dessin du pendu selon les vies restantes.</li>
* </ul>
*/ */
private void updateUI() { private void updateUI() {
wordLabel.setText(game.getHiddenWord()); wordLabel.setText(game.getHiddenWord());
incorrectLettersLabel.setText("Incorrect letters: " + game.getIncorrectLetters()); incorrectLettersLabel.setText("Incorrect letters: " + game.getIncorrectLetters());
livesLabel.setText("Lives: " + game.getLives()); affiche.setLives(game.getLives());
} }
/** /**
* Termine le jeu et affiche un message. * Termine la partie en affichant un message selon le résultat (victoire ou défaite)
* Désactive le champ de saisie. * et empêche de nouvelles saisies.
* @param message Message à afficher (victoire ou défaite) *
* @param message message à afficher dans une boîte de dialogue
*/ */
private void endGame(String message) { private void endGame(String message) {
if (game.isWon()) {
affiche.setYouWin(true);
} else {
affiche.setLives(0);
}
JOptionPane.showMessageDialog(gameFrame, message); JOptionPane.showMessageDialog(gameFrame, message);
letterInputField.setEditable(false); letterInputField.setEditable(false);
} }
} }
+88 -30
View File
@@ -1,20 +1,58 @@
package fr.iut.Projet;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
/**
* Classe graphique responsable du dessin du pendu dans le jeu.
* <p>
* Cette classe hérite de {@link JComponent} et redéfinit la méthode
* {@link #paintComponent(Graphics)} pour afficher le pendu selon le nombre
* de vies restantes. Elle affiche également un message de victoire ou de défaite.
* </p>
*
* @author
* @version 1.0
*/
class Affiche extends JComponent { class Affiche extends JComponent {
private int step = 0;
/** Nombre de vies restantes (entre 0 et 8). */
private int lives = 8;
/** Indique si le joueur a gagné. */
private boolean youWin = false; private boolean youWin = false;
public void setStep(int step) { /**
this.step = step; * Définit le nombre de vies restantes et redessine le composant.
*
* @param lives nombre de vies restantes
*/
public void setLives(int lives) {
this.lives = lives;
repaint(); repaint();
} }
/**
* Définit si le joueur a gagné et redessine le composant.
*
* @param value {@code true} si le joueur a gagné, sinon {@code false}
*/
public void setYouWin(boolean value) { public void setYouWin(boolean value) {
this.youWin = value; this.youWin = value;
repaint(); repaint();
} }
/**
* Redessine le pendu en fonction du nombre de vies restantes.
* <ul>
* <li>Affiche la potence dès la première erreur</li>
* <li>Ajoute progressivement les membres du pendu</li>
* <li>Affiche une tête de mort si toutes les vies sont perdues</li>
* <li>Affiche un message "YOU WIN" si la partie est gagnée</li>
* </ul>
*
* @param g contexte graphique utilisé pour dessiner
*/
@Override @Override
protected void paintComponent(Graphics g) { protected void paintComponent(Graphics g) {
super.paintComponent(g); super.paintComponent(g);
@@ -28,43 +66,67 @@ class Affiche extends JComponent {
g2.setStroke(new BasicStroke(3)); g2.setStroke(new BasicStroke(3));
g2.setColor(Color.BLACK); g2.setColor(Color.BLACK);
drawGallows(g2); if (lives <= 7) drawGallows(g2);
drawHangman(g2); if (lives <= 6) drawHead(g2);
if (lives <= 5) drawBody(g2);
if (step >= 7) drawSkull(g2); if (lives <= 4) drawLeftArm(g2);
if (lives <= 3) drawRightArm(g2);
if (lives <= 2) drawLeftLeg(g2);
if (lives <= 1) drawRightLeg(g2);
if (lives == 1) drawAura(g2);
if (lives == 0) drawSkull(g2);
if (youWin) drawYouWinMessage(g2); if (youWin) drawYouWinMessage(g2);
g2.dispose(); g2.dispose();
} }
// ==================== Méthodes de dessin ====================
/** Dessine la potence. */
private void drawGallows(Graphics2D g2) { private void drawGallows(Graphics2D g2) {
// Base and vertical post
g2.drawLine(50, 350, 200, 350); g2.drawLine(50, 350, 200, 350);
g2.drawLine(100, 350, 100, 50); g2.drawLine(100, 350, 100, 50);
// Horizontal beam and rope
g2.drawLine(100, 50, 250, 50); g2.drawLine(100, 50, 250, 50);
g2.drawLine(250, 50, 250, 100); g2.drawLine(250, 50, 250, 100);
// Diagonal support
g2.drawLine(100, 100, 180, 50); g2.drawLine(100, 100, 180, 50);
} }
private void drawHangman(Graphics2D g2) { // Coordonnées et tailles du pendu
int headX = 225, headY = 100, headDiam = 50; private final int headX = 225, headY = 100, headDiam = 50;
int bodyX = headX + headDiam / 2, bodyYStart = headY + headDiam, bodyYEnd = bodyYStart + 100; private final int bodyX = headX + headDiam / 2;
int armLength = 60; private final int bodyYStart = headY + headDiam;
int legLength = 70; private final int bodyYEnd = bodyYStart + 100;
private final int armLength = 60;
private final int legLength = 70;
if (step >= 1) g2.drawOval(headX, headY, headDiam, headDiam); // head /** Dessine la tête du pendu. */
if (step >= 2) g2.drawLine(bodyX, bodyYStart, bodyX, bodyYEnd); // body private void drawHead(Graphics2D g2) { g2.drawOval(headX, headY, headDiam, headDiam); }
if (step >= 3) g2.drawLine(bodyX, bodyYStart + 20, bodyX - armLength, bodyYStart + 20); // left arm
if (step >= 4) g2.drawLine(bodyX, bodyYStart + 20, bodyX + armLength, bodyYStart + 20); // right arm
if (step >= 5) g2.drawLine(bodyX, bodyYEnd, bodyX - 5, bodyYEnd + legLength); // left leg
if (step >= 6) g2.drawLine(bodyX, bodyYEnd, bodyX + 5, bodyYEnd + legLength); // right leg
if (step == 6) drawAura(g2, headX, headY, headDiam, bodyX, bodyYStart, bodyYEnd, armLength, legLength); /** Dessine le corps du pendu. */
private void drawBody(Graphics2D g2) { g2.drawLine(bodyX, bodyYStart, bodyX, bodyYEnd); }
/** Dessine le bras gauche. */
private void drawLeftArm(Graphics2D g2) {
g2.drawLine(bodyX, bodyYStart + 20, bodyX - armLength, bodyYStart + 20);
} }
private void drawAura(Graphics2D g2, int headX, int headY, int headDiam, int bodyX, int bodyYStart, int bodyYEnd, int armLength, int legLength) { /** Dessine le bras droit. */
private void drawRightArm(Graphics2D g2) {
g2.drawLine(bodyX, bodyYStart + 20, bodyX + armLength, bodyYStart + 20);
}
/** Dessine la jambe gauche. */
private void drawLeftLeg(Graphics2D g2) {
g2.drawLine(bodyX, bodyYEnd, bodyX - 5, bodyYEnd + legLength);
}
/** Dessine la jambe droite. */
private void drawRightLeg(Graphics2D g2) {
g2.drawLine(bodyX, bodyYEnd, bodyX + 5, bodyYEnd + legLength);
}
/** Dessine une aura bleue lorsque le joueur est sur sa dernière vie. */
private void drawAura(Graphics2D g2) {
g2.setColor(new Color(0, 0, 255, 100)); g2.setColor(new Color(0, 0, 255, 100));
g2.setStroke(new BasicStroke(8, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setStroke(new BasicStroke(8, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2.drawOval(headX, headY, headDiam, headDiam); g2.drawOval(headX, headY, headDiam, headDiam);
@@ -75,27 +137,22 @@ class Affiche extends JComponent {
g2.drawLine(bodyX, bodyYEnd, bodyX + 5, bodyYEnd + legLength); g2.drawLine(bodyX, bodyYEnd, bodyX + 5, bodyYEnd + legLength);
} }
/** Dessine la tête de mort et le message "GAME OVER". */
private void drawSkull(Graphics2D g2) { private void drawSkull(Graphics2D g2) {
int skullX = 225, skullY = 100, skullDiam = 50; int skullX = 225, skullY = 100, skullDiam = 50;
// Skull
g2.setColor(Color.BLACK); g2.setColor(Color.BLACK);
g2.fillOval(skullX, skullY, skullDiam, skullDiam); g2.fillOval(skullX, skullY, skullDiam, skullDiam);
// Eyes
g2.setColor(Color.WHITE); g2.setColor(Color.WHITE);
g2.fillOval(skullX + skullDiam / 5, skullY + skullDiam / 6, skullDiam / 5, skullDiam / 5); g2.fillOval(skullX + skullDiam / 5, skullY + skullDiam / 6, skullDiam / 5, skullDiam / 5);
g2.fillOval(skullX + 3 * skullDiam / 5, skullY + skullDiam / 6, skullDiam / 5, skullDiam / 5); g2.fillOval(skullX + 3 * skullDiam / 5, skullY + skullDiam / 6, skullDiam / 5, skullDiam / 5);
// Nose
g2.fillOval(skullX + skullDiam / 2 - skullDiam / 12, skullY + skullDiam / 2 - skullDiam / 12, skullDiam / 6, skullDiam / 6); g2.fillOval(skullX + skullDiam / 2 - skullDiam / 12, skullY + skullDiam / 2 - skullDiam / 12, skullDiam / 6, skullDiam / 6);
// Mouth
g2.setStroke(new BasicStroke(2)); g2.setStroke(new BasicStroke(2));
g2.drawLine(skullX + skullDiam / 5, skullY + 2 * skullDiam / 3, g2.drawLine(skullX + skullDiam / 5, skullY + 2 * skullDiam / 3,
skullX + 4 * skullDiam / 5, skullY + 2 * skullDiam / 3); skullX + 4 * skullDiam / 5, skullY + 2 * skullDiam / 3);
// GAME OVER message
g2.setColor(Color.RED); g2.setColor(Color.RED);
g2.setFont(new Font("Arial", Font.BOLD, 36)); g2.setFont(new Font("Arial", Font.BOLD, 36));
String message = "GAME OVER"; String message = "GAME OVER";
@@ -106,6 +163,7 @@ class Affiche extends JComponent {
g2.drawString(message, xText, yText); g2.drawString(message, xText, yText);
} }
/** Dessine le message "YOU WIN" en vert en cas de victoire. */
private void drawYouWinMessage(Graphics2D g2) { private void drawYouWinMessage(Graphics2D g2) {
g2.setColor(Color.GREEN); g2.setColor(Color.GREEN);
g2.setFont(new Font("Arial", Font.BOLD, 36)); g2.setFont(new Font("Arial", Font.BOLD, 36));
@@ -116,4 +174,4 @@ class Affiche extends JComponent {
int yText = 50; int yText = 50;
g2.drawString(message, xText, yText); g2.drawString(message, xText, yText);
} }
} }
-25
View File
@@ -1,25 +0,0 @@
import java.awt.event.*;
import javax.swing.SwingUtilities;
class Mouse extends MouseAdapter {
private Affiche aff;
private int step = 0; // correspond à Affiche.step
public Mouse(Affiche aff) {
this.aff = aff;
}
@Override
public void mousePressed(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
// clic droit -> gagne
aff.setYouWin(true);
} else {
// clic gauche -> incrémente étape
if (step < 7) {
step++;
aff.setStep(step); // <-- utiliser setStep
}
}
}
}
+6 -1
View File
@@ -102,7 +102,12 @@ public class Random_word {
} }
public boolean isWon() { public boolean isWon() {
return secretWord.equals(String.valueOf(hiddenWord)); for (char c : hiddenWord) {
if (c == '_') {
return false;
}
}
return true;
} }
public String getSecretWord() { public String getSecretWord() {