package linea; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.util.ArrayList; public class Ligne extends ObjetGraphique{ private int nbSegments = 4000; private double xCercle = 400; private Segment SegCourant; // vitesse de déplacement (augmente légèrement chaque frame) private double vitesse = 4.8; // croissance initiale (fractionnelle) appliquée chaque frame 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.00002; // accélération plus douce private int niveau = 1; // niveau de difficulté, à augmenter pour rendre le jeu plus difficile // liste des segments private ArrayList segments = new ArrayList(); // écran fixe actuellement 800x600 (voir ZoneDessin) private static final int SCREEN_WIDTH = 800; private static final int SCREEN_HEIGHT = 600; private static final int VERTICAL_MARGIN = 20; // éviter de toucher les bords public Ligne(int _niveaux){ niveau = _niveaux; double x = SCREEN_WIDTH; // commence au bord droit double y = SCREEN_HEIGHT/2.0; // milieu vertical double dx,dy; nbSegments += niveau * 50; // augmenter le nombre de segments avec les niveaux Segment s; for (int i=0; i SCREEN_HEIGHT - VERTICAL_MARGIN - 45) { rawDy += Math.signum(ecartCentre) * 14.0; } // limiter la variation brute if (rawDy > maxStep) rawDy = maxStep; if (rawDy < -maxStep) rawDy = -maxStep; double tentativeY = y + rawDy; // si on dépasserait les marges, repositionner vers l'intérieur if (tentativeY < VERTICAL_MARGIN) { tentativeY = VERTICAL_MARGIN + Math.random()*10; } else if (tentativeY > SCREEN_HEIGHT - VERTICAL_MARGIN) { tentativeY = SCREEN_HEIGHT - VERTICAL_MARGIN - Math.random()*10; } dy = tentativeY - y; // éviter pente nulle (ligne plate) en forçant un petit mouvement if (Math.abs(dy) < 1.0) { dy = (rawDy < 0 ? -1.0 : 1.0); tentativeY = y + dy; } s = new Segment(x,y,dx,dy); s.setCouleur(new Color(0.2f,0.2f,0.2f)); segments.add(s); x += dx; y = tentativeY; } } @Override public void Afficher(Graphics g){ Graphics2D g2D = (Graphics2D) g; g2D.setStroke(new BasicStroke(3.0f)); for (Segment seg : segments) { seg.Afficher(g); } } @Override public void Animer() { // déplace tous les segments vers la gauche double delta = vitesse; // vitesse de déplacement (exponentielle) for (Segment seg : segments) { seg.x -= delta; } // appliquer la croissance (vitesse *= 1 + croissance) 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; } // 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 seg; } } 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[] info = contactInfo(c.getX(), c.getY(), c.getRayon()); return info != null && info[1] <= c.getRayon(); } // 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) public double getVitesse() { 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; double vy = y2 - y1; double wx = px - x1; double wy = py - y1; double c = vx*vx + vy*vy; if (c == 0) { return Math.hypot(px - x1, py - y1); } double t = (vx*wx + vy*wy) / c; if (t < 0) t = 0; else if (t > 1) t = 1; double projx = x1 + t * vx; double projy = y1 + t * vy; return Math.hypot(px - projx, py - projy); } }