diff --git a/TestV2/ressources/images/MainMenu/Leaderboard/1.png b/TestV2/ressources/images/MainMenu/Leaderboard/1.png new file mode 100644 index 0000000..d305d6d Binary files /dev/null and b/TestV2/ressources/images/MainMenu/Leaderboard/1.png differ diff --git a/TestV2/ressources/images/MainMenu/Leaderboard/2.png b/TestV2/ressources/images/MainMenu/Leaderboard/2.png new file mode 100644 index 0000000..7cdd23c Binary files /dev/null and b/TestV2/ressources/images/MainMenu/Leaderboard/2.png differ diff --git a/TestV2/ressources/images/MainMenu/Leaderboard/3.png b/TestV2/ressources/images/MainMenu/Leaderboard/3.png new file mode 100644 index 0000000..09678f0 Binary files /dev/null and b/TestV2/ressources/images/MainMenu/Leaderboard/3.png differ diff --git a/TestV2/src/fr/monkhanny/dorfromantik/gui/Leaderboard.java b/TestV2/src/fr/monkhanny/dorfromantik/gui/Leaderboard.java new file mode 100644 index 0000000..588ac06 --- /dev/null +++ b/TestV2/src/fr/monkhanny/dorfromantik/gui/Leaderboard.java @@ -0,0 +1,12 @@ +package fr.monkhanny.dorfromantik.gui; + +import javax.swing.*; +import java.awt.*; + +public abstract class Leaderboard extends JPanel { + public Leaderboard() { + setLayout(new BorderLayout()); + } + + public abstract void refresh(); // Méthode pour actualiser le contenu +} diff --git a/TestV2/src/fr/monkhanny/dorfromantik/gui/LeaderboardBarChartPanel.java b/TestV2/src/fr/monkhanny/dorfromantik/gui/LeaderboardBarChartPanel.java new file mode 100644 index 0000000..bb08e42 --- /dev/null +++ b/TestV2/src/fr/monkhanny/dorfromantik/gui/LeaderboardBarChartPanel.java @@ -0,0 +1,40 @@ +package fr.monkhanny.dorfromantik.gui; + +import javax.swing.*; +import java.awt.*; + +public class LeaderboardBarChartPanel extends JPanel { + private int totalPlayers; + private int rank; + + public LeaderboardBarChartPanel(int totalPlayers, int rank) { + this.totalPlayers = totalPlayers; + this.rank = rank; + } + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + int barWidth = 30; // Largeur des barres + int spacing = 10; // Espacement entre les barres + int barHeight = 20; // Hauteur de la barre + int totalBars = 10; // Nombre de tranches + int maxWidth = (getWidth() - (totalBars + 1) * spacing) / totalBars; + + // Dessiner chaque barre pour chaque tranche + for (int i = 0; i < totalBars; i++) { + int x = spacing + i * (maxWidth + spacing); + int y = 50; // Position verticale de la barre + + // Déterminer la couleur : colorier la tranche actuelle + if (i == (rank - 1) / (totalPlayers / 10)) { + g.setColor(new Color(0, 255, 0)); // Vert pour la tranche actuelle + } else { + g.setColor(new Color(255, 0, 0)); // Rouge pour les autres tranches + } + + // Dessiner la barre + g.fillRect(x, y, maxWidth, barHeight); + } + } +} diff --git a/TestV2/src/fr/monkhanny/dorfromantik/gui/LeaderboardByTier.java b/TestV2/src/fr/monkhanny/dorfromantik/gui/LeaderboardByTier.java new file mode 100644 index 0000000..1b1862a --- /dev/null +++ b/TestV2/src/fr/monkhanny/dorfromantik/gui/LeaderboardByTier.java @@ -0,0 +1,64 @@ +package fr.monkhanny.dorfromantik.gui; + +import javax.swing.*; +import java.awt.*; + +// @TODO : MODIFIER CAR C'EST PAS BEAU + BDD +public class LeaderboardByTier extends Leaderboard { + + public LeaderboardByTier() { + super(); + refresh(); // Charge les données initiales + } + + @Override + public void refresh() { + removeAll(); // Supprime tout contenu existant + setBackground(new Color(64, 0, 128)); + + // Titre + JLabel titleLabel = new JLabel("CLASSEMENT PAR TRANCHE"); + titleLabel.setForeground(Color.WHITE); + titleLabel.setFont(new Font("Arial", Font.BOLD, 24)); + titleLabel.setHorizontalAlignment(SwingConstants.CENTER); + add(titleLabel, BorderLayout.NORTH); + + // Contenu + JPanel tierPanel = new JPanel(); + tierPanel.setLayout(new BoxLayout(tierPanel, BoxLayout.Y_AXIS)); + tierPanel.setBackground(new Color(64, 0, 128)); + + // Exemple de tranche + int totalPlayers = 1000; + int rank = 237; // Exemple : rang du joueur + int tierSize = totalPlayers / 10; + int tier = (rank - 1) / tierSize + 1; + + // Label indiquant la tranche dans laquelle le joueur se trouve + JLabel infoLabel = new JLabel("Vous êtes dans la tranche : " + tier); + infoLabel.setFont(new Font("Arial", Font.PLAIN, 18)); + infoLabel.setForeground(Color.WHITE); + infoLabel.setAlignmentX(CENTER_ALIGNMENT); + + // Pourcentage du joueur + double percentage = (double) rank / totalPlayers * 100; + JLabel percentageLabel = new JLabel(String.format("Vous faites partie des %.2f%% des joueurs", percentage)); + percentageLabel.setFont(new Font("Arial", Font.PLAIN, 18)); + percentageLabel.setForeground(Color.WHITE); + percentageLabel.setAlignmentX(CENTER_ALIGNMENT); + + // Ajouter les labels à la JPanel + tierPanel.add(Box.createVerticalStrut(20)); + tierPanel.add(infoLabel); + tierPanel.add(percentageLabel); + + // Ajouter le diagramme en barres pour les tranches + LeaderboardBarChartPanel barChartPanel = new LeaderboardBarChartPanel(totalPlayers, rank); + tierPanel.add(Box.createVerticalStrut(20)); // Espacement + tierPanel.add(barChartPanel); + + add(tierPanel, BorderLayout.CENTER); + revalidate(); + repaint(); + } +} diff --git a/TestV2/src/fr/monkhanny/dorfromantik/gui/LeaderboardWorldWide.java b/TestV2/src/fr/monkhanny/dorfromantik/gui/LeaderboardWorldWide.java new file mode 100644 index 0000000..5ebd7df --- /dev/null +++ b/TestV2/src/fr/monkhanny/dorfromantik/gui/LeaderboardWorldWide.java @@ -0,0 +1,160 @@ +package fr.monkhanny.dorfromantik.gui; + +import fr.monkhanny.dorfromantik.utils.Database; +import fr.monkhanny.dorfromantik.utils.PlayerScore; + +import javax.swing.*; +import java.awt.*; +import java.sql.SQLException; +import java.util.List; + +public class LeaderboardWorldWide extends Leaderboard { + + public LeaderboardWorldWide() { + super(); + refresh(); // Charge les données initiales + } + + @Override + public void refresh() { + removeAll(); // Supprime tout contenu existant + setBackground(new Color(238, 238, 238)); // Gris clair moderne + + // Panel principal pour centrer le leaderboard + JPanel mainPanel = new JPanel(); + mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); + mainPanel.setBackground(new Color(238, 238, 238)); // Gris clair + mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + + // Titre + JLabel titleLabel = new JLabel("Classement mondial"); + titleLabel.setForeground(new Color(34, 139, 34)); // Vert forêt pour le titre + titleLabel.setFont(new Font("Roboto", Font.BOLD, 32)); // Police moderne + titleLabel.setAlignmentX(CENTER_ALIGNMENT); + + // Panel pour les trois premiers + JPanel topThreePanel = new JPanel(new GridBagLayout()); + topThreePanel.setBackground(new Color(238, 238, 238)); // Gris clair + GridBagConstraints gbc = new GridBagConstraints(); + gbc.fill = GridBagConstraints.BOTH; + gbc.insets = new Insets(0, 10, 0, 10); + + // Récupérer les meilleurs joueurs depuis la base de données + Database db = null; + List topPlayers = null; + try { + db = new Database(); + topPlayers = db.getTopPlayers(); + } catch (SQLException e) { + e.printStackTrace(); + } finally { + if (db != null) { + db.close(); + } + } + + if (topPlayers != null && topPlayers.size() >= 3) { + // Ajout des trois premiers joueurs avec médailles + gbc.gridx = 0; + gbc.weightx = 0.4; + topThreePanel.add(createTopPlayerPanel(topPlayers.get(1).getUsername(), topPlayers.get(1).getScore(), + "./ressources/images/MainMenu/Leaderboard/2.png", false), gbc); + + gbc.gridx = 1; + gbc.weightx = 0.5; + topThreePanel.add(createTopPlayerPanel(topPlayers.get(0).getUsername(), topPlayers.get(0).getScore(), + "./ressources/images/MainMenu/Leaderboard/1.png", true), gbc); + + gbc.gridx = 2; + gbc.weightx = 0.4; + topThreePanel.add(createTopPlayerPanel(topPlayers.get(2).getUsername(), topPlayers.get(2).getScore(), + "./ressources/images/MainMenu/Leaderboard/3.png", false), gbc); + } + + // Panel pour les autres joueurs + JPanel playersPanel = new JPanel(); + playersPanel.setLayout(new BoxLayout(playersPanel, BoxLayout.Y_AXIS)); + playersPanel.setBackground(new Color(255, 255, 255)); // Blanc cassé + + // Ajout des joueurs restants (de 4 à 10) + if (topPlayers != null) { + for (int i = 3; i < topPlayers.size(); i++) { + PlayerScore player = topPlayers.get(i); + playersPanel.add(createPlayerPanel(player.getUsername(), player.getScore(), i + 1)); + } + } + + // Ajoute tout au panneau principal + mainPanel.add(titleLabel); + mainPanel.add(Box.createRigidArea(new Dimension(0, 20))); + mainPanel.add(topThreePanel); + mainPanel.add(Box.createRigidArea(new Dimension(0, 20))); + mainPanel.add(playersPanel); + + add(mainPanel, BorderLayout.CENTER); + + revalidate(); + repaint(); + } + + private JPanel createPlayerPanel(String playerName, int score, int rank) { + JPanel panel = new JPanel(); + panel.setLayout(new BorderLayout()); + panel.setBackground(new Color(250, 250, 250)); // Blanc cassé + panel.setBorder(BorderFactory.createMatteBorder(1, 0, 1, 0, new Color(200, 200, 200))); // Bordure gris clair + + JLabel rankLabel = new JLabel(rank + ". "); + rankLabel.setFont(new Font("Roboto", Font.BOLD, 18)); + rankLabel.setForeground(new Color(34, 139, 34)); // Vert forêt pour le rang + rankLabel.setPreferredSize(new Dimension(40, 40)); + + JLabel nameLabel = new JLabel(playerName); + nameLabel.setFont(new Font("Roboto", Font.PLAIN, 18)); + nameLabel.setForeground(new Color(58, 58, 58)); // Gris clair + + JLabel scoreLabel = new JLabel(Integer.toString(score)); + scoreLabel.setFont(new Font("Roboto", Font.BOLD, 18)); + scoreLabel.setForeground(new Color(255, 165, 0)); // Orange moderne + + panel.add(rankLabel, BorderLayout.WEST); + panel.add(nameLabel, BorderLayout.CENTER); + panel.add(scoreLabel, BorderLayout.EAST); + + return panel; + } + + private ImageIcon resizeIcon(String path, int width, int height) { + ImageIcon icon = new ImageIcon(path); + Image img = icon.getImage().getScaledInstance(width, height, Image.SCALE_SMOOTH); + return new ImageIcon(img); + } + + private JPanel createTopPlayerPanel(String playerName, int score, String medalPath, boolean isFirst) { + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + panel.setBackground(isFirst ? new Color(255, 223, 0) : new Color(144, 238, 144)); // Doré pour le premier + panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + + // Ajout de l'icône de médaille redimensionnée + JLabel medalLabel = new JLabel(resizeIcon(medalPath, isFirst ? 80 : 60, isFirst ? 80 : 60)); + medalLabel.setAlignmentX(CENTER_ALIGNMENT); + + JLabel nameLabel = new JLabel(playerName); + nameLabel.setFont(new Font("Roboto", isFirst ? Font.BOLD : Font.PLAIN, 20)); + nameLabel.setForeground(new Color(34, 139, 34)); // Vert forêt pour le nom + nameLabel.setAlignmentX(CENTER_ALIGNMENT); + + JLabel scoreLabel = new JLabel(Integer.toString(score)); + scoreLabel.setFont(new Font("Roboto", Font.BOLD, isFirst ? 32 : 28)); + scoreLabel.setForeground(new Color(58, 58, 58)); + scoreLabel.setAlignmentX(CENTER_ALIGNMENT); + + panel.add(medalLabel); + panel.add(Box.createRigidArea(new Dimension(0, 5))); + panel.add(nameLabel); + panel.add(Box.createRigidArea(new Dimension(0, 5))); + panel.add(scoreLabel); + + return panel; + } +} diff --git a/TestV2/src/fr/monkhanny/dorfromantik/gui/MainMenu.java b/TestV2/src/fr/monkhanny/dorfromantik/gui/MainMenu.java index ec2624b..a041e4e 100644 --- a/TestV2/src/fr/monkhanny/dorfromantik/gui/MainMenu.java +++ b/TestV2/src/fr/monkhanny/dorfromantik/gui/MainMenu.java @@ -8,13 +8,17 @@ import fr.monkhanny.dorfromantik.Options; import javax.swing.*; import java.awt.*; -import java.awt.event.ComponentAdapter; -import java.awt.event.ComponentEvent; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + public class MainMenu extends JFrame { private Title titleLabel; private ButtonPanel buttonPanel; + private JPanel leaderboardContainer; // Conteneur pour le leaderboard + private Leaderboard currentLeaderboard; // Référence au leaderboard actuel + private JButton toggleLeaderboardButton; // Bouton pour basculer entre les leaderboards public MainMenu() { // Charger les polices pour le titre et les boutons @@ -39,10 +43,39 @@ public class MainMenu extends JFrame { this.titleLabel = new Title("Dorfromantik", Options.BASE_TITLE_FONT_SIZE); background.add(titleLabel, BorderLayout.NORTH); - // Panneau des boutons avec style personnalisé + // Panneau des boutons avec style personnalisé (à gauche) this.buttonPanel = new ButtonPanel(Options.BASE_BUTTON_FONT_SIZE); background.add(buttonPanel, BorderLayout.WEST); + // Panel contenant le leaderboard avec espace à droite (pour pas qu'il soit collé au bord) + JPanel leaderboardWrapper = new JPanel(); + leaderboardWrapper.setLayout(new BorderLayout()); + leaderboardWrapper.setOpaque(false); // Fond transparent pour laisser voir le background + leaderboardWrapper.setBorder(BorderFactory.createEmptyBorder(20, 10, 20, 20)); // Ajout de marges internes + + // Conteneur du leaderboard + leaderboardContainer = new JPanel(); + leaderboardContainer.setLayout(new BorderLayout()); + leaderboardContainer.setOpaque(false); // Fond transparent pour laisser voir le background + leaderboardWrapper.add(leaderboardContainer, BorderLayout.CENTER); + background.add(leaderboardWrapper, BorderLayout.EAST); + + // Initialisation du premier leaderboard (LeaderboardWorldwide) + currentLeaderboard = new LeaderboardWorldWide(); + leaderboardContainer.add(currentLeaderboard, BorderLayout.CENTER); + + // Bouton pour basculer entre les leaderboards + toggleLeaderboardButton = new JButton("Changement de classement"); + toggleLeaderboardButton.setFont(new Font("Arial", Font.BOLD, 16)); + toggleLeaderboardButton.setBackground(new Color(64, 0, 128)); + toggleLeaderboardButton.setForeground(Color.WHITE); + toggleLeaderboardButton.setFocusPainted(false); + toggleLeaderboardButton.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + leaderboardContainer.add(toggleLeaderboardButton, BorderLayout.SOUTH); + + // Ajouter l'action du bouton + toggleLeaderboardButton.addActionListener(new LeaderboardToggleActionListener(leaderboardContainer, currentLeaderboard)); + setVisible(true); } diff --git a/TestV2/src/fr/monkhanny/dorfromantik/listeners/LeaderboardToggleActionListener.java b/TestV2/src/fr/monkhanny/dorfromantik/listeners/LeaderboardToggleActionListener.java new file mode 100644 index 0000000..fef5fd6 --- /dev/null +++ b/TestV2/src/fr/monkhanny/dorfromantik/listeners/LeaderboardToggleActionListener.java @@ -0,0 +1,35 @@ +package fr.monkhanny.dorfromantik.gui; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.BorderLayout; + +public class LeaderboardToggleActionListener implements ActionListener { + + private boolean showingWorldwide = true; + private JPanel leaderboardContainer; + private Leaderboard currentLeaderboard; + + // Constructeur qui reçoit le conteneur du leaderboard + public LeaderboardToggleActionListener(JPanel leaderboardContainer, Leaderboard currentLeaderboard) { + this.leaderboardContainer = leaderboardContainer; + this.currentLeaderboard = currentLeaderboard; + } + + @Override + public void actionPerformed(ActionEvent e) { + // Basculer entre les deux leaderboards + leaderboardContainer.remove(currentLeaderboard); + if (showingWorldwide) { + currentLeaderboard = new LeaderboardByTier(); // Leaderboard par tranche + } else { + currentLeaderboard = new LeaderboardWorldWide(); // Leaderboard avec les meilleurs joueurs du monde + } + showingWorldwide = !showingWorldwide; + + leaderboardContainer.add(currentLeaderboard, BorderLayout.CENTER); + leaderboardContainer.revalidate(); + leaderboardContainer.repaint(); + } +} diff --git a/TestV2/src/fr/monkhanny/dorfromantik/utils/Database.java b/TestV2/src/fr/monkhanny/dorfromantik/utils/Database.java index ad6e91c..f5479f3 100644 --- a/TestV2/src/fr/monkhanny/dorfromantik/utils/Database.java +++ b/TestV2/src/fr/monkhanny/dorfromantik/utils/Database.java @@ -1,11 +1,14 @@ package fr.monkhanny.dorfromantik.utils; + import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; import java.sql.ResultSet; import java.sql.PreparedStatement; +import java.util.ArrayList; +import java.util.List; public class Database { // Chargement des variables d'environnement @@ -102,6 +105,29 @@ public class Database { } +/** + * Récupère les meilleurs scores des joueurs (limite de 10 scores) + * @return une liste de résultats sous forme de tableau d'objets contenant le nom du joueur et son score + */ + public List getTopPlayers() throws SQLException { + List topPlayers = new ArrayList<>(); + + String query = "SELECT username, score FROM Scores ORDER BY score DESC LIMIT 10"; + try (Statement stmt = this.database.createStatement(); + ResultSet rs = stmt.executeQuery(query)) { + + while (rs.next()) { + String username = rs.getString("username"); + if (username == null || username.trim().isEmpty()) { + username = "Joueur Anonyme"; // Remplacer par "Joueur Anonyme" si le pseudo est vide ou nul + } + int score = rs.getInt("score"); + topPlayers.add(new PlayerScore(username, score)); + } + } + + return topPlayers; + } public void close() { try { diff --git a/TestV2/src/fr/monkhanny/dorfromantik/utils/PlayerScore.java b/TestV2/src/fr/monkhanny/dorfromantik/utils/PlayerScore.java new file mode 100644 index 0000000..2f156c6 --- /dev/null +++ b/TestV2/src/fr/monkhanny/dorfromantik/utils/PlayerScore.java @@ -0,0 +1,22 @@ +package fr.monkhanny.dorfromantik.utils; + +/** + * Représente un score d'un joueur avec son nom et son score. + */ +public class PlayerScore { + private String username; + private int score; + + public PlayerScore(String username, int score) { + this.username = username; + this.score = score; + } + + public String getUsername() { + return username; + } + + public int getScore() { + return score; + } +}