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