2026-02-10 16:39:21 +01:00
|
|
|
package linea;
|
|
|
|
|
|
|
|
|
|
import java.awt.BorderLayout;
|
|
|
|
|
import java.awt.Color;
|
|
|
|
|
import java.awt.Dimension;
|
|
|
|
|
import java.awt.Graphics;
|
|
|
|
|
import java.awt.Graphics2D;
|
|
|
|
|
import java.awt.RenderingHints;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
|
|
|
|
|
import javax.swing.JPanel;
|
|
|
|
|
|
|
|
|
|
public class ZoneDessin extends JPanel {
|
|
|
|
|
|
|
|
|
|
private static final long serialVersionUID = 1L;
|
|
|
|
|
|
2026-03-28 17:19:34 +01:00
|
|
|
// arreter annimation
|
2026-02-10 16:39:21 +01:00
|
|
|
protected boolean estArrete = false;
|
|
|
|
|
|
|
|
|
|
// liste des objets graphiques
|
|
|
|
|
private ArrayList<ObjetGraphique> listeObjets = new ArrayList<ObjetGraphique>();
|
2026-03-28 17:19:34 +01:00
|
|
|
// indicateur d'une defaite
|
2026-02-23 09:41:54 +01:00
|
|
|
private boolean collisionOccur = false;
|
2026-03-28 17:19:34 +01:00
|
|
|
// indique si le cercle a déjà été sur la ligne
|
|
|
|
|
private boolean AEteSurLigne = false;
|
|
|
|
|
// mode immortel
|
|
|
|
|
private boolean immortel = false;
|
2026-03-28 08:16:44 +01:00
|
|
|
// liste des boules bonus
|
|
|
|
|
private ArrayList<BouleBonus> boolesBonus = new ArrayList<BouleBonus>();
|
|
|
|
|
// compteur pour générer les boules à intervalle régulier
|
|
|
|
|
private int compteurBoule = 0;
|
2026-03-28 14:18:17 +01:00
|
|
|
private int intervalleBouleBase = 165; // moins de boules sur la durée
|
2026-03-28 17:19:34 +01:00
|
|
|
private int delaiInitialBoule = 85; // apparition initiale légèrement plus tôt
|
2026-03-28 14:18:17 +01:00
|
|
|
private int niveauActuel = 1;
|
|
|
|
|
private Double dernierJoueurY = null;
|
2026-03-28 08:16:44 +01:00
|
|
|
// type de bonus récupéré (-1 = rouge, 1 = vert, 0 = aucun)
|
|
|
|
|
private int bonusRecupere = 0;
|
2026-02-10 16:39:21 +01:00
|
|
|
|
|
|
|
|
public ZoneDessin(){
|
|
|
|
|
setLayout(new BorderLayout());
|
|
|
|
|
setPreferredSize(new Dimension(800, 600));
|
|
|
|
|
setBackground(new Color(220,170,0));
|
|
|
|
|
}
|
2026-03-28 14:18:17 +01:00
|
|
|
|
|
|
|
|
public void setCouleurFond(Color couleurFond) {
|
|
|
|
|
setBackground(couleurFond);
|
|
|
|
|
}
|
2026-03-28 08:16:44 +01:00
|
|
|
|
|
|
|
|
public void setImmortel(boolean immortel) {
|
|
|
|
|
this.immortel = immortel;
|
|
|
|
|
}
|
2026-03-28 14:18:17 +01:00
|
|
|
|
|
|
|
|
public void setNiveau(int niveau) {
|
|
|
|
|
if (niveau < 1) {
|
|
|
|
|
niveauActuel = 1;
|
|
|
|
|
} else if (niveau > 100) {
|
|
|
|
|
niveauActuel = 100;
|
|
|
|
|
} else {
|
|
|
|
|
niveauActuel = niveau;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-03-28 08:16:44 +01:00
|
|
|
|
|
|
|
|
public int getBonusRecupere() {
|
|
|
|
|
return bonusRecupere;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void reinitialiserBonus() {
|
|
|
|
|
bonusRecupere = 0;
|
|
|
|
|
}
|
2026-02-10 16:39:21 +01:00
|
|
|
|
|
|
|
|
// Ajout d'un objet graphique à la zone de dessin
|
|
|
|
|
public void ajouterObjet(ObjetGraphique unObjet) {
|
|
|
|
|
listeObjets.add(unObjet);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void arreter(){
|
|
|
|
|
estArrete = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void demarrer(){
|
|
|
|
|
estArrete = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void traiterBoucleAnimation(){
|
|
|
|
|
if (estArrete==true) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-03-28 14:18:17 +01:00
|
|
|
|
|
|
|
|
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;
|
2026-02-10 16:39:21 +01:00
|
|
|
|
2026-03-28 17:19:34 +01:00
|
|
|
// Récupérer la ligne pour synchroniser les boules
|
2026-03-28 08:16:44 +01:00
|
|
|
Ligne ligneObjet = null;
|
|
|
|
|
for (ObjetGraphique obj : listeObjets) {
|
|
|
|
|
if (obj instanceof Ligne) {
|
|
|
|
|
ligneObjet = (Ligne) obj;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-28 17:19:34 +01:00
|
|
|
// Générer une boule
|
2026-03-28 14:18:17 +01:00
|
|
|
double progression = Math.min(1.0, (niveauActuel - 1) / 25.0);
|
|
|
|
|
int intervalleBoule = (int) Math.round(intervalleBouleBase - progression * 20.0); // ~165 -> 145
|
2026-03-28 17:19:34 +01:00
|
|
|
double probaVerteBase = 0.23 - progression * 0.04; // ~23% -> 19%
|
2026-03-28 14:18:17 +01:00
|
|
|
double variationAleatoire = (Math.random() - 0.5) * 0.10; // +/- 5%
|
2026-03-28 17:19:34 +01:00
|
|
|
double probaVerte = Math.max(0.10, Math.min(0.31, probaVerteBase + variationAleatoire));
|
2026-03-28 14:18:17 +01:00
|
|
|
|
2026-03-28 08:16:44 +01:00
|
|
|
compteurBoule++;
|
|
|
|
|
if (compteurBoule >= intervalleBoule && ligneObjet != null) {
|
|
|
|
|
compteurBoule = 0;
|
2026-03-28 14:18:17 +01:00
|
|
|
boolean estVerte = Math.random() < probaVerte;
|
|
|
|
|
|
|
|
|
|
double spawnX = 800;
|
|
|
|
|
double spawnY;
|
|
|
|
|
if (estVerte) {
|
2026-03-28 17:19:34 +01:00
|
|
|
// boules Vertes
|
2026-03-28 14:18:17 +01:00
|
|
|
double margeVerte = 95.0 + progression * 45.0;
|
|
|
|
|
spawnY = joueurY + (Math.random() * (2.0 * margeVerte)) - margeVerte;
|
|
|
|
|
} else {
|
2026-03-28 17:19:34 +01:00
|
|
|
// boules Rouges
|
2026-03-28 14:18:17 +01:00
|
|
|
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) {
|
2026-03-28 17:19:34 +01:00
|
|
|
// Marge suffisante pour esquiver
|
2026-03-28 14:18:17 +01:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-03-28 08:16:44 +01:00
|
|
|
|
2026-03-28 17:19:34 +01:00
|
|
|
// On crée la boule au bord droit
|
2026-03-28 08:16:44 +01:00
|
|
|
BouleBonus boule = new BouleBonus(spawnX, spawnY, estVerte);
|
|
|
|
|
boolesBonus.add(boule);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-28 17:19:34 +01:00
|
|
|
// Animation des objets
|
2026-03-28 08:16:44 +01:00
|
|
|
for (ObjetGraphique obj : listeObjets) obj.Animer();
|
|
|
|
|
|
2026-03-28 17:19:34 +01:00
|
|
|
// Mettre à jour et animer les boules
|
2026-03-28 08:16:44 +01:00
|
|
|
if (ligneObjet != null) {
|
|
|
|
|
for (BouleBonus boule : boolesBonus) {
|
2026-03-28 14:18:17 +01:00
|
|
|
boule.animerAvecCible(ligneObjet.getVitesse(), joueurY, vitesseJoueurY);
|
2026-03-28 17:19:34 +01:00
|
|
|
double yLigneLocal = ligneObjet.getYAuX(boule.getX());
|
|
|
|
|
boule.ajusterVitessePourDistanceLigne(yLigneLocal, 15.0);
|
|
|
|
|
boule.garantirDistanceLigne(yLigneLocal, 15.0);
|
2026-03-28 08:16:44 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-28 17:19:34 +01:00
|
|
|
// vérifier collision entre la Ligne et le Cercle
|
2026-03-28 14:18:17 +01:00
|
|
|
if (ligneObjet != null && cercleReference != null) {
|
|
|
|
|
double[] info = ligneObjet.contactInfo(
|
|
|
|
|
cercleReference.getX(), cercleReference.getY(), cercleReference.getRayon());
|
|
|
|
|
|
|
|
|
|
boolean enContact = (info != null) && (info[1] <= cercleReference.getRayon());
|
|
|
|
|
double ligneY = (info != null) ? info[0] : ligneObjet.getYAuX(cercleReference.getX());
|
|
|
|
|
|
2026-03-28 17:19:34 +01:00
|
|
|
// force d'attraction depuis le début
|
|
|
|
|
if (!AEteSurLigne && immortel) {
|
2026-03-28 14:18:17 +01:00
|
|
|
double delta = ligneY - cercleReference.y;
|
|
|
|
|
cercleReference.vitesse += delta * 0.12;
|
|
|
|
|
|
|
|
|
|
// Marquer le premier contact
|
|
|
|
|
if (enContact) {
|
2026-03-28 17:19:34 +01:00
|
|
|
AEteSurLigne = true;
|
2026-03-28 14:18:17 +01:00
|
|
|
}
|
2026-03-28 17:19:34 +01:00
|
|
|
} else if (AEteSurLigne && immortel) {
|
|
|
|
|
// après le premier contact, maintenir le cercle sur la ligne
|
2026-03-28 14:18:17 +01:00
|
|
|
double rayon = cercleReference.getRayon();
|
|
|
|
|
double limite = ligneY - rayon;
|
|
|
|
|
double limiteBas = ligneY + rayon;
|
|
|
|
|
|
2026-03-28 17:19:34 +01:00
|
|
|
// empêcher le cercle de sortir au-dessus
|
2026-03-28 14:18:17 +01:00
|
|
|
if (cercleReference.y < limite) {
|
|
|
|
|
cercleReference.y = limite;
|
|
|
|
|
if (cercleReference.vitesse < 0) cercleReference.vitesse *= -0.3;
|
|
|
|
|
}
|
2026-03-28 17:19:34 +01:00
|
|
|
// empêcher le cercle de sortir en-dessous
|
2026-03-28 14:18:17 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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;
|
2026-02-23 09:41:54 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-03-28 08:16:44 +01:00
|
|
|
|
2026-03-28 17:19:34 +01:00
|
|
|
// vérifier collisions entre les boules bonus et le cercle
|
2026-03-28 08:16:44 +01:00
|
|
|
for (int i = boolesBonus.size() - 1; i >= 0; i--)
|
|
|
|
|
{
|
|
|
|
|
BouleBonus boule = boolesBonus.get(i);
|
|
|
|
|
boolean collision = false;
|
2026-02-23 09:41:54 +01:00
|
|
|
|
2026-03-28 08:16:44 +01:00
|
|
|
for (ObjetGraphique obj : listeObjets) {
|
|
|
|
|
if (obj instanceof Cercle) {
|
|
|
|
|
Cercle c = (Cercle) obj;
|
|
|
|
|
if (boule.collisionAvec(c)) {
|
2026-03-28 17:19:34 +01:00
|
|
|
// Si touché définit le bonus et on détruit la boule
|
2026-03-28 08:16:44 +01:00
|
|
|
bonusRecupere = boule.isVerte() ? 1 : -1;
|
|
|
|
|
boolesBonus.remove(i);
|
|
|
|
|
collision = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-28 17:19:34 +01:00
|
|
|
//Détruire la boule si elle dépasse le joueur sans être touchée
|
|
|
|
|
|
2026-03-28 14:18:17 +01:00
|
|
|
if (!collision && boule.getX() < 320) {
|
2026-03-28 08:16:44 +01:00
|
|
|
boolesBonus.remove(i);
|
2026-03-28 17:19:34 +01:00
|
|
|
|
2026-03-28 08:16:44 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-23 09:41:54 +01:00
|
|
|
repaint();
|
2026-02-10 16:39:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void paintComponent(Graphics g) {
|
|
|
|
|
super.paintComponent(g);
|
|
|
|
|
|
|
|
|
|
Graphics2D g2D = (Graphics2D) g;
|
|
|
|
|
g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
|
|
|
|
|
|
|
|
|
|
// Afficher tous les objets
|
|
|
|
|
for (ObjetGraphique obj : listeObjets) {
|
|
|
|
|
obj.Afficher(g);
|
|
|
|
|
}
|
2026-03-28 08:16:44 +01:00
|
|
|
|
|
|
|
|
// Afficher les boules bonus
|
|
|
|
|
for (BouleBonus boule : boolesBonus) {
|
|
|
|
|
boule.Afficher(g);
|
|
|
|
|
}
|
2026-02-10 16:39:21 +01:00
|
|
|
}
|
2026-02-23 09:41:54 +01:00
|
|
|
|
|
|
|
|
// Indique si une collision est survenue
|
|
|
|
|
public boolean aCollision() {
|
|
|
|
|
return collisionOccur;
|
|
|
|
|
}
|
2026-02-23 09:57:06 +01:00
|
|
|
|
|
|
|
|
// Réinitialise l'état de la zone de dessin et supprime les objets graphiques
|
|
|
|
|
public void reinitialiser() {
|
|
|
|
|
listeObjets.clear();
|
2026-03-28 08:16:44 +01:00
|
|
|
boolesBonus.clear();
|
2026-02-23 09:57:06 +01:00
|
|
|
estArrete = false;
|
|
|
|
|
collisionOccur = false;
|
2026-03-28 17:19:34 +01:00
|
|
|
AEteSurLigne = false;
|
2026-03-28 08:16:44 +01:00
|
|
|
bonusRecupere = 0;
|
2026-03-28 14:18:17 +01:00
|
|
|
compteurBoule = -delaiInitialBoule;
|
|
|
|
|
dernierJoueurY = null;
|
2026-02-23 09:57:06 +01:00
|
|
|
repaint();
|
|
|
|
|
}
|
2026-02-10 16:39:21 +01:00
|
|
|
}
|