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.*;
/**
* Classe qui représente l'interface graphique du jeu du pendu.
* Elle gère l'affichage du mot caché, des lettres incorrectes, des vies
* et permet de saisir des lettres. Un bouton permet de relancer le jeu.
* Classe principale qui gère l'interface graphique du jeu du pendu.
* <p>
* 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 {
// Fenêtre principale du jeu
/** Fenêtre principale du jeu. */
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 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;
// Instance du jeu
/** Instance du jeu, contenant la logique (mot, vies, lettres, etc.). */
private Random_word game;
/** Composant graphique qui affiche le dessin du pendu. */
private Affiche affiche;
/**
* Constructeur de la classe Action.
* Initialise le jeu, les composants graphiques et affiche la fenêtre.
* Constructeur de la classe {@code Action}.
* <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() {
game = new Random_word();
@@ -36,27 +49,25 @@ public class Action {
gameFrame.setVisible(true);
}
// ==================== Initialisation des composants ====================
// ==================== Initialisation ====================
/**
* Initialise tous les composants graphiques :
* - Fenêtre principale
* - Labels pour le mot, les vies et les lettres incorrectes
* - Champ de saisie pour entrer les lettres
* Initialise tous les composants graphiques (labels, champs, boutons...).
*/
private void initializeComponents() {
gameFrame = new JFrame("Hanging Man");
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.setFont(new Font("Arial", Font.BOLD, 32));
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.setFont(new Font("Arial", Font.PLAIN, 20));
incorrectLettersLabel.setHorizontalAlignment(SwingConstants.CENTER);
@@ -65,119 +76,60 @@ public class Action {
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.
* Sépare la fenêtre en deux parties : le haut (mot et vies) et le bas (lettres incorrectes, saisie, bouton restart)
* Dispose les composants graphiques dans la fenêtre selon un {@link BorderLayout}.
*/
private void layoutComponents() {
JPanel mainPanel = new JPanel(new GridBagLayout());
GridBagConstraints mainConstraints = new GridBagConstraints();
mainConstraints.gridx = 0;
mainConstraints.fill = GridBagConstraints.BOTH;
mainConstraints.insets = new Insets(5, 5, 5, 5);
JPanel mainPanel = new JPanel(new BorderLayout());
JPanel topPanel = createTopPanel();
mainConstraints.gridy = 0;
mainConstraints.weighty = 3.0;
mainConstraints.weightx = 1.0;
mainPanel.add(topPanel, mainConstraints);
// --- panneau gauche : dessin du pendu ---
JPanel leftPanel = new JPanel(new BorderLayout());
leftPanel.add(affiche, BorderLayout.CENTER);
mainPanel.add(leftPanel, BorderLayout.WEST);
JPanel bottomPanel = createBottomPanel();
mainConstraints.gridy = 1;
mainConstraints.weighty = 1.0;
mainPanel.add(bottomPanel, mainConstraints);
// --- panneau droit : interface du jeu ---
JPanel rightPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
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);
/**
* Crée le panneau supérieur avec :
* - Le label des vies (à gauche)
* - 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);
// Lettres incorrectes
gbc.gridy = 1;
rightPanel.add(incorrectLettersLabel, gbc);
// Champ de saisie
JLabel promptLabel = new JLabel("Enter a letter:");
promptLabel.setFont(new Font("Arial", Font.PLAIN, 16));
promptLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
JPanel inputRow = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 5));
inputRow.add(promptLabel);
gbc.gridy = 2;
JPanel inputRow = new JPanel();
inputRow.add(new JLabel("Enter a letter:"));
inputRow.add(letterInputField);
inputRow.setAlignmentX(Component.CENTER_ALIGNMENT);
rightPanel.add(inputRow, gbc);
bottomPanel.add(Box.createVerticalStrut(10));
bottomPanel.add(inputRow);
// Bouton "Restart" en bas à droite
// Bouton de redémarrage
gbc.gridy = 3;
JButton restartButton = new JButton("Restart");
restartButton.addActionListener(new PlayButtonListener(gameFrame));
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
buttonPanel.add(restartButton);
rightPanel.add(restartButton, gbc);
bottomPanel.add(Box.createVerticalStrut(10));
bottomPanel.add(buttonPanel);
return bottomPanel;
mainPanel.add(rightPanel, BorderLayout.CENTER);
gameFrame.add(mainPanel);
}
// ==================== Gestion du jeu ====================
/**
* 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() {
String inputText = letterInputField.getText();
@@ -187,17 +139,17 @@ public class Action {
char guessedLetter = inputText.charAt(0);
String message = game.guessLetter(guessedLetter);
updateUI();
if (game.isGameOver()) endGame(message);
}
/**
* Vérifie si la saisie de l'utilisateur est valide :
* - Une seule lettre
* - Caractère alphabétique
* @param inputText texte saisi par l'utilisateur
* @return true si la saisie est valide, false sinon
* Vérifie que la saisie de l'utilisateur est une seule lettre valide.
*
* @param inputText texte saisi dans le champ de saisie
* @return {@code true} si la saisie est valide, {@code false} sinon
*/
private boolean isValidInput(String inputText) {
if (inputText.length() != 1 || !Character.isLetter(inputText.charAt(0))) {
@@ -208,24 +160,33 @@ public class Action {
}
/**
* Met à jour l'affichage des labels :
* - Mot caché
* - Lettres incorrectes
* - Nombre de vies restantes
* Met à jour les éléments de l'interface graphique :
* <ul>
* <li>le mot affiché,</li>
* <li>les lettres incorrectes,</li>
* <li>et le dessin du pendu selon les vies restantes.</li>
* </ul>
*/
private void updateUI() {
wordLabel.setText(game.getHiddenWord());
incorrectLettersLabel.setText("Incorrect letters: " + game.getIncorrectLetters());
livesLabel.setText("Lives: " + game.getLives());
affiche.setLives(game.getLives());
}
/**
* Termine le jeu et affiche un message.
* Désactive le champ de saisie.
* @param message Message à afficher (victoire ou défaite)
* Termine la partie en affichant un message selon le résultat (victoire ou défaite)
* et empêche de nouvelles saisies.
*
* @param message message à afficher dans une boîte de dialogue
*/
private void endGame(String message) {
if (game.isWon()) {
affiche.setYouWin(true);
} else {
affiche.setLives(0);
}
JOptionPane.showMessageDialog(gameFrame, message);
letterInputField.setEditable(false);
}
}
}
+88 -30
View File
@@ -1,20 +1,58 @@
package fr.iut.Projet;
import javax.swing.*;
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 {
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;
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();
}
/**
* 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) {
this.youWin = value;
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
protected void paintComponent(Graphics g) {
super.paintComponent(g);
@@ -28,43 +66,67 @@ class Affiche extends JComponent {
g2.setStroke(new BasicStroke(3));
g2.setColor(Color.BLACK);
drawGallows(g2);
drawHangman(g2);
if (step >= 7) drawSkull(g2);
if (lives <= 7) drawGallows(g2);
if (lives <= 6) drawHead(g2);
if (lives <= 5) drawBody(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);
g2.dispose();
}
// ==================== Méthodes de dessin ====================
/** Dessine la potence. */
private void drawGallows(Graphics2D g2) {
// Base and vertical post
g2.drawLine(50, 350, 200, 350);
g2.drawLine(100, 350, 100, 50);
// Horizontal beam and rope
g2.drawLine(100, 50, 250, 50);
g2.drawLine(250, 50, 250, 100);
// Diagonal support
g2.drawLine(100, 100, 180, 50);
}
private void drawHangman(Graphics2D g2) {
int headX = 225, headY = 100, headDiam = 50;
int bodyX = headX + headDiam / 2, bodyYStart = headY + headDiam, bodyYEnd = bodyYStart + 100;
int armLength = 60;
int legLength = 70;
// Coordonnées et tailles du pendu
private final int headX = 225, headY = 100, headDiam = 50;
private final int bodyX = headX + headDiam / 2;
private final int bodyYStart = headY + headDiam;
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
if (step >= 2) g2.drawLine(bodyX, bodyYStart, bodyX, bodyYEnd); // body
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
/** Dessine la tête du pendu. */
private void drawHead(Graphics2D g2) { g2.drawOval(headX, headY, headDiam, headDiam); }
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.setStroke(new BasicStroke(8, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2.drawOval(headX, headY, headDiam, headDiam);
@@ -75,27 +137,22 @@ class Affiche extends JComponent {
g2.drawLine(bodyX, bodyYEnd, bodyX + 5, bodyYEnd + legLength);
}
/** Dessine la tête de mort et le message "GAME OVER". */
private void drawSkull(Graphics2D g2) {
int skullX = 225, skullY = 100, skullDiam = 50;
// Skull
g2.setColor(Color.BLACK);
g2.fillOval(skullX, skullY, skullDiam, skullDiam);
// Eyes
g2.setColor(Color.WHITE);
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);
// Nose
g2.fillOval(skullX + skullDiam / 2 - skullDiam / 12, skullY + skullDiam / 2 - skullDiam / 12, skullDiam / 6, skullDiam / 6);
// Mouth
g2.setStroke(new BasicStroke(2));
g2.drawLine(skullX + skullDiam / 5, skullY + 2 * skullDiam / 3,
skullX + 4 * skullDiam / 5, skullY + 2 * skullDiam / 3);
// GAME OVER message
g2.setColor(Color.RED);
g2.setFont(new Font("Arial", Font.BOLD, 36));
String message = "GAME OVER";
@@ -106,6 +163,7 @@ class Affiche extends JComponent {
g2.drawString(message, xText, yText);
}
/** Dessine le message "YOU WIN" en vert en cas de victoire. */
private void drawYouWinMessage(Graphics2D g2) {
g2.setColor(Color.GREEN);
g2.setFont(new Font("Arial", Font.BOLD, 36));
@@ -116,4 +174,4 @@ class Affiche extends JComponent {
int yText = 50;
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() {
return secretWord.equals(String.valueOf(hiddenWord));
for (char c : hiddenWord) {
if (c == '_') {
return false;
}
}
return true;
}
public String getSecretWord() {