updateBoule/immortel

This commit is contained in:
2026-03-28 14:18:17 +01:00
parent 4e8e947ff5
commit 1e7f70ab6b
9 changed files with 679 additions and 147 deletions

BIN
Jeu.db

Binary file not shown.

View File

@@ -11,6 +11,14 @@ public class BouleBonus extends ObjetGraphique {
private double vitesse = 5.0; private double vitesse = 5.0;
private boolean estVerte; // true = bonus (niveau +1), false = malus (niveau -1) private boolean estVerte; // true = bonus (niveau +1), false = malus (niveau -1)
private int frameCounter = 0; private int frameCounter = 0;
private double vitesseVerticale = 0.0;
private double amplitudeOndulation = 0.2;
private double vitesseHorizontaleLisse = 0.0;
private double phaseOndulation = Math.random() * Math.PI * 2; // phase unique par boule
private static double clamp(double value, double min, double max) {
return Math.max(min, Math.min(max, value));
}
public BouleBonus(double x, double y, boolean estVerte) { public BouleBonus(double x, double y, boolean estVerte) {
this.x = x; this.x = x;
@@ -19,8 +27,14 @@ public class BouleBonus extends ObjetGraphique {
if (estVerte) { if (estVerte) {
this.couleur = new Color(0.0f, 0.8f, 0.0f); // Vert this.couleur = new Color(0.0f, 0.8f, 0.0f); // Vert
this.rayon = 15;
this.amplitudeOndulation = 0.45; // onde visible plus ample
this.vitesseHorizontaleLisse = 4.8;
} else { } else {
this.couleur = new Color(0.8f, 0.0f, 0.0f); // Rouge this.couleur = new Color(0.8f, 0.0f, 0.0f); // Rouge
this.rayon = 14;
this.amplitudeOndulation = 0.14;
this.vitesseHorizontaleLisse = 4.3;
} }
} }
@@ -37,20 +51,18 @@ public class BouleBonus extends ObjetGraphique {
Graphics2D g2D = (Graphics2D) g; Graphics2D g2D = (Graphics2D) g;
// Effet de pulsation (le rayon augmente/diminue) // Effet de pulsation (le rayon augmente/diminue)
double rayonAffiche = rayon + Math.sin(frameCounter * 0.1) * 3; double rayonAffiche = rayon + Math.sin(frameCounter * 0.12) * 1.5;
// Dessiner le cercle rempli // Dessiner le cercle rempli (centré sur x,y)
g2D.setColor(couleur); g2D.setColor(couleur);
g2D.fillOval((int)(x - rayonAffiche/2), (int)(y - rayonAffiche), g2D.fillOval((int)(x - rayonAffiche), (int)(y - rayonAffiche),
(int)rayonAffiche, (int)rayonAffiche); (int)(2 * rayonAffiche), (int)(2 * rayonAffiche));
// Contour // Contour
g2D.setStroke(new BasicStroke(2.0f)); 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.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), g2D.drawOval((int)(x - rayonAffiche), (int)(y - rayonAffiche),
(int)rayonAffiche, (int)rayonAffiche); (int)(2 * rayonAffiche), (int)(2 * rayonAffiche));
frameCounter++;
} }
@Override @Override
@@ -59,6 +71,64 @@ public class BouleBonus extends ObjetGraphique {
x -= vitesse; x -= vitesse;
} }
public void animerAvecCible(double vitesseLigne, double cibleY) {
animerAvecCible(vitesseLigne, cibleY, 0.0);
}
public void animerAvecCible(double vitesseLigne, double cibleY, double cibleVitesseY) {
// Vertes: trajectoire fluide à intercepter. Rouges: poursuite plus nette avec fenêtre d'esquive.
double facteurHorizontal = estVerte ? 0.88 : 0.64;
double vitesseMax = estVerte ? 9.2 : 5.8;
double vitessePoursuite = estVerte ? 0.075 : 0.050; // meilleure réactivité
double limiteVerticale = estVerte ? 1.85 : 1.05; // accélération verticale
double amortissement = estVerte ? 0.87 : 0.81; // moins de friction
double zoneMorte = estVerte ? 18.0 : 16.0; // zone mort réduite
double vitesseVerticaleMax = estVerte ? 4.2 : 2.6; // vitesses verticales plus hautes
double vitesseLigneSecurisee = Math.max(0.0, vitesseLigne);
double vitesseCible = Math.min(vitesseMax, vitesseLigneSecurisee * facteurHorizontal);
if (!estVerte) {
// Les rouges gardent une vitesse plus stable d'une boule à l'autre.
vitesseCible = vitesseCible * 0.68 + 4.5 * 0.32;
}
double deltaVitesse = clamp(vitesseCible - vitesseHorizontaleLisse, -0.25, 0.25);
double vitesseMaxLocale = vitesseMax;
if (!estVerte && x < 380) {
// En fin d'écran, on plafonne un peu la vitesse pour laisser une fenêtre d'esquive stable.
double facteurApproche = clamp((380.0 - x) / 180.0, 0.0, 1.0);
vitesseMaxLocale = vitesseMax - (0.55 * facteurApproche);
}
vitesseHorizontaleLisse = clamp(vitesseHorizontaleLisse + deltaVitesse, 4.0, vitesseMaxLocale);
vitesse = vitesseHorizontaleLisse;
x -= vitesse;
double vitesseJoueurLimitee = clamp(cibleVitesseY, -6.0, 6.0);
// Verte: anticipation légère + oscillation. Rouge: AUCUNE anticipation → trajectoire lisible, esquivable.
double anticipation = estVerte ? vitesseJoueurLimitee * 3.2 : 0.0;
double cibleLisse = cibleY + anticipation + (estVerte ? Math.sin(frameCounter * 0.055 + phaseOndulation) * 45.0 : 0.0);
double deltaY = cibleLisse - y;
if (Math.abs(deltaY) < zoneMorte) {
deltaY = 0;
}
vitesseVerticale += clamp(deltaY * vitessePoursuite, -limiteVerticale, limiteVerticale);
vitesseVerticale *= amortissement;
vitesseVerticale = clamp(vitesseVerticale, -vitesseVerticaleMax, vitesseVerticaleMax);
double ondulation = Math.sin(frameCounter * 0.085 + (estVerte ? 0.0 : 1.1)) * amplitudeOndulation;
y += vitesseVerticale + ondulation;
frameCounter++;
if (y < 20) {
y = 20;
vitesseVerticale = 0;
} else if (y > 580) {
y = 580;
vitesseVerticale = 0;
}
}
// Vérifier collision avec le cercle // Vérifier collision avec le cercle
public boolean collisionAvec(Cercle c) { public boolean collisionAvec(Cercle c) {
double cx = c.getX(); double cx = c.getX();
@@ -66,7 +136,8 @@ public class BouleBonus extends ObjetGraphique {
double cRayon = c.getRayon(); double cRayon = c.getRayon();
double dist = Math.hypot(cx - x, cy - y); double dist = Math.hypot(cx - x, cy - y);
return dist <= (rayon + cRayon); double seuil = estVerte ? (rayon + cRayon - 6.0) : (rayon + cRayon - 9.0);
return dist <= seuil;
} }
public void setVitesse(double vitesse) { public void setVitesse(double vitesse) {

View File

@@ -71,6 +71,10 @@ public class Cercle extends ObjetGraphique{ // il s'agit plutôt d'arcs de cercl
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
public void Monter(){ public void Monter(){
montee = true; montee = true;
// Évite l'effet "chute incontrôlable" quand on reprend la montée tard.
if (vitesse > 2.0) {
vitesse = 2.0;
}
} }
@@ -108,31 +112,36 @@ public class Cercle extends ObjetGraphique{ // il s'agit plutôt d'arcs de cercl
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@Override @Override
void Animer() { void Animer() {
// pas est à prendre comme un "delta t" double gravite = 0.95;
double poussee = 1.45;
double amortissement = 0.92;
// chute libre
vitesse = vitesse + 9.81 * pas;
// impulsion
if (montee==true) { if (montee==true) {
vitesse = vitesse - impulsion *pas; vitesse -= poussee;
} else {
vitesse += gravite;
} }
depY = 1/2 * 9.81 + vitesse * pas; // Lissage global pour un ressenti plus régulier.
vitesse *= amortissement;
if (depY<-10) { if (vitesse < -6.5) {
depY=-10; vitesse = -6.5;
} }
if (depY>10){ if (vitesse > 6.5) {
depY =10; vitesse = 6.5;
} }
depY = vitesse;
y += depY; y += depY;
//position //position
if(y<= 0 + rayon){ if(y<= 0 + rayon){
y = 0 + rayon; y = 0 + rayon;
vitesse = 0;
}else if(y>=600 - rayon){ }else if(y>=600 - rayon){
y = 600 - rayon; y = 600 - rayon;
vitesse = 0;
} }
} }

View File

@@ -65,14 +65,6 @@ public class DatabaseConnection {
); );
"""; """;
String createNiveau = """
CREATE TABLE IF NOT EXISTS Niveau (
id_niveau INTEGER PRIMARY KEY AUTOINCREMENT,
nom TEXT,
nb_Objet INTEGER NOT NULL
);
""";
String createScore = """ String createScore = """
CREATE TABLE IF NOT EXISTS Score ( CREATE TABLE IF NOT EXISTS Score (
id_score INTEGER PRIMARY KEY AUTOINCREMENT, id_score INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -80,16 +72,23 @@ public class DatabaseConnection {
nb_mort INTEGER, nb_mort INTEGER,
temps_jeu INTEGER, temps_jeu INTEGER,
id_compte INTEGER, id_compte INTEGER,
id_niveau INTEGER, FOREIGN KEY(id_compte) REFERENCES Compte(id_compte)
FOREIGN KEY(id_compte) REFERENCES Compte(id_compte), );
FOREIGN KEY(id_niveau) REFERENCES Niveau(id_niveau) """;
String createProgressionCampagne = """
CREATE TABLE IF NOT EXISTS ProgressionCampagne (
id_compte INTEGER PRIMARY KEY,
niveau_debloque_max INTEGER NOT NULL DEFAULT 1,
FOREIGN KEY(id_compte) REFERENCES Compte(id_compte)
); );
"""; """;
try (Statement stmt = conn.createStatement()) { try (Statement stmt = conn.createStatement()) {
stmt.executeUpdate(createCompte); stmt.executeUpdate(createCompte);
stmt.executeUpdate(createNiveau);
stmt.executeUpdate(createScore); stmt.executeUpdate(createScore);
stmt.executeUpdate("DROP TABLE IF EXISTS Niveau");
stmt.executeUpdate(createProgressionCampagne);
System.out.println("Tables créées / existantes OK"); System.out.println("Tables créées / existantes OK");
} catch (SQLException e) { } catch (SQLException e) {
System.err.println("Erreur création tables : " + e.getMessage()); System.err.println("Erreur création tables : " + e.getMessage());
@@ -131,7 +130,11 @@ public class DatabaseConnection {
ps.setString(1, pseudo.trim()); ps.setString(1, pseudo.trim());
ps.executeUpdate(); ps.executeUpdate();
try (ResultSet rs = ps.getGeneratedKeys()) { try (ResultSet rs = ps.getGeneratedKeys()) {
if (rs.next()) return rs.getInt(1); if (rs.next()) {
int idCompte = rs.getInt(1);
initialiserProgressionCampagne(idCompte);
return idCompte;
}
} }
} catch (SQLException e) { } catch (SQLException e) {
System.err.println("Erreur création compte : " + e.getMessage()); System.err.println("Erreur création compte : " + e.getMessage());
@@ -155,8 +158,11 @@ public class DatabaseConnection {
public void supprimerCompte(int idCompte) { public void supprimerCompte(int idCompte) {
if (conn == null || idCompte <= 0) return; if (conn == null || idCompte <= 0) return;
try (PreparedStatement ps1 = conn.prepareStatement("DELETE FROM Score WHERE id_compte = ?"); try (PreparedStatement ps0 = conn.prepareStatement("DELETE FROM ProgressionCampagne WHERE id_compte = ?");
PreparedStatement ps1 = conn.prepareStatement("DELETE FROM Score WHERE id_compte = ?");
PreparedStatement ps2 = conn.prepareStatement("DELETE FROM Compte WHERE id_compte = ?")) { PreparedStatement ps2 = conn.prepareStatement("DELETE FROM Compte WHERE id_compte = ?")) {
ps0.setInt(1, idCompte);
ps0.executeUpdate();
ps1.setInt(1, idCompte); ps1.setInt(1, idCompte);
ps1.executeUpdate(); ps1.executeUpdate();
ps2.setInt(1, idCompte); ps2.setInt(1, idCompte);
@@ -181,6 +187,53 @@ public class DatabaseConnection {
return pseudos; return pseudos;
} }
private void initialiserProgressionCampagne(int idCompte) {
if (conn == null || idCompte <= 0) return;
String sql = "INSERT OR IGNORE INTO ProgressionCampagne (id_compte, niveau_debloque_max) VALUES (?, 1)";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, idCompte);
ps.executeUpdate();
} catch (SQLException e) {
System.err.println("Erreur init progression campagne : " + e.getMessage());
}
}
public int getNiveauDebloqueCampagne(int idCompte) {
if (conn == null || idCompte <= 0) return 1;
initialiserProgressionCampagne(idCompte);
String sql = "SELECT niveau_debloque_max FROM ProgressionCampagne WHERE id_compte = ?";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, idCompte);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
int niveau = rs.getInt("niveau_debloque_max");
if (niveau < 1) return 1;
return Math.min(100, niveau);
}
}
} catch (SQLException e) {
System.err.println("Erreur lecture progression campagne : " + e.getMessage());
}
return 1;
}
public void debloquerNiveauCampagne(int idCompte, int niveauTermine) {
if (conn == null || idCompte <= 0) return;
int niveauCible = Math.min(100, Math.max(1, niveauTermine + 1));
initialiserProgressionCampagne(idCompte);
String sql = "UPDATE ProgressionCampagne SET niveau_debloque_max = MAX(niveau_debloque_max, ?) WHERE id_compte = ?";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, niveauCible);
ps.setInt(2, idCompte);
ps.executeUpdate();
} catch (SQLException e) {
System.err.println("Erreur mise à jour progression campagne : " + e.getMessage());
}
}
public String getStatsParCompte(int idCompte) { public String getStatsParCompte(int idCompte) {
if (conn == null || idCompte <= 0) { if (conn == null || idCompte <= 0) {
return "Aucune statistique disponible."; return "Aucune statistique disponible.";
@@ -207,5 +260,18 @@ public class DatabaseConnection {
} }
return "Aucune statistique disponible."; return "Aucune statistique disponible.";
} }
public String getStatsCampagneParCompte(int idCompte) {
if (conn == null || idCompte <= 0) {
return "Campagne : non disponible.";
}
int niveauMax = getNiveauDebloqueCampagne(idCompte);
int niveauxTermines = Math.max(0, niveauMax - 1);
return "Campagne\n"
+ "Niveau max débloqué : " + niveauMax
+ "\nNiveaux terminés : " + niveauxTermines;
}
} }

Binary file not shown.

View File

@@ -29,9 +29,11 @@ public class Jeu implements KeyListener, ActionListener {
private int _niv; private int _niv;
protected Timer horloge; protected Timer horloge;
protected JFrame fenetre;
protected double score = 0; protected double score = 0;
protected JLabel labScore; protected JLabel labScore;
protected JLabel labMeilleurScore; protected JLabel labMeilleurScore;
protected JLabel labNiveau;
private DatabaseConnection db; private DatabaseConnection db;
private int idCompte; private int idCompte;
private int meilleurSansCompte = 0; private int meilleurSansCompte = 0;
@@ -39,6 +41,7 @@ public class Jeu implements KeyListener, ActionListener {
private int tempsSansCompteSec = 0; private int tempsSansCompteSec = 0;
private long debutPartieMs = 0; private long debutPartieMs = 0;
private boolean immortel = false; private boolean immortel = false;
private final boolean modeCampagne;
private int meilleurActuel() { private int meilleurActuel() {
return idCompte > 0 ? db.getMeilleurScoreParCompte(idCompte) : meilleurSansCompte; return idCompte > 0 ? db.getMeilleurScoreParCompte(idCompte) : meilleurSansCompte;
@@ -46,11 +49,11 @@ public class Jeu implements KeyListener, ActionListener {
private String statsActuelles() { private String statsActuelles() {
if (idCompte > 0) { if (idCompte > 0) {
return db.getStatsParCompte(idCompte); return db.getStatsParCompte(idCompte) + "\n\n" + db.getStatsCampagneParCompte(idCompte);
} }
return "Nombre de morts : " + mortsSansCompte return "💀 Nombre de morts: " + mortsSansCompte
+ "\nTemps de jeu total : " + tempsSansCompteSec + " s" + "\n⏱️ Temps total: " + tempsSansCompteSec + "s"
+ "\nMeilleur score : " + meilleurSansCompte; + "\n🏆 Meilleur score: " + meilleurSansCompte;
} }
private void enregistrerPartie(int scoreActuel, int tempsPartieSec) { private void enregistrerPartie(int scoreActuel, int tempsPartieSec) {
@@ -67,26 +70,173 @@ public class Jeu implements KeyListener, ActionListener {
// CONSTRUCTEUR // CONSTRUCTEUR
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
public Jeu(DatabaseConnection db, int idCompte, int niveau) { public Jeu(DatabaseConnection db, int idCompte, int niveau) {
this(db, idCompte, niveau, false);
}
public Jeu(DatabaseConnection db, int idCompte, int niveau, boolean modeCampagne) {
this.db = db; this.db = db;
this.idCompte = idCompte; this.idCompte = idCompte;
this._niv = niveau; this._niv = niveau;
this.modeCampagne = modeCampagne;
labScore = new JLabel(); labScore = new JLabel();
labScore.setText("<html><h3>score : 0</h3></html>"); labScore.setText("<html><h3>score : 0</h3></html>");
labMeilleurScore = new JLabel(); labMeilleurScore = new JLabel();
labNiveau = new JLabel();
JPanel panneauScores = new JPanel(new FlowLayout(FlowLayout.LEFT, 20, 0)); JPanel panneauScores = new JPanel(new FlowLayout(FlowLayout.LEFT, 20, 0));
panneauScores.setOpaque(false); panneauScores.setOpaque(false);
panneauScores.add(labScore); panneauScores.add(labScore);
panneauScores.add(labMeilleurScore); panneauScores.add(labMeilleurScore);
panneauScores.add(labNiveau);
ecran.add(panneauScores, BorderLayout.NORTH); ecran.add(panneauScores, BorderLayout.NORTH);
rafraichirMeilleurScore(); rafraichirMeilleurScore();
rafraichirNiveau();
} }
private void rafraichirMeilleurScore() { private void rafraichirMeilleurScore() {
labMeilleurScore.setText("<html><h3>meilleur : " + meilleurActuel() + "</h3></html>"); labMeilleurScore.setText("<html><h3>meilleur : " + meilleurActuel() + "</h3></html>");
} }
private void rafraichirNiveau() {
labNiveau.setText("<html><h3>niveau : " + _niv + "</h3></html>");
}
private void rafraichirTitreFenetre() {
if (fenetre == null) {
return;
}
String titre = modeCampagne ? "Linea Game [CAMPAGNE]" : "Linea Game";
fenetre.setTitle(titre + (immortel ? " [MODE IMMORTEL 🛡️]" : ""));
}
private String categorieNiveau(int niveau) {
if (niveau <= 2) return "Facile";
if (niveau <= 4) return "Moyen";
if (niveau <= 6) return "Difficile";
if (niveau <= 8) return "Tres Difficile";
if (niveau <= 10) return "Expert";
if (niveau <= 12) return "Cauchemar";
if (niveau <= 14) return "Chaos";
if (niveau <= 16) return "Infernal";
if (niveau <= 18) return "Apocalypse";
if (niveau <= 20) return "Extreme";
if (niveau <= 30) return "Infini";
if (niveau <= 50) return "Au-dela";
return "Cosmos";
}
private void appliquerThemeNiveau() {
String categorie = categorieNiveau(_niv);
Color fond;
Color couleurLigne;
Color couleurAvant;
Color couleurArriere;
Color couleurTexte;
switch (categorie) {
case "Facile":
fond = new Color(225, 245, 225);
couleurLigne = new Color(45, 120, 45);
couleurAvant = new Color(55, 185, 80);
couleurArriere = new Color(175, 70, 70);
couleurTexte = new Color(20, 50, 20);
break;
case "Moyen":
fond = new Color(215, 235, 250);
couleurLigne = new Color(40, 95, 150);
couleurAvant = new Color(50, 165, 120);
couleurArriere = new Color(185, 80, 85);
couleurTexte = new Color(20, 45, 80);
break;
case "Difficile":
fond = new Color(250, 235, 200);
couleurLigne = new Color(155, 95, 40);
couleurAvant = new Color(195, 145, 55);
couleurArriere = new Color(175, 70, 40);
couleurTexte = new Color(85, 55, 20);
break;
case "Tres Difficile":
fond = new Color(245, 215, 195);
couleurLigne = new Color(145, 70, 40);
couleurAvant = new Color(185, 110, 65);
couleurArriere = new Color(175, 55, 45);
couleurTexte = new Color(80, 35, 25);
break;
case "Expert":
fond = new Color(210, 190, 235);
couleurLigne = new Color(105, 55, 160);
couleurAvant = new Color(130, 85, 200);
couleurArriere = new Color(170, 60, 95);
couleurTexte = new Color(45, 20, 70);
break;
case "Cauchemar":
fond = new Color(175, 160, 210);
couleurLigne = new Color(85, 65, 150);
couleurAvant = new Color(120, 90, 190);
couleurArriere = new Color(155, 55, 110);
couleurTexte = new Color(245, 245, 245);
break;
case "Chaos":
fond = new Color(205, 120, 120);
couleurLigne = new Color(170, 40, 45);
couleurAvant = new Color(225, 115, 40);
couleurArriere = new Color(200, 30, 60);
couleurTexte = new Color(245, 245, 245);
break;
case "Infernal":
fond = new Color(165, 70, 55);
couleurLigne = new Color(190, 35, 25);
couleurAvant = new Color(235, 95, 25);
couleurArriere = new Color(210, 25, 20);
couleurTexte = new Color(245, 245, 245);
break;
case "Apocalypse":
fond = new Color(120, 40, 45);
couleurLigne = new Color(210, 30, 40);
couleurAvant = new Color(245, 95, 35);
couleurArriere = new Color(225, 20, 35);
couleurTexte = new Color(245, 245, 245);
break;
case "Extreme":
fond = new Color(70, 70, 70);
couleurLigne = new Color(225, 225, 225);
couleurAvant = new Color(255, 235, 70);
couleurArriere = new Color(240, 80, 80);
couleurTexte = new Color(245, 245, 245);
break;
case "Infini":
fond = new Color(35, 55, 85);
couleurLigne = new Color(95, 170, 255);
couleurAvant = new Color(70, 220, 255);
couleurArriere = new Color(180, 80, 255);
couleurTexte = new Color(245, 245, 245);
break;
case "Au-dela":
fond = new Color(20, 30, 70);
couleurLigne = new Color(120, 155, 255);
couleurAvant = new Color(80, 205, 255);
couleurArriere = new Color(205, 95, 255);
couleurTexte = new Color(245, 245, 245);
break;
default:
fond = new Color(10, 15, 45);
couleurLigne = new Color(140, 120, 255);
couleurAvant = new Color(120, 225, 255);
couleurArriere = new Color(235, 95, 255);
couleurTexte = new Color(245, 245, 245);
break;
}
ecran.setCouleurFond(fond);
ligne.setCouleurLigne(couleurLigne);
demiCercleAvant.setCouleur(couleurAvant);
demiCercleArriere.setCouleur(couleurArriere);
labScore.setForeground(couleurTexte);
labMeilleurScore.setForeground(couleurTexte);
labNiveau.setForeground(couleurTexte);
}
private boolean choisirNouveauCompte() { private boolean choisirNouveauCompte() {
List<String> pseudos = new ArrayList<>(db.getPseudos()); List<String> pseudos = new ArrayList<>(db.getPseudos());
pseudos.add(0, "Sans compte"); pseudos.add(0, "Sans compte");
@@ -202,15 +352,24 @@ public class Jeu implements KeyListener, ActionListener {
demiCercleAvant = new Cercle(90, -180); demiCercleAvant = new Cercle(90, -180);
demiCercleArriere = new Cercle(90, 180); demiCercleArriere = new Cercle(90, 180);
ligne = new Ligne(_niv); ligne = new Ligne(_niv);
ecran.setNiveau(_niv);
// 3. Configuration visuelle // 3. En mode immortel, positionner les cercles loin (la force les attirera vers la ligne)
demiCercleArriere.setCouleur(new Color(0.8f, 0.0f, 0.0f)); // En mode normal, ils restent au centre (y = 200 par défaut du constructeur)
demiCercleAvant.setCouleur(new Color(0.0f, 0.8f, 0.0f)); if (immortel) {
demiCercleAvant.y = -300;
demiCercleArriere.y = 300;
}
// 4. Ajout à l'écran (l'ordre définit la superposition) // 4. Configuration visuelle
appliquerThemeNiveau();
// 5. Ajout à l'écran (l'ordre définit la superposition)
ecran.ajouterObjet(demiCercleArriere); ecran.ajouterObjet(demiCercleArriere);
ecran.ajouterObjet(ligne); ecran.ajouterObjet(ligne);
ecran.ajouterObjet(demiCercleAvant); ecran.ajouterObjet(demiCercleAvant);
rafraichirNiveau();
} }
public void demarrer() { public void demarrer() {
@@ -220,7 +379,8 @@ public class Jeu implements KeyListener, ActionListener {
// Passer le flag immortel à l'écran // Passer le flag immortel à l'écran
ecran.setImmortel(immortel); ecran.setImmortel(immortel);
JFrame fenetre = new JFrame("Linea Game" + (immortel ? " [MODE IMMORTEL 🛡️]" : "")); fenetre = new JFrame();
rafraichirTitreFenetre();
// Initialise les objets une première fois // Initialise les objets une première fois
initialiserPartie(); initialiserPartie();
@@ -244,11 +404,9 @@ public class Jeu implements KeyListener, ActionListener {
score = 0; score = 0;
labScore.setText("<html><h3>score : 0</h3></html>"); labScore.setText("<html><h3>score : 0</h3></html>");
// Demander le mode immortel à chaque reset
choisirModeImmortel();
// Passer le flag immortel à l'écran // Passer le flag immortel à l'écran
ecran.setImmortel(immortel); ecran.setImmortel(immortel);
rafraichirTitreFenetre();
// Ré-initialisation des objets graphiques // Ré-initialisation des objets graphiques
initialiserPartie(); initialiserPartie();
@@ -271,6 +429,7 @@ public class Jeu implements KeyListener, ActionListener {
int bonus = ecran.getBonusRecupere(); int bonus = ecran.getBonusRecupere();
if (bonus != 0) { if (bonus != 0) {
ecran.reinitialiserBonus(); ecran.reinitialiserBonus();
int niveauActuel = _niv;
int nouveauNiveau = _niv + bonus; int nouveauNiveau = _niv + bonus;
// Limiter le niveau entre 1 et 100 // Limiter le niveau entre 1 et 100
@@ -280,6 +439,10 @@ public class Jeu implements KeyListener, ActionListener {
nouveauNiveau = 100; nouveauNiveau = 100;
} }
if (modeCampagne && idCompte > 0 && bonus > 0) {
db.debloquerNiveauCampagne(idCompte, niveauActuel);
}
_niv = nouveauNiveau; _niv = nouveauNiveau;
resetLevel(); resetLevel();
return; return;
@@ -295,18 +458,46 @@ public class Jeu implements KeyListener, ActionListener {
rafraichirMeilleurScore(); rafraichirMeilleurScore();
while (true) { while (true) {
Object[] options = {"Relancer", "Changer de compte", "Changer de niveau", "Voir stats", "Quitter"}; Object[] options = modeCampagne
? new Object[]{"▶️ Relancer", "📊 Statistiques", "❌ Quitter"}
: new Object[]{"▶️ Relancer", "👤 Compte", "📈 Niveau", "📊 Statistiques", "❌ Quitter"};
String message = "🏁 GAME OVER\n\n"
+ "Score: " + scoreActuel + "\n"
+ "Meilleur: " + meilleurActuel() + "\n"
+ "Durée: " + tempsPartieSec + "s";
int choix = JOptionPane.showOptionDialog(null, int choix = JOptionPane.showOptionDialog(null,
"Perdu\nScore : " + scoreActuel + "\nMeilleur : " + meilleurActuel(), message,
"Game Over", "🏁 Fin de Partie",
JOptionPane.DEFAULT_OPTION, JOptionPane.DEFAULT_OPTION,
JOptionPane.INFORMATION_MESSAGE, JOptionPane.PLAIN_MESSAGE,
null, options, options[0]); null, options, options[0]);
if (choix == 0) { if (choix == 0) {
int modeRelance = JOptionPane.showConfirmDialog(
null,
"Relancer en mode immortel ?",
"Relancer",
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE
);
if (modeRelance == JOptionPane.CANCEL_OPTION || modeRelance == JOptionPane.CLOSED_OPTION) {
continue;
}
immortel = (modeRelance == JOptionPane.YES_OPTION);
ecran.setImmortel(immortel);
resetLevel(); resetLevel();
break; break;
} }
if (modeCampagne) {
if (choix == 1) {
JOptionPane.showMessageDialog(null, statsActuelles(), "📊 Statistiques", JOptionPane.INFORMATION_MESSAGE);
continue;
}
System.exit(0);
}
if (choix == 1) { if (choix == 1) {
if (choisirNouveauCompte()) { if (choisirNouveauCompte()) {
resetLevel(); resetLevel();
@@ -324,7 +515,7 @@ public class Jeu implements KeyListener, ActionListener {
continue; continue;
} }
if (choix == 3) { if (choix == 3) {
JOptionPane.showMessageDialog(null, statsActuelles(), "Statistiques", JOptionPane.INFORMATION_MESSAGE); JOptionPane.showMessageDialog(null, statsActuelles(), "📊 Statistiques", JOptionPane.INFORMATION_MESSAGE);
continue; continue;
} }
System.exit(0); System.exit(0);

View File

@@ -12,11 +12,11 @@ public class Ligne extends ObjetGraphique{
private double xCercle = 400; private double xCercle = 400;
private Segment SegCourant; private Segment SegCourant;
// vitesse de déplacement (augmente légèrement chaque frame) // vitesse de déplacement (augmente légèrement chaque frame)
private double vitesse = 5.0; private double vitesse = 4.8;
// croissance initiale (fractionnelle) appliquée chaque frame // croissance initiale (fractionnelle) appliquée chaque frame
private double croissance = 0.001; // ~0.1% initial private double croissance = 0.0008; // montée plus progressive
// facteur qui amplifie la croissance elle-même (pour accélérer la montée) // facteur qui amplifie la croissance elle-même (pour accélérer la montée)
private double facteurCroissance = 1.00003; // croissance augmente légèrement private double facteurCroissance = 1.00002; // accélération plus douce
private int niveau = 1; // niveau de difficulté, à augmenter pour rendre le jeu plus difficile private int niveau = 1; // niveau de difficulté, à augmenter pour rendre le jeu plus difficile
@@ -95,43 +95,50 @@ public class Ligne extends ObjetGraphique{
} }
// appliquer la croissance (vitesse *= 1 + croissance) // appliquer la croissance (vitesse *= 1 + croissance)
vitesse *= (1.0 + croissance + (niveau * 0.00001)); // augmenter la croissance avec le niveau vitesse *= (1.0 + croissance + (niveau * 0.000006)); // hausse niveau plus progressive
// augmenter légèrement la croissance pour que l'accélération s'amplifie // augmenter légèrement la croissance pour que l'accélération s'amplifie
croissance *= facteurCroissance; croissance *= facteurCroissance;
} }
// Indique si l'axe horizontal du cercle (cx) se trouve au niveau // Trouve le segment couvrant l'abscisse cx (une seule itération)
// d'un des segments de la ligne -> le cercle est "sur la ligne" private Segment trouverSegmentAuX(double cx) {
public boolean estSurLaLigne(double cx) {
for (Segment seg : segments) { for (Segment seg : segments) {
double x1 = seg.x; double x1 = seg.x;
double x2 = seg.x + seg.xLong; double x2 = seg.x + seg.xLong;
if ((cx >= Math.min(x1, x2)) && (cx <= Math.max(x1, x2))) { if (cx >= Math.min(x1, x2) && cx <= Math.max(x1, x2)) {
return true; return seg;
} }
} }
return false; return null;
}
// Résultat de contact : null = pas sur la ligne, sinon double[]{ligneY, distance}
public double[] contactInfo(double cx, double cy, double rayon) {
Segment seg = trouverSegmentAuX(cx);
if (seg == null) return null;
double ligneY = (seg.xLong != 0) ? seg.y + ((cx - seg.x) / seg.xLong) * seg.yLong : seg.y;
double dist = pointSegmentDistance(cx, cy, seg.x, seg.y, seg.x + seg.xLong, seg.y + seg.yLong);
return new double[]{ligneY, dist};
}
// Indique si l'axe horizontal du cercle (cx) se trouve au niveau
// d'un des segments de la ligne -> le cercle est "sur la ligne"
public boolean estSurLaLigne(double cx) {
return trouverSegmentAuX(cx) != null;
} }
// Vérifie la collision entre la ligne (segments) et un cercle // Vérifie la collision entre la ligne (segments) et un cercle
public boolean collisionAvec(Cercle c) { public boolean collisionAvec(Cercle c) {
double cx = c.getX(); double[] info = contactInfo(c.getX(), c.getY(), c.getRayon());
double cy = c.getY(); return info != null && info[1] <= c.getRayon();
double rayon = c.getRayon();
for (Segment seg : segments) {
double x1 = seg.x;
double y1 = seg.y;
double x2 = seg.x + seg.xLong;
double y2 = seg.y + seg.yLong;
double dist = pointSegmentDistance(cx, cy, x1, y1, x2, y2);
if (dist <= rayon) {
return true;
} }
}
return false; // Retourne la coordonnée Y de la ligne à l'abscisse cx
public double getYAuX(double cx) {
Segment seg = trouverSegmentAuX(cx);
if (seg == null || seg.xLong == 0) return 300;
return seg.y + ((cx - seg.x) / seg.xLong) * seg.yLong;
} }
// Obtenir la vitesse actuelle de la ligne (pour les boules bonus) // Obtenir la vitesse actuelle de la ligne (pour les boules bonus)
@@ -139,6 +146,12 @@ public class Ligne extends ObjetGraphique{
return vitesse; return vitesse;
} }
public void setCouleurLigne(Color couleur) {
for (Segment seg : segments) {
seg.setCouleur(couleur);
}
}
// distance minimale entre un point (px,py) et un segment (x1,y1)-(x2,y2) // 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) { private double pointSegmentDistance(double px, double py, double x1, double y1, double x2, double y2) {
double vx = x2 - x1; double vx = x2 - x1;

View File

@@ -1,13 +1,29 @@
package linea; package linea;
import java.awt.GridLayout;
import java.util.List; import java.util.List;
import javax.swing.ButtonGroup;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList; import javax.swing.JList;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.UIManager; import javax.swing.UIManager;
public class LineaAppli { public class LineaAppli {
private static class SelectionJeu {
final int idCompte;
final boolean modeCampagne;
SelectionJeu(int idCompte, boolean modeCampagne) {
this.idCompte = idCompte;
this.modeCampagne = modeCampagne;
}
}
private static String choisirPseudo(DatabaseConnection db, String message, int messageType) { private static String choisirPseudo(DatabaseConnection db, String message, int messageType) {
List<String> pseudos = db.getPseudos(); List<String> pseudos = db.getPseudos();
if (pseudos.isEmpty()) { if (pseudos.isEmpty()) {
@@ -50,7 +66,38 @@ public class LineaAppli {
if (result == JOptionPane.OK_OPTION) { if (result == JOptionPane.OK_OPTION) {
return list.getSelectedIndex() + 1; return list.getSelectedIndex() + 1;
} }
return 1; return -1;
}
private static int choisirNiveauCampagne(DatabaseConnection db, int idCompte) {
int niveauMaxDebloque = db.getNiveauDebloqueCampagne(idCompte);
if (niveauMaxDebloque < 1) {
niveauMaxDebloque = 1;
}
String[] niveaux = new String[niveauMaxDebloque];
for (int i = 1; i <= niveauMaxDebloque; i++) {
niveaux[i - 1] = genererLabelNiveau(i);
}
JList<String> list = new JList<>(niveaux);
list.setSelectedIndex(niveauMaxDebloque - 1);
list.setVisibleRowCount(15);
JScrollPane scrollPane = new JScrollPane(list);
scrollPane.setPreferredSize(new java.awt.Dimension(350, 350));
int result = JOptionPane.showConfirmDialog(
null,
scrollPane,
"🏆 Campagne - Niveaux débloqués (1 à " + niveauMaxDebloque + ")",
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE
);
if (result == JOptionPane.OK_OPTION) {
return list.getSelectedIndex() + 1;
}
return -1;
} }
private static String genererLabelNiveau(int niveau) { private static String genererLabelNiveau(int niveau) {
@@ -129,6 +176,63 @@ public class LineaAppli {
} }
} }
private static SelectionJeu choisirCompteEtModeRapide(DatabaseConnection db) {
while (true) {
List<String> pseudos = db.getPseudos();
JPanel panel = new JPanel(new GridLayout(0, 1, 8, 8));
panel.add(new JLabel("Compte :"));
String[] optionsCompte = new String[pseudos.size() + 2];
optionsCompte[0] = "Sans compte";
for (int i = 0; i < pseudos.size(); i++) {
optionsCompte[i + 1] = pseudos.get(i);
}
optionsCompte[optionsCompte.length - 1] = "Gérer les comptes...";
JComboBox<String> comboCompte = new JComboBox<>(optionsCompte);
panel.add(comboCompte);
panel.add(new JLabel("Mode :"));
JRadioButton modeClassique = new JRadioButton("Classique", true);
JRadioButton modeCampagne = new JRadioButton("Campagne");
ButtonGroup group = new ButtonGroup();
group.add(modeClassique);
group.add(modeCampagne);
JPanel panelMode = new JPanel(new GridLayout(1, 2, 8, 0));
panelMode.add(modeClassique);
panelMode.add(modeCampagne);
panel.add(panelMode);
int result = JOptionPane.showConfirmDialog(
null,
panel,
"Jouer rapidement",
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE
);
if (result != JOptionPane.OK_OPTION) {
return null;
}
String choixCompte = (String) comboCompte.getSelectedItem();
if (choixCompte == null) {
return null;
}
if ("Gérer les comptes...".equals(choixCompte)) {
menuComptes(db);
continue;
}
int idCompte = "Sans compte".equals(choixCompte) ? -1 : db.getIdParPseudo(choixCompte);
boolean campagne = modeCampagne.isSelected();
return new SelectionJeu(idCompte, campagne);
}
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// Classe de base de l'application, rien à modifier ici // Classe de base de l'application, rien à modifier ici
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@@ -140,31 +244,37 @@ public class LineaAppli {
db.createTables(); db.createTables();
while (true) { while (true) {
Object[] options = {"Comptes", "Sans compte", "Quitter"}; SelectionJeu selection = choisirCompteEtModeRapide(db);
int choix = JOptionPane.showOptionDialog(null, if (selection == null) {
"Choisissez une action :",
"Menu", JOptionPane.DEFAULT_OPTION,
JOptionPane.QUESTION_MESSAGE, null, options, options[0]);
if (choix == JOptionPane.CLOSED_OPTION || choix == 2) {
return; return;
} }
switch (choix) { if (!selection.modeCampagne) {
case 1 -> {
int niveau = choisirNiveau(); int niveau = choisirNiveau();
new Jeu(db, -1, niveau).demarrer(); if (niveau > 0) {
new Jeu(db, selection.idCompte, niveau).demarrer();
return; return;
} }
case 0 -> { continue;
Integer idCompte = menuComptes(db); }
if (idCompte != null) {
int niveau = choisirNiveau(); if (selection.idCompte > 0) {
new Jeu(db, idCompte, niveau).demarrer(); int niveau = choisirNiveauCampagne(db, selection.idCompte);
if (niveau > 0) {
new Jeu(db, selection.idCompte, niveau, true).demarrer();
return;
}
continue;
}
JOptionPane.showMessageDialog(
null,
"Campagne sans compte : progression non sauvegardée.",
"Campagne",
JOptionPane.INFORMATION_MESSAGE
);
new Jeu(db, -1, 1, true).demarrer();
return; return;
} }
} }
} }
}
}
}

View File

@@ -29,7 +29,10 @@ public class ZoneDessin extends JPanel {
private ArrayList<BouleBonus> boolesBonus = new ArrayList<BouleBonus>(); private ArrayList<BouleBonus> boolesBonus = new ArrayList<BouleBonus>();
// compteur pour générer les boules à intervalle régulier // compteur pour générer les boules à intervalle régulier
private int compteurBoule = 0; private int compteurBoule = 0;
private int intervalleBoule = 80; // générer une boule tous les 80 frames private int intervalleBouleBase = 165; // moins de boules sur la durée
private int delaiInitialBoule = 97; // apparition initiale avancée de 3%
private int niveauActuel = 1;
private Double dernierJoueurY = null;
// type de bonus récupéré (-1 = rouge, 1 = vert, 0 = aucun) // type de bonus récupéré (-1 = rouge, 1 = vert, 0 = aucun)
private int bonusRecupere = 0; private int bonusRecupere = 0;
@@ -39,10 +42,24 @@ public class ZoneDessin extends JPanel {
setBackground(new Color(220,170,0)); setBackground(new Color(220,170,0));
} }
public void setCouleurFond(Color couleurFond) {
setBackground(couleurFond);
}
public void setImmortel(boolean immortel) { public void setImmortel(boolean immortel) {
this.immortel = immortel; this.immortel = immortel;
} }
public void setNiveau(int niveau) {
if (niveau < 1) {
niveauActuel = 1;
} else if (niveau > 100) {
niveauActuel = 100;
} else {
niveauActuel = niveau;
}
}
public int getBonusRecupere() { public int getBonusRecupere() {
return bonusRecupere; return bonusRecupere;
} }
@@ -69,6 +86,20 @@ public class ZoneDessin extends JPanel {
return; return;
} }
Cercle cercleReference = null;
for (ObjetGraphique obj : listeObjets) {
if (obj instanceof Cercle) {
cercleReference = (Cercle) obj;
break;
}
}
double joueurY = (cercleReference != null) ? cercleReference.getY() : 300;
double vitesseJoueurY = 0.0;
if (dernierJoueurY != null) {
vitesseJoueurY = joueurY - dernierJoueurY;
}
dernierJoueurY = joueurY;
// --- 0. Récupérer la ligne pour synchroniser les boules --- // --- 0. Récupérer la ligne pour synchroniser les boules ---
Ligne ligneObjet = null; Ligne ligneObjet = null;
for (ObjetGraphique obj : listeObjets) { for (ObjetGraphique obj : listeObjets) {
@@ -79,69 +110,109 @@ public class ZoneDessin extends JPanel {
} }
// --- 1. Générer une boule au bord droit sur la ligne --- // --- 1. Générer une boule au bord droit sur la ligne ---
double progression = Math.min(1.0, (niveauActuel - 1) / 25.0);
int intervalleBoule = (int) Math.round(intervalleBouleBase - progression * 20.0); // ~165 -> 145
double probaVerteBase = 0.35 - progression * 0.06; // ~35% -> 29%
double variationAleatoire = (Math.random() - 0.5) * 0.10; // +/- 5%
double probaVerte = Math.max(0.22, Math.min(0.45, probaVerteBase + variationAleatoire));
compteurBoule++; compteurBoule++;
if (compteurBoule >= intervalleBoule && ligneObjet != null) { if (compteurBoule >= intervalleBoule && ligneObjet != null) {
compteurBoule = 0; compteurBoule = 0;
boolean estVerte = Math.random() < 0.7; boolean estVerte = Math.random() < probaVerte;
// 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 spawnX = 800;
double spawnY = 300; // Valeur par défaut double spawnY;
if (estVerte) {
// Vertes: proches de la trajectoire du joueur pour être récupérables.
double margeVerte = 95.0 + progression * 45.0;
spawnY = joueurY + (Math.random() * (2.0 * margeVerte)) - margeVerte;
} else {
// Rouges: visent davantage le joueur, mais démarrent avec une marge d'esquive.
double offset = 220 + progression * 20.0 + Math.random() * 150.0;
spawnY = joueurY + (Math.random() < 0.5 ? -offset : offset);
}
if (spawnY < 20) spawnY = 20;
if (spawnY > 580) spawnY = 580;
if (!estVerte) {
// Marge suffisante pour esquiver, sans rendre les rouges inoffensives.
double distanceMin = 125.0;
if (Math.abs(spawnY - joueurY) < distanceMin) {
if (spawnY >= joueurY) {
spawnY = Math.min(580, joueurY + distanceMin);
} else {
spawnY = Math.max(20, joueurY - distanceMin);
}
}
}
// On crée la boule au bord droit (800) // On crée la boule au bord droit (800)
BouleBonus boule = new BouleBonus(spawnX, spawnY, estVerte); 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); boolesBonus.add(boule);
} }
// --- 2. Animation des objets --- // --- 2. Animation des objets ---
for (ObjetGraphique obj : listeObjets) obj.Animer(); for (ObjetGraphique obj : listeObjets) obj.Animer();
// Mettre à jour la vitesse des boules (car la ligne accélère avec le temps) // Mettre à jour et animer les boules (une seule fois par frame)
if (ligneObjet != null) { if (ligneObjet != null) {
for (BouleBonus boule : boolesBonus) { for (BouleBonus boule : boolesBonus) {
boule.setVitesse(ligneObjet.getVitesse()); boule.animerAvecCible(ligneObjet.getVitesse(), joueurY, vitesseJoueurY);
boule.Animer();
} }
} }
// Les boules bougent via leur propre Animer() qui ajuste leur vitesse // 2. vérifier collision entre la Ligne et le Cercle (une seule passe de segments)
if (ligneObjet != null && cercleReference != null) {
double[] info = ligneObjet.contactInfo(
cercleReference.getX(), cercleReference.getY(), cercleReference.getRayon());
for (BouleBonus boule : boolesBonus) { boolean enContact = (info != null) && (info[1] <= cercleReference.getRayon());
boule.Animer(); double ligneY = (info != null) ? info[0] : ligneObjet.getYAuX(cercleReference.getX());
}
// 2. vérifier collisions entre une Ligne et un Cercle // Phase initiale en mode immortel : force d'attraction depuis le début
for (ObjetGraphique obj : listeObjets) { if (!hadBeenOnLine && immortel) {
if (obj instanceof Ligne) { double delta = ligneY - cercleReference.y;
Ligne l = (Ligne) obj; cercleReference.vitesse += delta * 0.12;
for (ObjetGraphique other : listeObjets) {
if (other instanceof Cercle) { // Marquer le premier contact
Cercle c = (Cercle) other; if (enContact) {
// On commence à surveiller une fois que le centre du
// cercle est au-dessus d'un segment (le cercle est "sur la ligne").
if (l.estSurLaLigne(c.getX())) {
hadBeenOnLine = true; hadBeenOnLine = true;
// Si le cercle n'est plus en contact (distance > rayon) }
// alors le joueur perd (il doit maintenir le contact). } else if (hadBeenOnLine && immortel) {
if (!l.collisionAvec(c)) { // Phase maintenance : après le premier contact, maintenir le cercle sur la ligne
// Ignorer la collision si on est en mode immortel double rayon = cercleReference.getRayon();
if (!immortel) { double limite = ligneY - rayon;
double limiteBas = ligneY + rayon;
// Clamping : empêcher le cercle de sortir au-dessus
if (cercleReference.y < limite) {
cercleReference.y = limite;
if (cercleReference.vitesse < 0) cercleReference.vitesse *= -0.3;
}
// Clamping : empêcher le cercle de sortir en-dessous
else if (cercleReference.y > limiteBas) {
cercleReference.y = limiteBas;
if (cercleReference.vitesse > 0) cercleReference.vitesse *= -0.3;
}
} else if (info != null && !enContact && !immortel) {
// Mode normal : mort si hors contact
collisionOccur = true; collisionOccur = true;
estArrete = true; estArrete = true;
break; }
// Synchroniser tous les autres Cercle en mode immortel
if (immortel) {
for (ObjetGraphique obj : listeObjets) {
if (obj instanceof Cercle && obj != cercleReference) {
Cercle autre = (Cercle) obj;
autre.y = cercleReference.y;
autre.vitesse = cercleReference.vitesse;
} }
} }
} }
} }
}
if (estArrete) break;
}
}
// 3. vérifier collisions entre les boules bonus et le cercle // 3. vérifier collisions entre les boules bonus et le cercle
for (int i = boolesBonus.size() - 1; i >= 0; i--) for (int i = boolesBonus.size() - 1; i >= 0; i--)
@@ -164,7 +235,7 @@ public class ZoneDessin extends JPanel {
//4. Détruire la boule si elle dépasse le joueur sans être touchée --- //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". // Le cercle est à X = 400. Si la boule est à X < 350, elle est "passée".
if (!collision && boule.getX() < 350) { if (!collision && boule.getX() < 320) {
boolesBonus.remove(i); boolesBonus.remove(i);
// On ne change pas bonusRecupere ici (donc rien ne se passe) // On ne change pas bonusRecupere ici (donc rien ne se passe)
} }
@@ -205,7 +276,8 @@ public class ZoneDessin extends JPanel {
collisionOccur = false; collisionOccur = false;
hadBeenOnLine = false; hadBeenOnLine = false;
bonusRecupere = 0; bonusRecupere = 0;
compteurBoule = 0; compteurBoule = -delaiInitialBoule;
dernierJoueurY = null;
repaint(); repaint();
} }
} }