From 4e8e947ff558263f9a023853e91092d07548141b Mon Sep 17 00:00:00 2001 From: Richard3il Date: Sat, 28 Mar 2026 08:16:44 +0100 Subject: [PATCH] Ajout menu et boule(Bug sur cette derniere) --- linea/BouleBonus.java | 75 ++++++++++++++++++++++++++ linea/Jeu.java | 122 ++++++++++++++++++++++++++++++++++++++++-- linea/Ligne.java | 7 ++- linea/LineaAppli.java | 65 +++++++++++++++++++++- linea/ZoneDessin.java | 114 ++++++++++++++++++++++++++++++++++++--- 5 files changed, 368 insertions(+), 15 deletions(-) create mode 100644 linea/BouleBonus.java diff --git a/linea/BouleBonus.java b/linea/BouleBonus.java new file mode 100644 index 0000000..7b95a0a --- /dev/null +++ b/linea/BouleBonus.java @@ -0,0 +1,75 @@ +package linea; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; + +public class BouleBonus extends ObjetGraphique { + + private double rayon = 15; + private double vitesse = 5.0; + private boolean estVerte; // true = bonus (niveau +1), false = malus (niveau -1) + private int frameCounter = 0; + + public BouleBonus(double x, double y, boolean estVerte) { + this.x = x; + this.y = y; + this.estVerte = estVerte; + + if (estVerte) { + this.couleur = new Color(0.0f, 0.8f, 0.0f); // Vert + } else { + this.couleur = new Color(0.8f, 0.0f, 0.0f); // Rouge + } + } + + public double getRayon() { + return rayon; + } + + public boolean isVerte() { + return estVerte; + } + + @Override + void Afficher(Graphics g) { + Graphics2D g2D = (Graphics2D) g; + + // Effet de pulsation (le rayon augmente/diminue) + double rayonAffiche = rayon + Math.sin(frameCounter * 0.1) * 3; + + // Dessiner le cercle rempli + g2D.setColor(couleur); + g2D.fillOval((int)(x - rayonAffiche/2), (int)(y - rayonAffiche), + (int)rayonAffiche, (int)rayonAffiche); + + // Contour + g2D.setStroke(new BasicStroke(2.0f)); + g2D.setColor(estVerte ? new Color(0.0f, 1.0f, 0.0f) : new Color(1.0f, 0.0f, 0.0f)); + g2D.drawOval((int)(x - rayonAffiche/2), (int)(y - rayonAffiche), + (int)rayonAffiche, (int)rayonAffiche); + + frameCounter++; + } + + @Override + void Animer() { + // Déplacement vers la gauche (même vitesse que la ligne) + x -= vitesse; + } + + // Vérifier collision avec le cercle + public boolean collisionAvec(Cercle c) { + double cx = c.getX(); + double cy = c.getY(); + double cRayon = c.getRayon(); + + double dist = Math.hypot(cx - x, cy - y); + return dist <= (rayon + cRayon); + } + + public void setVitesse(double vitesse) { + this.vitesse = vitesse; + } +} diff --git a/linea/Jeu.java b/linea/Jeu.java index 7061980..e286a81 100644 --- a/linea/Jeu.java +++ b/linea/Jeu.java @@ -11,8 +11,10 @@ import java.util.ArrayList; import java.util.List; import javax.swing.JFrame; import javax.swing.JLabel; +import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; +import javax.swing.JScrollPane; import javax.swing.Timer; public class Jeu implements KeyListener, ActionListener { @@ -25,7 +27,7 @@ public class Jeu implements KeyListener, ActionListener { protected Cercle demiCercleArriere; protected Ligne ligne; - private int _niv = 1; + private int _niv; protected Timer horloge; protected double score = 0; protected JLabel labScore; @@ -36,6 +38,7 @@ public class Jeu implements KeyListener, ActionListener { private int mortsSansCompte = 0; private int tempsSansCompteSec = 0; private long debutPartieMs = 0; + private boolean immortel = false; private int meilleurActuel() { return idCompte > 0 ? db.getMeilleurScoreParCompte(idCompte) : meilleurSansCompte; @@ -63,9 +66,10 @@ public class Jeu implements KeyListener, ActionListener { //------------------------------------------------------------------------- // CONSTRUCTEUR //------------------------------------------------------------------------- - public Jeu(DatabaseConnection db, int idCompte) { + public Jeu(DatabaseConnection db, int idCompte, int niveau) { this.db = db; this.idCompte = idCompte; + this._niv = niveau; labScore = new JLabel(); labScore.setText("

score : 0

"); @@ -113,6 +117,75 @@ public class Jeu implements KeyListener, ActionListener { return true; } + private int choisirNouveauNiveau() { + // Générer les niveaux dynamiquement jusqu'à 100 + String[] niveaux = new String[100]; + for (int i = 1; i <= 100; i++) { + niveaux[i - 1] = genererLabelNiveau(i); + } + + JList list = new JList<>(niveaux); + list.setSelectedIndex(_niv - 1); + list.setVisibleRowCount(15); + JScrollPane scrollPane = new JScrollPane(list); + scrollPane.setPreferredSize(new java.awt.Dimension(350, 350)); + + int result = JOptionPane.showConfirmDialog( + null, + scrollPane, + "🎮 Sélection du Niveau - Linea", + JOptionPane.OK_CANCEL_OPTION, + JOptionPane.QUESTION_MESSAGE + ); + + if (result == JOptionPane.OK_OPTION) { + return list.getSelectedIndex() + 1; + } + return -1; + } + + private String genererLabelNiveau(int niveau) { + if (niveau <= 2) { + return "⭐ Niveau " + niveau + " - Facile" + (niveau == 2 ? "+" : ""); + } else if (niveau <= 4) { + return "⭐⭐ Niveau " + niveau + " - Moyen" + (niveau == 4 ? "+" : ""); + } else if (niveau <= 6) { + return "⭐⭐⭐ Niveau " + niveau + " - Difficile" + (niveau == 6 ? "+" : ""); + } else if (niveau <= 8) { + return "⭐⭐⭐⭐ Niveau " + niveau + " - Très Difficile" + (niveau == 8 ? "+" : ""); + } else if (niveau <= 10) { + return "⭐⭐⭐⭐⭐ Niveau " + niveau + " - Expert" + (niveau == 10 ? "+" : ""); + } else if (niveau <= 12) { + return "🔥 Niveau " + niveau + " - Cauchemar" + (niveau == 12 ? "+" : ""); + } else if (niveau <= 14) { + return "🔥 Niveau " + niveau + " - Chaos" + (niveau == 14 ? "+" : ""); + } else if (niveau <= 16) { + return "💀 Niveau " + niveau + " - Infernal" + (niveau == 16 ? "+" : ""); + } else if (niveau <= 18) { + return "💀 Niveau " + niveau + " - Apocalypse" + (niveau == 18 ? "+" : ""); + } else if (niveau <= 20) { + return "⚡ Niveau " + niveau + " - Extrême" + (niveau == 20 ? "+" : ""); + } else if (niveau <= 30) { + return "⚡ Niveau " + niveau + " - Infini"; + } else if (niveau <= 50) { + return "∞ Niveau " + niveau + " - Au-delà"; + } else { + return "🌌 Niveau " + niveau + " - Cosmos"; + } + } + + private void choisirModeImmortel() { + int result = JOptionPane.showConfirmDialog( + null, + "Activer le mode IMMORTEL ? 🛡️\n(Vous ne pourrez pas mourir)", + "Mode Immortel", + JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE + ); + + immortel = (result == JOptionPane.YES_OPTION); + } + //------------------------------------------------------------------------- // METHODES DE GESTION DU JEU //------------------------------------------------------------------------- @@ -141,7 +214,13 @@ public class Jeu implements KeyListener, ActionListener { } public void demarrer() { - JFrame fenetre = new JFrame("Linea Game"); + // Demander si le mode immortel est activé + choisirModeImmortel(); + + // Passer le flag immortel à l'écran + ecran.setImmortel(immortel); + + JFrame fenetre = new JFrame("Linea Game" + (immortel ? " [MODE IMMORTEL 🛡️]" : "")); // Initialise les objets une première fois initialiserPartie(); @@ -165,6 +244,12 @@ public class Jeu implements KeyListener, ActionListener { score = 0; labScore.setText("

score : 0

"); + // Demander le mode immortel à chaque reset + choisirModeImmortel(); + + // Passer le flag immortel à l'écran + ecran.setImmortel(immortel); + // Ré-initialisation des objets graphiques initialiserPartie(); debutPartieMs = System.currentTimeMillis(); @@ -181,8 +266,26 @@ public class Jeu implements KeyListener, ActionListener { @Override public void actionPerformed(ActionEvent e) { ecran.traiterBoucleAnimation(); + + // Vérifier si un bonus a été récupéré + int bonus = ecran.getBonusRecupere(); + if (bonus != 0) { + ecran.reinitialiserBonus(); + int nouveauNiveau = _niv + bonus; + + // Limiter le niveau entre 1 et 100 + if (nouveauNiveau < 1) { + nouveauNiveau = 1; + } else if (nouveauNiveau > 100) { + nouveauNiveau = 100; + } + + _niv = nouveauNiveau; + resetLevel(); + return; + } - if (ecran.aCollision()) { + if (ecran.aCollision() && !immortel) { horloge.stop(); int scoreActuel = (int) score; @@ -192,7 +295,7 @@ public class Jeu implements KeyListener, ActionListener { rafraichirMeilleurScore(); while (true) { - Object[] options = {"Relancer", "Changer de compte", "Voir stats", "Quitter"}; + Object[] options = {"Relancer", "Changer de compte", "Changer de niveau", "Voir stats", "Quitter"}; int choix = JOptionPane.showOptionDialog(null, "Perdu\nScore : " + scoreActuel + "\nMeilleur : " + meilleurActuel(), "Game Over", @@ -212,6 +315,15 @@ public class Jeu implements KeyListener, ActionListener { continue; } if (choix == 2) { + int nouveauNiveau = choisirNouveauNiveau(); + if (nouveauNiveau > 0) { + _niv = nouveauNiveau; + resetLevel(); + break; + } + continue; + } + if (choix == 3) { JOptionPane.showMessageDialog(null, statsActuelles(), "Statistiques", JOptionPane.INFORMATION_MESSAGE); continue; } diff --git a/linea/Ligne.java b/linea/Ligne.java index e6a22b6..e81d3c3 100644 --- a/linea/Ligne.java +++ b/linea/Ligne.java @@ -8,7 +8,7 @@ import java.util.ArrayList; public class Ligne extends ObjetGraphique{ - private int nbSegments = 400; + private int nbSegments = 4000; private double xCercle = 400; private Segment SegCourant; // vitesse de déplacement (augmente légèrement chaque frame) @@ -134,6 +134,11 @@ public class Ligne extends ObjetGraphique{ return false; } + // Obtenir la vitesse actuelle de la ligne (pour les boules bonus) + public double getVitesse() { + return vitesse; + } + // distance minimale entre un point (px,py) et un segment (x1,y1)-(x2,y2) private double pointSegmentDistance(double px, double py, double x1, double y1, double x2, double y2) { double vx = x2 - x1; diff --git a/linea/LineaAppli.java b/linea/LineaAppli.java index e2ff307..d6356f5 100644 --- a/linea/LineaAppli.java +++ b/linea/LineaAppli.java @@ -1,7 +1,9 @@ package linea; import java.util.List; +import javax.swing.JList; import javax.swing.JOptionPane; +import javax.swing.JScrollPane; import javax.swing.UIManager; public class LineaAppli { @@ -24,6 +26,63 @@ public class LineaAppli { ); } + private static int choisirNiveau() { + // Générer les niveaux dynamiquement jusqu'à 100 + String[] niveaux = new String[100]; + for (int i = 1; i <= 100; i++) { + niveaux[i - 1] = genererLabelNiveau(i); + } + + JList list = new JList<>(niveaux); + list.setSelectedIndex(0); + list.setVisibleRowCount(15); + JScrollPane scrollPane = new JScrollPane(list); + scrollPane.setPreferredSize(new java.awt.Dimension(350, 350)); + + int result = JOptionPane.showConfirmDialog( + null, + scrollPane, + "🎮 Sélection du Niveau - Linea", + JOptionPane.OK_CANCEL_OPTION, + JOptionPane.QUESTION_MESSAGE + ); + + if (result == JOptionPane.OK_OPTION) { + return list.getSelectedIndex() + 1; + } + return 1; + } + + private static String genererLabelNiveau(int niveau) { + if (niveau <= 2) { + return "⭐ Niveau " + niveau + " - Facile" + (niveau == 2 ? "+" : ""); + } else if (niveau <= 4) { + return "⭐⭐ Niveau " + niveau + " - Moyen" + (niveau == 4 ? "+" : ""); + } else if (niveau <= 6) { + return "⭐⭐⭐ Niveau " + niveau + " - Difficile" + (niveau == 6 ? "+" : ""); + } else if (niveau <= 8) { + return "⭐⭐⭐⭐ Niveau " + niveau + " - Très Difficile" + (niveau == 8 ? "+" : ""); + } else if (niveau <= 10) { + return "⭐⭐⭐⭐⭐ Niveau " + niveau + " - Expert" + (niveau == 10 ? "+" : ""); + } else if (niveau <= 12) { + return "🔥 Niveau " + niveau + " - Cauchemar" + (niveau == 12 ? "+" : ""); + } else if (niveau <= 14) { + return "🔥 Niveau " + niveau + " - Chaos" + (niveau == 14 ? "+" : ""); + } else if (niveau <= 16) { + return "💀 Niveau " + niveau + " - Infernal" + (niveau == 16 ? "+" : ""); + } else if (niveau <= 18) { + return "💀 Niveau " + niveau + " - Apocalypse" + (niveau == 18 ? "+" : ""); + } else if (niveau <= 20) { + return "⚡ Niveau " + niveau + " - Extrême" + (niveau == 20 ? "+" : ""); + } else if (niveau <= 30) { + return "⚡ Niveau " + niveau + " - Infini"; + } else if (niveau <= 50) { + return "∞ Niveau " + niveau + " - Au-delà"; + } else { + return "🌌 Niveau " + niveau + " - Cosmos"; + } + } + private static Integer menuComptes(DatabaseConnection db) { while (true) { Object[] options = {"Sélectionner", "Créer", "Supprimer", "Retour"}; @@ -93,13 +152,15 @@ public class LineaAppli { switch (choix) { case 1 -> { - new Jeu(db, -1).demarrer(); + int niveau = choisirNiveau(); + new Jeu(db, -1, niveau).demarrer(); return; } case 0 -> { Integer idCompte = menuComptes(db); if (idCompte != null) { - new Jeu(db, idCompte).demarrer(); + int niveau = choisirNiveau(); + new Jeu(db, idCompte, niveau).demarrer(); return; } } diff --git a/linea/ZoneDessin.java b/linea/ZoneDessin.java index 37da296..9730a0b 100644 --- a/linea/ZoneDessin.java +++ b/linea/ZoneDessin.java @@ -23,12 +23,33 @@ public class ZoneDessin extends JPanel { private boolean collisionOccur = false; // indique si le cercle a déjà été sur la ligne (début de la phase de maintien) private boolean hadBeenOnLine = false; + // mode immortel - ignore les collisions + private boolean immortel = false; + // liste des boules bonus + private ArrayList boolesBonus = new ArrayList(); + // compteur pour générer les boules à intervalle régulier + private int compteurBoule = 0; + private int intervalleBoule = 80; // générer une boule tous les 80 frames + // type de bonus récupéré (-1 = rouge, 1 = vert, 0 = aucun) + private int bonusRecupere = 0; public ZoneDessin(){ setLayout(new BorderLayout()); setPreferredSize(new Dimension(800, 600)); setBackground(new Color(220,170,0)); } + + public void setImmortel(boolean immortel) { + this.immortel = immortel; + } + + public int getBonusRecupere() { + return bonusRecupere; + } + + public void reinitialiserBonus() { + bonusRecupere = 0; + } // Ajout d'un objet graphique à la zone de dessin public void ajouterObjet(ObjetGraphique unObjet) { @@ -48,9 +69,50 @@ public class ZoneDessin extends JPanel { return; } - // 1. on déplace chaque objet graphique - for (ObjetGraphique obj : listeObjets){ - obj.Animer(); + // --- 0. Récupérer la ligne pour synchroniser les boules --- + Ligne ligneObjet = null; + for (ObjetGraphique obj : listeObjets) { + if (obj instanceof Ligne) { + ligneObjet = (Ligne) obj; + break; + } + } + + // --- 1. Générer une boule au bord droit sur la ligne --- + compteurBoule++; + if (compteurBoule >= intervalleBoule && ligneObjet != null) { + compteurBoule = 0; + boolean estVerte = Math.random() < 0.7; + + // On récupère le Y du dernier segment de la ligne (bord droit de l'écran) + // Note: Si votre classe Ligne n'a pas de méthode pour avoir le Y à X=800, + // utilisez une valeur proche de la fin de votre liste de segments. + double spawnX = 800; + double spawnY = 300; // Valeur par défaut + + // On crée la boule au bord droit (800) + BouleBonus boule = new BouleBonus(spawnX, spawnY, estVerte); + + // On lui donne la vitesse actuelle de la ligne pour qu'elle suive le mouvement + boule.setVitesse(ligneObjet.getVitesse()); + boolesBonus.add(boule); + } + + // --- 2. Animation des objets --- + for (ObjetGraphique obj : listeObjets) obj.Animer(); + + // Mettre à jour la vitesse des boules (car la ligne accélère avec le temps) + if (ligneObjet != null) { + for (BouleBonus boule : boolesBonus) { + boule.setVitesse(ligneObjet.getVitesse()); + boule.Animer(); + } + } + + // Les boules bougent via leur propre Animer() qui ajuste leur vitesse + + for (BouleBonus boule : boolesBonus) { + boule.Animer(); } // 2. vérifier collisions entre une Ligne et un Cercle @@ -67,9 +129,12 @@ public class ZoneDessin extends JPanel { // Si le cercle n'est plus en contact (distance > rayon) // alors le joueur perd (il doit maintenir le contact). if (!l.collisionAvec(c)) { - collisionOccur = true; - estArrete = true; - break; + // Ignorer la collision si on est en mode immortel + if (!immortel) { + collisionOccur = true; + estArrete = true; + break; + } } } } @@ -77,8 +142,35 @@ public class ZoneDessin extends JPanel { if (estArrete) break; } } + + // 3. vérifier collisions entre les boules bonus et le cercle + for (int i = boolesBonus.size() - 1; i >= 0; i--) + { + BouleBonus boule = boolesBonus.get(i); + boolean collision = false; - // 3. on demande à redessiner + for (ObjetGraphique obj : listeObjets) { + if (obj instanceof Cercle) { + Cercle c = (Cercle) obj; + if (boule.collisionAvec(c)) { + // Si touché : on définit le bonus et on détruit la boule + bonusRecupere = boule.isVerte() ? 1 : -1; + boolesBonus.remove(i); + collision = true; + break; + } + } + } + + //4. Détruire la boule si elle dépasse le joueur sans être touchée --- + // Le cercle est à X = 400. Si la boule est à X < 350, elle est "passée". + if (!collision && boule.getX() < 350) { + boolesBonus.remove(i); + // On ne change pas bonusRecupere ici (donc rien ne se passe) + } + } + + // 5. on demande à redessiner repaint(); } @@ -93,6 +185,11 @@ public class ZoneDessin extends JPanel { for (ObjetGraphique obj : listeObjets) { obj.Afficher(g); } + + // Afficher les boules bonus + for (BouleBonus boule : boolesBonus) { + boule.Afficher(g); + } } // Indique si une collision est survenue @@ -103,9 +200,12 @@ public class ZoneDessin extends JPanel { // Réinitialise l'état de la zone de dessin et supprime les objets graphiques public void reinitialiser() { listeObjets.clear(); + boolesBonus.clear(); estArrete = false; collisionOccur = false; hadBeenOnLine = false; + bonusRecupere = 0; + compteurBoule = 0; repaint(); } } \ No newline at end of file