updateBoule/immortel
This commit is contained in:
@@ -11,6 +11,14 @@ public class BouleBonus extends ObjetGraphique {
|
||||
private double vitesse = 5.0;
|
||||
private boolean estVerte; // true = bonus (niveau +1), false = malus (niveau -1)
|
||||
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) {
|
||||
this.x = x;
|
||||
@@ -19,8 +27,14 @@ public class BouleBonus extends ObjetGraphique {
|
||||
|
||||
if (estVerte) {
|
||||
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 {
|
||||
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;
|
||||
|
||||
// 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.fillOval((int)(x - rayonAffiche/2), (int)(y - rayonAffiche),
|
||||
(int)rayonAffiche, (int)rayonAffiche);
|
||||
g2D.fillOval((int)(x - rayonAffiche), (int)(y - rayonAffiche),
|
||||
(int)(2 * rayonAffiche), (int)(2 * 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++;
|
||||
g2D.drawOval((int)(x - rayonAffiche), (int)(y - rayonAffiche),
|
||||
(int)(2 * rayonAffiche), (int)(2 * rayonAffiche));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -59,6 +71,64 @@ public class BouleBonus extends ObjetGraphique {
|
||||
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
|
||||
public boolean collisionAvec(Cercle c) {
|
||||
double cx = c.getX();
|
||||
@@ -66,7 +136,8 @@ public class BouleBonus extends ObjetGraphique {
|
||||
double cRayon = c.getRayon();
|
||||
|
||||
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) {
|
||||
|
||||
@@ -71,6 +71,10 @@ public class Cercle extends ObjetGraphique{ // il s'agit plutôt d'arcs de cercl
|
||||
//-------------------------------------------------------------------------
|
||||
public void Monter(){
|
||||
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
|
||||
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) {
|
||||
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) {
|
||||
depY=-10;
|
||||
if (vitesse < -6.5) {
|
||||
vitesse = -6.5;
|
||||
}
|
||||
if (depY>10){
|
||||
depY =10;
|
||||
if (vitesse > 6.5) {
|
||||
vitesse = 6.5;
|
||||
}
|
||||
y+=depY;
|
||||
|
||||
depY = vitesse;
|
||||
y += depY;
|
||||
|
||||
//position
|
||||
if(y<= 0 + rayon){
|
||||
y = 0 + rayon;
|
||||
vitesse = 0;
|
||||
}else if(y>=600 - rayon){
|
||||
y = 600 - rayon;
|
||||
vitesse = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 = """
|
||||
CREATE TABLE IF NOT EXISTS Score (
|
||||
id_score INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
@@ -80,16 +72,23 @@ public class DatabaseConnection {
|
||||
nb_mort INTEGER,
|
||||
temps_jeu INTEGER,
|
||||
id_compte INTEGER,
|
||||
id_niveau INTEGER,
|
||||
FOREIGN KEY(id_compte) REFERENCES Compte(id_compte),
|
||||
FOREIGN KEY(id_niveau) REFERENCES Niveau(id_niveau)
|
||||
FOREIGN KEY(id_compte) REFERENCES Compte(id_compte)
|
||||
);
|
||||
""";
|
||||
|
||||
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()) {
|
||||
stmt.executeUpdate(createCompte);
|
||||
stmt.executeUpdate(createNiveau);
|
||||
stmt.executeUpdate(createScore);
|
||||
stmt.executeUpdate("DROP TABLE IF EXISTS Niveau");
|
||||
stmt.executeUpdate(createProgressionCampagne);
|
||||
System.out.println("Tables créées / existantes OK");
|
||||
} catch (SQLException e) {
|
||||
System.err.println("Erreur création tables : " + e.getMessage());
|
||||
@@ -131,7 +130,11 @@ public class DatabaseConnection {
|
||||
ps.setString(1, pseudo.trim());
|
||||
ps.executeUpdate();
|
||||
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) {
|
||||
System.err.println("Erreur création compte : " + e.getMessage());
|
||||
@@ -155,8 +158,11 @@ public class DatabaseConnection {
|
||||
|
||||
public void supprimerCompte(int idCompte) {
|
||||
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 = ?")) {
|
||||
ps0.setInt(1, idCompte);
|
||||
ps0.executeUpdate();
|
||||
ps1.setInt(1, idCompte);
|
||||
ps1.executeUpdate();
|
||||
ps2.setInt(1, idCompte);
|
||||
@@ -181,6 +187,53 @@ public class DatabaseConnection {
|
||||
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) {
|
||||
if (conn == null || idCompte <= 0) {
|
||||
return "Aucune statistique disponible.";
|
||||
@@ -207,5 +260,18 @@ public class DatabaseConnection {
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BIN
linea/Jeu.db
BIN
linea/Jeu.db
Binary file not shown.
225
linea/Jeu.java
225
linea/Jeu.java
@@ -29,9 +29,11 @@ public class Jeu implements KeyListener, ActionListener {
|
||||
|
||||
private int _niv;
|
||||
protected Timer horloge;
|
||||
protected JFrame fenetre;
|
||||
protected double score = 0;
|
||||
protected JLabel labScore;
|
||||
protected JLabel labMeilleurScore;
|
||||
protected JLabel labNiveau;
|
||||
private DatabaseConnection db;
|
||||
private int idCompte;
|
||||
private int meilleurSansCompte = 0;
|
||||
@@ -39,6 +41,7 @@ public class Jeu implements KeyListener, ActionListener {
|
||||
private int tempsSansCompteSec = 0;
|
||||
private long debutPartieMs = 0;
|
||||
private boolean immortel = false;
|
||||
private final boolean modeCampagne;
|
||||
|
||||
private int meilleurActuel() {
|
||||
return idCompte > 0 ? db.getMeilleurScoreParCompte(idCompte) : meilleurSansCompte;
|
||||
@@ -46,11 +49,11 @@ public class Jeu implements KeyListener, ActionListener {
|
||||
|
||||
private String statsActuelles() {
|
||||
if (idCompte > 0) {
|
||||
return db.getStatsParCompte(idCompte);
|
||||
return db.getStatsParCompte(idCompte) + "\n\n" + db.getStatsCampagneParCompte(idCompte);
|
||||
}
|
||||
return "Nombre de morts : " + mortsSansCompte
|
||||
+ "\nTemps de jeu total : " + tempsSansCompteSec + " s"
|
||||
+ "\nMeilleur score : " + meilleurSansCompte;
|
||||
return "💀 Nombre de morts: " + mortsSansCompte
|
||||
+ "\n⏱️ Temps total: " + tempsSansCompteSec + "s"
|
||||
+ "\n🏆 Meilleur score: " + meilleurSansCompte;
|
||||
}
|
||||
|
||||
private void enregistrerPartie(int scoreActuel, int tempsPartieSec) {
|
||||
@@ -67,26 +70,173 @@ public class Jeu implements KeyListener, ActionListener {
|
||||
// CONSTRUCTEUR
|
||||
//-------------------------------------------------------------------------
|
||||
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.idCompte = idCompte;
|
||||
this._niv = niveau;
|
||||
this.modeCampagne = modeCampagne;
|
||||
labScore = new JLabel();
|
||||
labScore.setText("<html><h3>score : 0</h3></html>");
|
||||
|
||||
labMeilleurScore = new JLabel();
|
||||
labNiveau = new JLabel();
|
||||
|
||||
JPanel panneauScores = new JPanel(new FlowLayout(FlowLayout.LEFT, 20, 0));
|
||||
panneauScores.setOpaque(false);
|
||||
panneauScores.add(labScore);
|
||||
panneauScores.add(labMeilleurScore);
|
||||
panneauScores.add(labNiveau);
|
||||
ecran.add(panneauScores, BorderLayout.NORTH);
|
||||
rafraichirMeilleurScore();
|
||||
rafraichirNiveau();
|
||||
}
|
||||
|
||||
private void rafraichirMeilleurScore() {
|
||||
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() {
|
||||
List<String> pseudos = new ArrayList<>(db.getPseudos());
|
||||
pseudos.add(0, "Sans compte");
|
||||
@@ -202,15 +352,24 @@ public class Jeu implements KeyListener, ActionListener {
|
||||
demiCercleAvant = new Cercle(90, -180);
|
||||
demiCercleArriere = new Cercle(90, 180);
|
||||
ligne = new Ligne(_niv);
|
||||
ecran.setNiveau(_niv);
|
||||
|
||||
// 3. Configuration visuelle
|
||||
demiCercleArriere.setCouleur(new Color(0.8f, 0.0f, 0.0f));
|
||||
demiCercleAvant.setCouleur(new Color(0.0f, 0.8f, 0.0f));
|
||||
// 3. En mode immortel, positionner les cercles loin (la force les attirera vers la ligne)
|
||||
// En mode normal, ils restent au centre (y = 200 par défaut du constructeur)
|
||||
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(ligne);
|
||||
ecran.ajouterObjet(demiCercleAvant);
|
||||
|
||||
rafraichirNiveau();
|
||||
}
|
||||
|
||||
public void demarrer() {
|
||||
@@ -220,7 +379,8 @@ public class Jeu implements KeyListener, ActionListener {
|
||||
// Passer le flag immortel à l'écran
|
||||
ecran.setImmortel(immortel);
|
||||
|
||||
JFrame fenetre = new JFrame("Linea Game" + (immortel ? " [MODE IMMORTEL 🛡️]" : ""));
|
||||
fenetre = new JFrame();
|
||||
rafraichirTitreFenetre();
|
||||
|
||||
// Initialise les objets une première fois
|
||||
initialiserPartie();
|
||||
@@ -244,11 +404,9 @@ public class Jeu implements KeyListener, ActionListener {
|
||||
score = 0;
|
||||
labScore.setText("<html><h3>score : 0</h3></html>");
|
||||
|
||||
// Demander le mode immortel à chaque reset
|
||||
choisirModeImmortel();
|
||||
|
||||
// Passer le flag immortel à l'écran
|
||||
ecran.setImmortel(immortel);
|
||||
rafraichirTitreFenetre();
|
||||
|
||||
// Ré-initialisation des objets graphiques
|
||||
initialiserPartie();
|
||||
@@ -271,6 +429,7 @@ public class Jeu implements KeyListener, ActionListener {
|
||||
int bonus = ecran.getBonusRecupere();
|
||||
if (bonus != 0) {
|
||||
ecran.reinitialiserBonus();
|
||||
int niveauActuel = _niv;
|
||||
int nouveauNiveau = _niv + bonus;
|
||||
|
||||
// Limiter le niveau entre 1 et 100
|
||||
@@ -280,6 +439,10 @@ public class Jeu implements KeyListener, ActionListener {
|
||||
nouveauNiveau = 100;
|
||||
}
|
||||
|
||||
if (modeCampagne && idCompte > 0 && bonus > 0) {
|
||||
db.debloquerNiveauCampagne(idCompte, niveauActuel);
|
||||
}
|
||||
|
||||
_niv = nouveauNiveau;
|
||||
resetLevel();
|
||||
return;
|
||||
@@ -295,18 +458,46 @@ public class Jeu implements KeyListener, ActionListener {
|
||||
rafraichirMeilleurScore();
|
||||
|
||||
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,
|
||||
"Perdu\nScore : " + scoreActuel + "\nMeilleur : " + meilleurActuel(),
|
||||
"Game Over",
|
||||
message,
|
||||
"🏁 Fin de Partie",
|
||||
JOptionPane.DEFAULT_OPTION,
|
||||
JOptionPane.INFORMATION_MESSAGE,
|
||||
JOptionPane.PLAIN_MESSAGE,
|
||||
null, options, options[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();
|
||||
break;
|
||||
}
|
||||
if (modeCampagne) {
|
||||
if (choix == 1) {
|
||||
JOptionPane.showMessageDialog(null, statsActuelles(), "📊 Statistiques", JOptionPane.INFORMATION_MESSAGE);
|
||||
continue;
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
if (choix == 1) {
|
||||
if (choisirNouveauCompte()) {
|
||||
resetLevel();
|
||||
@@ -324,7 +515,7 @@ public class Jeu implements KeyListener, ActionListener {
|
||||
continue;
|
||||
}
|
||||
if (choix == 3) {
|
||||
JOptionPane.showMessageDialog(null, statsActuelles(), "Statistiques", JOptionPane.INFORMATION_MESSAGE);
|
||||
JOptionPane.showMessageDialog(null, statsActuelles(), "📊 Statistiques", JOptionPane.INFORMATION_MESSAGE);
|
||||
continue;
|
||||
}
|
||||
System.exit(0);
|
||||
|
||||
@@ -12,11 +12,11 @@ public class Ligne extends ObjetGraphique{
|
||||
private double xCercle = 400;
|
||||
private Segment SegCourant;
|
||||
// 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
|
||||
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)
|
||||
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
|
||||
|
||||
@@ -95,43 +95,50 @@ public class Ligne extends ObjetGraphique{
|
||||
}
|
||||
|
||||
// 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
|
||||
croissance *= facteurCroissance;
|
||||
}
|
||||
|
||||
|
||||
// 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) {
|
||||
// Trouve le segment couvrant l'abscisse cx (une seule itération)
|
||||
private Segment trouverSegmentAuX(double cx) {
|
||||
for (Segment seg : segments) {
|
||||
double x1 = seg.x;
|
||||
double x2 = seg.x + seg.xLong;
|
||||
if ((cx >= Math.min(x1, x2)) && (cx <= Math.max(x1, x2))) {
|
||||
return true;
|
||||
if (cx >= Math.min(x1, x2) && cx <= Math.max(x1, x2)) {
|
||||
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
|
||||
public boolean collisionAvec(Cercle c) {
|
||||
double cx = c.getX();
|
||||
double cy = c.getY();
|
||||
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;
|
||||
double[] info = contactInfo(c.getX(), c.getY(), c.getRayon());
|
||||
return info != null && info[1] <= c.getRayon();
|
||||
}
|
||||
}
|
||||
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)
|
||||
@@ -139,6 +146,12 @@ public class Ligne extends ObjetGraphique{
|
||||
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)
|
||||
private double pointSegmentDistance(double px, double py, double x1, double y1, double x2, double y2) {
|
||||
double vx = x2 - x1;
|
||||
|
||||
@@ -1,13 +1,29 @@
|
||||
package linea;
|
||||
|
||||
import java.awt.GridLayout;
|
||||
import java.util.List;
|
||||
import javax.swing.ButtonGroup;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JRadioButton;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.UIManager;
|
||||
|
||||
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) {
|
||||
List<String> pseudos = db.getPseudos();
|
||||
if (pseudos.isEmpty()) {
|
||||
@@ -50,7 +66,38 @@ public class LineaAppli {
|
||||
if (result == JOptionPane.OK_OPTION) {
|
||||
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) {
|
||||
@@ -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
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -140,31 +244,37 @@ public class LineaAppli {
|
||||
db.createTables();
|
||||
|
||||
while (true) {
|
||||
Object[] options = {"Comptes", "Sans compte", "Quitter"};
|
||||
int choix = JOptionPane.showOptionDialog(null,
|
||||
"Choisissez une action :",
|
||||
"Menu", JOptionPane.DEFAULT_OPTION,
|
||||
JOptionPane.QUESTION_MESSAGE, null, options, options[0]);
|
||||
|
||||
if (choix == JOptionPane.CLOSED_OPTION || choix == 2) {
|
||||
SelectionJeu selection = choisirCompteEtModeRapide(db);
|
||||
if (selection == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (choix) {
|
||||
case 1 -> {
|
||||
if (!selection.modeCampagne) {
|
||||
int niveau = choisirNiveau();
|
||||
new Jeu(db, -1, niveau).demarrer();
|
||||
if (niveau > 0) {
|
||||
new Jeu(db, selection.idCompte, niveau).demarrer();
|
||||
return;
|
||||
}
|
||||
case 0 -> {
|
||||
Integer idCompte = menuComptes(db);
|
||||
if (idCompte != null) {
|
||||
int niveau = choisirNiveau();
|
||||
new Jeu(db, idCompte, niveau).demarrer();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (selection.idCompte > 0) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,10 @@ public class ZoneDessin extends JPanel {
|
||||
private ArrayList<BouleBonus> boolesBonus = new ArrayList<BouleBonus>();
|
||||
// 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
|
||||
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)
|
||||
private int bonusRecupere = 0;
|
||||
|
||||
@@ -39,10 +42,24 @@ public class ZoneDessin extends JPanel {
|
||||
setBackground(new Color(220,170,0));
|
||||
}
|
||||
|
||||
public void setCouleurFond(Color couleurFond) {
|
||||
setBackground(couleurFond);
|
||||
}
|
||||
|
||||
public void setImmortel(boolean 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() {
|
||||
return bonusRecupere;
|
||||
}
|
||||
@@ -69,6 +86,20 @@ public class ZoneDessin extends JPanel {
|
||||
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 ---
|
||||
Ligne ligneObjet = null;
|
||||
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 ---
|
||||
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++;
|
||||
if (compteurBoule >= intervalleBoule && ligneObjet != null) {
|
||||
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 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)
|
||||
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)
|
||||
// Mettre à jour et animer les boules (une seule fois par frame)
|
||||
if (ligneObjet != null) {
|
||||
for (BouleBonus boule : boolesBonus) {
|
||||
boule.setVitesse(ligneObjet.getVitesse());
|
||||
boule.Animer();
|
||||
boule.animerAvecCible(ligneObjet.getVitesse(), joueurY, vitesseJoueurY);
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
boule.Animer();
|
||||
}
|
||||
boolean enContact = (info != null) && (info[1] <= cercleReference.getRayon());
|
||||
double ligneY = (info != null) ? info[0] : ligneObjet.getYAuX(cercleReference.getX());
|
||||
|
||||
// 2. vérifier collisions entre une Ligne et un Cercle
|
||||
for (ObjetGraphique obj : listeObjets) {
|
||||
if (obj instanceof Ligne) {
|
||||
Ligne l = (Ligne) obj;
|
||||
for (ObjetGraphique other : listeObjets) {
|
||||
if (other instanceof Cercle) {
|
||||
Cercle c = (Cercle) other;
|
||||
// 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())) {
|
||||
// Phase initiale en mode immortel : force d'attraction depuis le début
|
||||
if (!hadBeenOnLine && immortel) {
|
||||
double delta = ligneY - cercleReference.y;
|
||||
cercleReference.vitesse += delta * 0.12;
|
||||
|
||||
// Marquer le premier contact
|
||||
if (enContact) {
|
||||
hadBeenOnLine = true;
|
||||
// Si le cercle n'est plus en contact (distance > rayon)
|
||||
// alors le joueur perd (il doit maintenir le contact).
|
||||
if (!l.collisionAvec(c)) {
|
||||
// Ignorer la collision si on est en mode immortel
|
||||
if (!immortel) {
|
||||
}
|
||||
} else if (hadBeenOnLine && immortel) {
|
||||
// Phase maintenance : après le premier contact, maintenir le cercle sur la ligne
|
||||
double rayon = cercleReference.getRayon();
|
||||
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;
|
||||
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
|
||||
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 ---
|
||||
// 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);
|
||||
// On ne change pas bonusRecupere ici (donc rien ne se passe)
|
||||
}
|
||||
@@ -205,7 +276,8 @@ public class ZoneDessin extends JPanel {
|
||||
collisionOccur = false;
|
||||
hadBeenOnLine = false;
|
||||
bonusRecupere = 0;
|
||||
compteurBoule = 0;
|
||||
compteurBoule = -delaiInitialBoule;
|
||||
dernierJoueurY = null;
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user