Compare commits

..

39 Commits

Author SHA1 Message Date
4ed39dd92a commentaires 2026-03-28 16:37:07 +01:00
B00M360
5660a6c5c6 Merge branch 'main' of https://titi.koxi.nl/blodat/projet-dev 2026-03-28 14:38:28 +01:00
B00M360
607ee1fff4 carré 2026-03-28 14:37:13 +01:00
MOISOIU Stefan-Mihai
f295a34ca5 commentaires ajoutés 2026-03-28 14:22:38 +01:00
tit-exe
6de8ca830e ajout de temps de jeu dans l'historique + commentaires 2026-03-28 07:43:33 +01:00
MOISOIU Stefan-Mihai
a01e27ad2c accents suppr 2026-03-27 19:23:52 +01:00
16787a4113 change: bonus regroupé en une seule classe mere
classe objetcolldectile qui regroupe tout
2026-03-27 19:17:03 +01:00
tit-exe
d69b806001 ajout de l'historique de jeu 2026-03-27 11:16:32 +01:00
2c93a102f2 Ajout : cheat mode + fix: invincibilité malus
ajout du cheat mode, plus fix d'un problème: avant possibilité de perdre une vie si malus récupéré pendant la période que le cercle est invincible ( clignote ) alors que ca ne devrait pas l"etre
2026-03-27 10:40:40 +01:00
MOISOIU Stefan-Mihai
ba78c22e91 mode 2 joueurs 2026-03-26 20:08:52 +01:00
e1e0ef5054 Ajout bonus de Taille
augmente la taille du cercle temporairement quand ramassé
2026-03-25 21:28:33 +01:00
eb74186d05 Clignotement lors de la perte de vie
Clignotement blanc : Début de partie et changement de niveau

Clignotement rouge : Collision avec la ligne et obtention de malus
2026-03-17 16:25:30 +01:00
tit-exe
732d29dad6 ajout invicibilité entre les niveaux 2026-03-17 15:01:49 +01:00
tit-exe
0b82113441 + jusqu'au niveau 10 2026-03-17 14:51:07 +01:00
0a4825d9ef Ajout de malus, ( mm logique que bonus )
perd 1 vie par malus, il faut l'éviter
2026-03-17 14:40:12 +01:00
tit-exe
eab0280f5e push 2026-03-17 14:37:00 +01:00
tit-exe
f8c74c4306 changement difficulté niveaux 2026-03-17 14:31:00 +01:00
tit-exe
b37f6cb881 Merge branch 'main' of https://titi.koxi.nl/blodat/projet-dev 2026-03-17 14:12:10 +01:00
tit-exe
9ec6f0ebfa ajout de toutes les données dans la bdd + Modularisation de l'écran fin de partie 2026-03-17 14:11:55 +01:00
b4ff63e92c Modif bonus vitesse pour qu'il suive la taille
bonus a mm vitesse que ligne, baisser le randomness de la position du bonus
2026-03-17 14:11:37 +01:00
MOISOIU Stefan-Mihai
dbafa23b4d Merge branch 'main' of https://titi.koxi.nl/blodat/projet-dev 2026-03-16 16:47:33 +01:00
MOISOIU Stefan-Mihai
7639df7abd fix niveaux 2026-03-16 16:47:27 +01:00
B00M360
8126007805 Merge branch 'main' of https://titi.koxi.nl/blodat/projet-dev 2026-03-16 16:38:51 +01:00
tit-exe
3dd0408323 score titouane 2026-03-16 16:36:27 +01:00
2017bd1907 Modifications bonus,
pas trop de bonus, couleur jaune a la récolte
2026-03-16 16:31:57 +01:00
MOISOIU Stefan-Mihai
4e5ab18694 fix niveaux 2026-03-16 16:25:35 +01:00
B00M360
2b52a88132 Merge branch 'main' of https://titi.koxi.nl/blodat/projet-dev 2026-03-16 16:19:59 +01:00
B00M360
5d1c525890 Update linea_scores.db 2026-03-16 16:18:47 +01:00
MOISOIU Stefan-Mihai
c15787681f Merge branch 'main' of https://titi.koxi.nl/blodat/projet-dev 2026-03-16 16:17:38 +01:00
MOISOIU Stefan-Mihai
5a58534a40 fix niveaux 2026-03-16 16:17:30 +01:00
tit-exe
65a99a3e3e commint 2026-03-16 16:12:24 +01:00
MOISOIU Stefan-Mihai
834ea28872 Merge branch 'main' of https://titi.koxi.nl/blodat/projet-dev 2026-03-16 16:09:27 +01:00
MOISOIU Stefan-Mihai
64062f04f2 ajout des niveaux 2026-03-16 16:09:19 +01:00
76494174cd Ajout du début du bonus ( temps etc ) pas encore fait des bonus difficiles a obtenir 2026-03-16 15:43:35 +01:00
MOISOIU Stefan-Mihai
468a88196e fix ligne 2026-03-16 15:27:00 +01:00
B00M360
99a1dfe5ee Merge branch 'main' of https://titi.koxi.nl/blodat/projet-dev 2026-03-14 15:01:11 +01:00
B00M360
e5aca580f9 BDD qui fonctone (PTN DE FICHIER . JAVA QUI EST TROP RESSAN 2026-03-14 15:01:06 +01:00
MOISOIU Stefan-Mihai
8c90b46b1a Merge branch 'main' of https://titi.koxi.nl/blodat/projet-dev 2026-03-04 15:00:31 +01:00
MOISOIU Stefan-Mihai
74b214e89c generation infinie de ligne 2026-03-04 15:00:29 +01:00
25 changed files with 1060 additions and 147 deletions

2
.gitignore vendored
View File

@@ -24,7 +24,7 @@ bin/
# ========================
# 3. ANTIGRAVITY / VSCODE
# ========================
.vscode/
.claude/
.antigravity/
*.code-workspace

9
.idea/libraries/slf4j_api_1_7_36.xml generated Normal file
View File

@@ -0,0 +1,9 @@
<component name="libraryTable">
<library name="slf4j-api-1.7.36">
<CLASSES>
<root url="jar://$PROJECT_DIR$/lib/slf4j-api-1.7.36.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

9
.idea/libraries/slf4j_simple_1_7_36.xml generated Normal file
View File

@@ -0,0 +1,9 @@
<component name="libraryTable">
<library name="slf4j-simple-1.7.36">
<CLASSES>
<root url="jar://$PROJECT_DIR$/lib/slf4j-simple-1.7.36.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

View File

@@ -1,7 +1,7 @@
<component name="libraryTable">
<library name="sqlite-jdbc-3.45.1.0">
<CLASSES>
<root url="jar://$USER_HOME$/Downloads/sqlite-jdbc-3.45.1.0.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/sqlite-jdbc-3.45.1.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />

BIN
lib/slf4j-api-1.7.36.jar Normal file

Binary file not shown.

BIN
lib/slf4j-simple-1.7.36.jar Normal file

Binary file not shown.

Binary file not shown.

BIN
linea_bdd.db Normal file

Binary file not shown.

View File

@@ -7,6 +7,8 @@
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="sqlite-jdbc-3.45.1.0" level="project" />
<orderEntry type="library" exported="" name="sqlite-jdbc-3.45.1.0" level="project" />
<orderEntry type="library" exported="" name="slf4j-api-1.7.36" level="project" />
<orderEntry type="library" exported="" name="slf4j-simple-1.7.36" level="project" />
</component>
</module>

37
src/Bonus.java Normal file
View File

@@ -0,0 +1,37 @@
package linea;
import java.awt.Color;
import java.awt.Graphics;
import java.util.List;
public class Bonus extends ObjetCollectible {
public Bonus(Ligne l, List<Joueur> joueurs, Jeu j) {
super(l, joueurs, j);
this.taille = 10;
this.couleur = Color.GREEN;
}
@Override protected int getSeuilActivation() { return 220; }
@Override protected Color getCouleurCapture() { return Color.BLUE; } // couleur après avoir été ramasssé
@Override
protected double calculerY(double hauteurLigne) {
if (Math.random() > 0.5) return hauteurLigne - 10 - (Math.random() * 50); // position du bonus
else return hauteurLigne + 10 + (Math.random() * 50);
}
@Override
protected void appliquerEffet(Joueur joueur) {
if (!monJeu.cheatMode) joueur.ajouterVie();
} // En cheat mode, le bonus ne sert à rien (on a déjà l'invincibilité)
@Override
protected void dessiner(Graphics g) {
g.fillRect((int)Math.round(x), (int)Math.round(y), (int)taille, (int)taille);
}
}

35
src/BonusTaille.java Normal file
View File

@@ -0,0 +1,35 @@
package linea;
import java.awt.Color;
import java.awt.Graphics;
import java.util.List;
public class BonusTaille extends ObjetCollectible {
public BonusTaille(Ligne l, List<Joueur> joueurs, Jeu j) {
super(l, joueurs, j);
this.taille = 12;
this.couleur = Color.CYAN;
this.compteurFrames = 200; // démarre déjà à 200 pour apparaître plus tôt
}
@Override protected int getSeuilActivation() { return 320; }
@Override protected Color getCouleurCapture() { return new Color(255, 255, 255, 100); }
@Override
protected double calculerY(double hauteurLigne) {
if (Math.random() > 0.5) return hauteurLigne - 8 - (Math.random() * 45); // position du bonus
else return hauteurLigne + 8 + (Math.random() * 45);
}
@Override
protected void appliquerEffet(Joueur joueur) {
joueur.activerBonusTaille();
}
@Override
protected void dessiner(Graphics g) {
g.fillOval((int)Math.round(x), (int)Math.round(y), (int)taille, (int)taille);
}
}

View File

@@ -5,7 +5,8 @@ import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Arc2D;
public class Cercle extends ObjetGraphique { // il s'agit plutôt d'arcs de cercle
// Gère l'affichage et le déplacement du demi-cercle
public class Cercle extends ObjetGraphique {
protected double rayon = 50;
protected double depY = 0;
@@ -15,20 +16,24 @@ public class Cercle extends ObjetGraphique { // il s'agit plutôt d'arcs de cerc
protected double fin = 360;
protected boolean montee = false;
protected double vitesse = -1.0;
protected boolean descente = false;
protected double vitesse = 0;
// pas = "delta t", permet de régler la jouabilité
protected double pas = 0.2;
protected double impulsion = 35;
protected double impulsion = 6;
protected double gravite = 1;
public static int xCercle = 400;
public Cercle() {
x = 400;
y = 200;
x = xCercle;
y = (double)ZoneDessin.hauteur / 2;
}
public Cercle(double debutArc, double finArc) {
x = 400;
y = 200;
x = xCercle;
y = (double)ZoneDessin.hauteur / 2;
debut = debutArc;
fin = finArc;
}
@@ -37,8 +42,10 @@ public class Cercle extends ObjetGraphique { // il s'agit plutôt d'arcs de cerc
return rayon;
}
// note que "haut" a été appuyée (évite d'être tributaire de la répétition
// clavier)
public void setRayon(double r) {
rayon = r;
}
public void Monter() {
montee = true;
}
@@ -47,6 +54,14 @@ public class Cercle extends ObjetGraphique { // il s'agit plutôt d'arcs de cerc
montee = false;
}
public void Descendre() {
descente = true;
}
public void ArreterDescendre() {
descente = false;
}
@Override
void Afficher(Graphics g) {
Graphics2D g2D = (Graphics2D) g;
@@ -57,36 +72,42 @@ public class Cercle extends ObjetGraphique { // il s'agit plutôt d'arcs de cerc
@Override
void Animer() {
// chute libre
vitesse = vitesse + 9.81 * pas;
// gravite
vitesse += gravite * pas;
// impulsion vers le haut
// acceleration vers le haut
if (montee == true) {
vitesse = vitesse - impulsion * pas;
vitesse -= impulsion * pas;
}
depY = 1 / 2 * 9.81 + vitesse * pas;
// acceleration vers le bas
if (descente == true) {
vitesse += impulsion * pas;
}
if (depY < -10) {
depY = -10;
// limiter la vitesse max
if (vitesse < -10) {
vitesse = -10;
}
if (depY > 10) {
depY = 10;
if (vitesse > 10) {
vitesse = 10;
}
y += depY;
y += vitesse;
}
// Recadre le cercle dans la ligne si il le dépasse
public void ResterDansLigne(Ligne li) {
double collisionHautPos = y + rayon;
double collisionBasPos = y - rayon;
double yLigne = li.GetHauteurPointCercle();
if (yLigne < collisionBasPos) {
if (yLigne < collisionBasPos) { // Dépassement par le bas
y = yLigne + rayon;
if (vitesse > 0)
vitesse = 0;
}
if (yLigne > collisionHautPos) {
if (yLigne > collisionHautPos) {// Dépassement par le haut
y = yLigne - rayon;
if (vitesse < 0)
vitesse = 0;

View File

@@ -0,0 +1,39 @@
package linea;
import javax.swing.JLabel;
public class GestionnaireFinDePartie {
private boolean estGameOver = false;
private JLabel labGameOver;
private GestionnaireScore gestionnaireBDD;
private GestionnaireHistorique gestionnaireHistorique;
public GestionnaireFinDePartie(JLabel labGameOver, GestionnaireScore gestionnaireBDD, GestionnaireHistorique gestionnaireHistorique) {
this.labGameOver = labGameOver;
this.gestionnaireBDD = gestionnaireBDD;
this.gestionnaireHistorique = gestionnaireHistorique;
}
public void declencherGameOver(ZoneDessin ecran, String pseudo, int score) {
estGameOver = true;
ecran.arreter(); // on fige tout, plus d'animation
labGameOver.setVisible(true);
// on enregistre dans le classement seulement si y'a un pseudo
if (pseudo != null && !pseudo.isEmpty()) {
gestionnaireBDD.sauvegarderScore(pseudo, score);
}
// score == durée en secondes (1 pt par seconde, voir Jeu.actionPerformed)
gestionnaireHistorique.sauvegarderPartie(pseudo, score, score);
}
public boolean estGameOver() {
return estGameOver;
}
public void reinitialiser() {
estGameOver = false;
labGameOver.setVisible(false);
}
}

View File

@@ -0,0 +1,72 @@
package linea;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.table.DefaultTableModel;
public class GestionnaireHistorique {
private static final String URL = "jdbc:sqlite:linea_bdd.db";
public GestionnaireHistorique() {
try {
Class.forName("org.sqlite.JDBC");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
// enregistre la partie peu importe si le joueur a mis un pseudo ou pas
public void sauvegarderPartie(String nom, int points, int duree) {
String pseudoFinal = (nom == null || nom.trim().isEmpty()) ? "Anonyme" : nom.trim();
String dateActuelle = new SimpleDateFormat("dd/MM/yyyy HH:mm").format(new Date());
String sql = "INSERT INTO historique(nom, points, date_partie, duree) VALUES(?, ?, ?, ?)";
try (Connection conn = DriverManager.getConnection(URL);
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, pseudoFinal);
pstmt.setInt(2, points);
pstmt.setString(3, dateActuelle);
pstmt.setInt(4, duree);
pstmt.executeUpdate();
} catch (SQLException e) {
System.err.println("impossible de sauvegarder l historique");
}
}
public DefaultTableModel getModeleTableau() {
// colonnes affichées dans la popup historique du menu
String[] nomsColonnes = { "Partie N°", "Date", "Pseudo", "Score", "Durée (s)" };
DefaultTableModel modele = new DefaultTableModel(nomsColonnes, 0);
// les plus récentes en haut
String sql = "SELECT id, date_partie, nom, points, duree FROM historique ORDER BY id DESC";
try (Connection conn = DriverManager.getConnection(URL);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
while (rs.next()) {
String dateRecup = rs.getString("date_partie");
if (dateRecup == null)
dateRecup = "Inconnue";
Object[] ligne = {
rs.getInt("id"),
dateRecup,
rs.getString("nom"),
rs.getInt("points"),
rs.getInt("duree")
};
modele.addRow(ligne);
}
} catch (SQLException e) {
System.err.println("erreur lecture historique");
}
return modele;
}
}

157
src/GestionnaireNiveau.java Normal file
View File

@@ -0,0 +1,157 @@
package linea;
import java.awt.Color;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class GestionnaireNiveau {
public static final int FRAMES_PAR_NIVEAU = 25 * 10; // 10 secondes
private final List<Niveau> niveaux = new ArrayList<>();
private int indexNiveau = 0;
private int framesDepuisDebut = 0;
private int framesDansNiveau = 0;
private static final int DUREE_FADE = 25 * 3; // 3 secondes
private static final String URL_BDD = "jdbc:sqlite:linea_bdd.db";
public GestionnaireNiveau() {
try {
//chargement driver
Class.forName("org.sqlite.JDBC");
} catch (ClassNotFoundException e) {
System.err.println("[BDD] Impossible de charger le driver SQLite.");
e.printStackTrace();
}
chargerNiveaux();
}
private void chargerNiveaux() {
String sql = "SELECT * FROM niveaux ORDER BY numero ASC";
try (Connection conn = DriverManager.getConnection(URL_BDD);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
while (rs.next()) {
int numero = rs.getInt("numero");
int r = rs.getInt("couleur_r");
int g = rs.getInt("couleur_g");
int b = rs.getInt("couleur_b");
double vitesse = rs.getDouble("vitesse_scroll");
double freq = rs.getDouble("noise_frequence");
double rayon = rs.getDouble("rayon_cercle");
double haut = rs.getDouble("limite_haut");
double bas = rs.getDouble("limite_bas");
niveaux.add(new Niveau(numero, new Color(r, g, b), vitesse, freq, rayon, haut, bas));
}
} catch (SQLException e) {
System.err.println("[BDD] Erreur lors du chargement des niveaux.");
e.printStackTrace();
}
if (niveaux.isEmpty()) {
niveaux.add(new Niveau(1, new Color(112, 158, 251), 8, 1.0/80.0, 70, 100, 500));
}
}
private boolean niveauVientDeChanger = false;
public void mettreAJour() {
framesDepuisDebut++;
framesDansNiveau++;
if (framesDansNiveau >= FRAMES_PAR_NIVEAU && indexNiveau < niveaux.size() - 1) {
indexNiveau++;
framesDansNiveau = 0;
niveauVientDeChanger = true;
}
}
public boolean aChangeDeNiveau() {
if (niveauVientDeChanger) {
niveauVientDeChanger = false;
return true;
}
return false;
}
//transition smooth entre les niveau
public Niveau getNiveauActuel() {
return niveaux.get(indexNiveau);
}
public int getNumeroNiveau() {
return niveaux.get(indexNiveau).numero;
}
public Color getCouleurFondInterpolee() {
if (framesDansNiveau < DUREE_FADE && indexNiveau > 0) {
Color de = niveaux.get(indexNiveau - 1).couleurFond;
Color vers = niveaux.get(indexNiveau).couleurFond;
double t = (double) framesDansNiveau / DUREE_FADE;
return interpolerCouleur(de, vers, t);
}
return niveaux.get(indexNiveau).couleurFond;
}
public double getVitesseScroll() {
if (framesDansNiveau < DUREE_FADE && indexNiveau > 0) {
double de = niveaux.get(indexNiveau - 1).vitesseScroll;
double vers = niveaux.get(indexNiveau).vitesseScroll;
double t = (double) framesDansNiveau / DUREE_FADE;
return de + (vers - de) * t;
}
return niveaux.get(indexNiveau).vitesseScroll;
}
public double getNoiseFrequence() {
if (framesDansNiveau < DUREE_FADE && indexNiveau > 0) {
double de = niveaux.get(indexNiveau - 1).noiseFrequence;
double vers = niveaux.get(indexNiveau).noiseFrequence;
double t = (double) framesDansNiveau / DUREE_FADE;
return de + (vers - de) * t;
}
return niveaux.get(indexNiveau).noiseFrequence;
}
public double getRayonCercle() {
if (framesDansNiveau < DUREE_FADE && indexNiveau > 0) {
double de = niveaux.get(indexNiveau - 1).rayonCercle;
double vers = niveaux.get(indexNiveau).rayonCercle;
double t = (double) framesDansNiveau / DUREE_FADE;
return de + (vers - de) * t;
}
return niveaux.get(indexNiveau).rayonCercle;
}
public double getLimiteHaut() {
return niveaux.get(indexNiveau).limiteHaut;
}
public double getLimiteBas() {
return niveaux.get(indexNiveau).limiteBas;
}
public void reinitialiser() {
indexNiveau = 0;
framesDepuisDebut = 0;
framesDansNiveau = 0;
}
private static Color interpolerCouleur(Color de, Color vers, double t) {
int r = (int) (de.getRed() + (vers.getRed() - de.getRed()) * t);
int g = (int) (de.getGreen() + (vers.getGreen() - de.getGreen()) * t);
int b = (int) (de.getBlue() + (vers.getBlue() - de.getBlue()) * t);
return new Color(
Math.max(0, Math.min(255, r)),
Math.max(0, Math.min(255, g)),
Math.max(0, Math.min(255, b))
);
}
}

View File

@@ -3,30 +3,36 @@ package linea;
import java.sql.*;
public class GestionnaireScore {
private String url = "jdbc:sqlite:linea_scores.db";
private static final String URL = "jdbc:sqlite:linea_bdd.db";
public GestionnaireScore() {
// Au démarrage, on crée la table si elle n'existe pas
try (Connection conn = DriverManager.getConnection(url)) {
String sql = "CREATE TABLE IF NOT EXISTS scores (" +
"id INTEGER PRIMARY KEY AUTOINCREMENT," +
"nom TEXT," +
"points INTEGER);";
Statement stmt = conn.createStatement();
stmt.execute(sql);
} catch (SQLException e) {
try {
//chargement driver SQLite
Class.forName("org.sqlite.JDBC");
} catch (ClassNotFoundException e) {
System.err.println("[BDD] Impossible de charger le driver SQLite.");
e.printStackTrace();
}
}
public void sauvegarderScore(String nom, int points) {
if (nom == null || nom.trim().isEmpty()) {
return;
}
String sql = "INSERT INTO scores(nom, points) VALUES(?, ?)";
try (Connection conn = DriverManager.getConnection(url);
try (Connection conn = DriverManager.getConnection(URL);
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, nom);
//contre injection SQL
pstmt.setString(1, nom.trim());
pstmt.setInt(2, points);
pstmt.executeUpdate();
} catch (SQLException e) {
System.err.println("[BDD] Erreur lors de l'enregistrement du score.");
e.printStackTrace();
}
}
@@ -35,17 +41,30 @@ public class GestionnaireScore {
StringBuilder sb = new StringBuilder("--- TOP 10 SCORES ---\n");
String sql = "SELECT nom, points FROM scores ORDER BY points DESC LIMIT 10";
try (Connection conn = DriverManager.getConnection(url);
try (Connection conn = DriverManager.getConnection(URL);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
boolean auMoinsUn = false;
while (rs.next()) {
sb.append(rs.getString("nom")).append(" : ")
.append(rs.getInt("points")).append("\n");
auMoinsUn = true;
sb.append(rs.getString("nom"))
.append(" : ")
.append(rs.getInt("points"))
.append("\n");
}
if (!auMoinsUn) {
sb.append("(Aucun score enregistré pour le moment)\n");
}
} catch (SQLException e) {
System.err.println("[BDD] Erreur lors de la lecture des scores.");
e.printStackTrace();
return "Erreur lors de la lecture des scores.";
}
return sb.toString();
}
}

View File

@@ -8,6 +8,8 @@ import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
@@ -18,36 +20,39 @@ public class Jeu implements KeyListener, ActionListener, MouseListener {
protected ZoneDessin ecran = new ZoneDessin();
protected Cercle demiCercleAvant = new Cercle(90, -180); // celui qui est sur la ligne
protected Cercle demiCercleArriere = new Cercle(90, 180); // celui qui est derrière la ligne
protected GestionnaireNiveau gestionnaireNiveau = new GestionnaireNiveau();
protected Ligne lili = new Ligne(new NoiseGenerator(0), gestionnaireNiveau);
// A FAIRE : ajouter les objets graphiques manquants, s'il y en a
protected Ligne lili = new Ligne(new NoiseGenerator(0));
protected List<Joueur> joueurs = new ArrayList<>();
protected boolean deuxJoueurs = false;
protected Timer horloge;
protected double score = 1;
protected JLabel labScore;
protected int vies = 3;
protected GestionnaireScore gestionnaireBDD = new GestionnaireScore();
// pour gestionnaire historique
protected GestionnaireHistorique gestionnaireHistorique = new GestionnaireHistorique();
protected GestionnaireFinDePartie gestionnaireFinDePartie;
protected int compteurFrames = 0;
protected boolean enCollision = false;
protected boolean estGameOver = false;
protected JLabel labGameOver;
protected int compteurInvincible = 0;
protected String pseudo = "";
protected JFrame fenetre;
protected MenuPrincipal menu;
public boolean cheatMode = false;
public Jeu() {
labScore = new JLabel();
labScore.setForeground(Color.WHITE);
labScore.setText("<html><h3>" + (int) score + "</h3></html>");
labScore.setBounds(20, 0, 200, 50);
labScore.setBounds(20, 0, 600, 50);
ecran.add(labScore);
labGameOver = new JLabel("GAME OVER", SwingConstants.CENTER);
@@ -57,27 +62,37 @@ public class Jeu implements KeyListener, ActionListener, MouseListener {
labGameOver.setVisible(false);
ecran.add(labGameOver);
gestionnaireFinDePartie = new GestionnaireFinDePartie(labGameOver, gestionnaireBDD, gestionnaireHistorique);
ecran.addMouseListener(this);
ecran.traiterBoucleAnimation();
}
private Joueur creerJoueur1() {
return new Joueur(
new Color(0.0f, 0.5f, 0.0f), new Color(0.8f, 0.0f, 0.0f),
KeyEvent.VK_UP, KeyEvent.VK_DOWN
);
}
private Joueur creerJoueur2() {
return new Joueur(
new Color(0.0f, 0.3f, 0.8f), new Color(0.6f, 0.0f, 0.6f),
KeyEvent.VK_Z, KeyEvent.VK_S
);
}
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == 38) { // flèche haut
demiCercleAvant.Monter();
demiCercleArriere.Monter();
for (Joueur joueur : joueurs) {
joueur.appliquerTouche(e.getKeyCode(), true);
}
}
@Override
public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == 38) {
demiCercleAvant.ArreterMonter();
demiCercleArriere.ArreterMonter();
for (Joueur joueur : joueurs) {
joueur.appliquerTouche(e.getKeyCode(), false);
}
}
@@ -98,15 +113,29 @@ public class Jeu implements KeyListener, ActionListener, MouseListener {
fenetre.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void lancerPartie(String pseudoSaisi) {
public void lancerPartie(String pseudoSaisi, boolean modeDeuxJoueurs) {
pseudo = pseudoSaisi;
deuxJoueurs = modeDeuxJoueurs;
joueurs.clear();
joueurs.add(creerJoueur1());
if (deuxJoueurs) {
joueurs.add(creerJoueur2());
}
for (Joueur joueur : joueurs) {
ecran.ajouterObjet(joueur.demiCercleArriere);
}
// A FAIRE : placer dans l'écran tous les objets graphiques nécessaires
ecran.ajouterObjet(demiCercleArriere);
ecran.ajouterObjet(lili);
ecran.ajouterObjet(demiCercleAvant);
demiCercleArriere.setCouleur(new Color(0.0f, 0.4f, 0.0f));
demiCercleAvant.setCouleur(new Color(0.0f, 0.5f, 0.0f));
for (Joueur joueur : joueurs) {
ecran.ajouterObjet(joueur.demiCercleAvant);
}
ecran.ajouterObjet(new Bonus(lili, joueurs, this));
ecran.ajouterObjet(new Malus(lili, joueurs, this));
ecran.ajouterObjet(new BonusTaille(lili, joueurs, this));
ecran.addKeyListener(this);
ecran.setFocusable(true);
@@ -118,66 +147,81 @@ public class Jeu implements KeyListener, ActionListener, MouseListener {
score = 1;
compteurFrames = 0;
vies = 3;
enCollision = false;
estGameOver = false;
compteurInvincible = 0;
labGameOver.setVisible(false);
gestionnaireNiveau.reinitialiser();
gestionnaireFinDePartie.reinitialiser();
double posY = deuxJoueurs ? 250 : 200;
for (int i = 0; i < joueurs.size(); i++) {
joueurs.get(i).reinitialiser(posY + i * 100);
}
ecran.demarrer();
if (horloge == null) {
// 40ms par frame, environ 25fps
horloge = new Timer(40, this);
}
horloge.start();
// A FAIRE : donner la couleur des 2 demi-cercles
// demiCercleArriere.setCouleur(new Color(0.8f, 0.0f, 0.0f));
demiCercleArriere.setCouleur(new Color(0.8f, 0.0f, 0.0f));
}
@Override
public void actionPerformed(ActionEvent e) {
if (estGameOver == true) {
return;
if (estGameOver) return;
gestionnaireNiveau.mettreAJour();
if (gestionnaireNiveau.aChangeDeNiveau()) {
for (Joueur joueur : joueurs) {
joueur.resetInvincibilite();
}
}
ecran.setCouleurFond(gestionnaireNiveau.getCouleurFondInterpolee());
double rayonBase = gestionnaireNiveau.getRayonCercle();
for (Joueur joueur : joueurs) {
joueur.mettreAJourRayon(rayonBase);
joueur.mettreAJourInvincibilite();
if (!cheatMode) joueur.verifierCollisionLigne(lili); // si cheat mode activé : plus de perte de vie
joueur.resterDansLigne(lili);
}
ecran.traiterBoucleAnimation();
compteurFrames = compteurFrames + 1;
compteurFrames++;
// 25 frames à 40ms = 1 seconde, donc score ≈ durée en secondes
if (compteurFrames >= 25) {
score = score + 1;
score++;
compteurFrames = 0;
}
if (compteurInvincible < 75) {
compteurInvincible = compteurInvincible + 1;
} else {
if (demiCercleArriere.VerifierCollision(lili)) {
if (enCollision == false) {
vies = vies - 1; // La nouvelle logique : on perd 1 vie
enCollision = true;
compteurInvincible = 0;
}
} else {
enCollision = false;
boolean tousMotrs = true;
for (Joueur joueur : joueurs) {
if (!joueur.estMort) {
tousMotrs = false;
break;
}
}
if (vies <= 0) {
vies = 0;
if (tousMotrs) {
// tous les joueurs sont morts, on déclenche le game over
estGameOver = true;
ecran.arreter();
labGameOver.setVisible(true);
if (pseudo != null && !pseudo.isEmpty()) {
gestionnaireBDD.sauvegarderScore(pseudo, (int) score);
}
gestionnaireFinDePartie.declencherGameOver(ecran, pseudo, (int) score);
}
labScore.setText("<html><h3>Score : " + (int) score + " | Vies : " + vies + "</h3></html>");
mettreAJourLabel();
}
demiCercleArriere.ResterDansLigne(lili);
demiCercleAvant.ResterDansLigne(lili);
private void mettreAJourLabel() {
StringBuilder sb = new StringBuilder("<html><h3>Score : " + (int) score + " | ");
if (deuxJoueurs) {
sb.append("J1 : ").append(joueurs.get(0).vies).append(" | ");
sb.append("J2 : ").append(joueurs.get(1).vies).append(" | ");
} else {
sb.append("Vies : ").append(joueurs.get(0).vies).append(" | ");
}
sb.append("Niv. ").append(gestionnaireNiveau.getNumeroNiveau()).append("</h3></html>");
labScore.setText(sb.toString());
}
private void retourMenu() {
@@ -185,12 +229,10 @@ public class Jeu implements KeyListener, ActionListener, MouseListener {
horloge.stop();
}
lili = new Ligne(new NoiseGenerator(0));
demiCercleAvant.y = 200;
demiCercleAvant.vitesse = -1.0;
demiCercleArriere.y = 200;
demiCercleArriere.vitesse = -1.0;
// on repart de zéro : nouvelle ligne, nouveaux joueurs
gestionnaireNiveau.reinitialiser();
lili = new Ligne(new NoiseGenerator(0), gestionnaireNiveau);
joueurs.clear();
ecran.viderObjets();
menu.afficher(pseudo);
@@ -202,7 +244,8 @@ public class Jeu implements KeyListener, ActionListener, MouseListener {
@Override
public void mousePressed(MouseEvent e) {
if (estGameOver == true) {
// un clic n'importe où à la fin de la partie pour revenir au menu
if (estGameOver) {
retourMenu();
}
}
@@ -218,7 +261,12 @@ public class Jeu implements KeyListener, ActionListener, MouseListener {
@Override
public void mouseExited(MouseEvent e) {
}
public GestionnaireScore getGestionnaireBDD() {
return gestionnaireBDD;
}
public GestionnaireHistorique getGestionnaireHistorique() {
return gestionnaireHistorique;
}
}

190
src/Joueur.java Normal file
View File

@@ -0,0 +1,190 @@
package linea;
import java.awt.Color;
// Gère le fonctionnement du joueur (vie, collision, déplacement)
public class Joueur {
protected Cercle demiCercleAvant;
protected Cercle demiCercleArriere;
protected int vies = 3;
protected boolean enCollision = false;
protected int compteurInvincible = 0;
protected boolean invincibiliteRouge = false;
protected boolean bonusTailleActif = false;
protected int compteurBonusTaille = 0;
protected boolean estMort = false;
protected Color couleurAvant;
protected Color couleurArriere;
protected int toucheHaut;
protected int toucheBas;
public Joueur(Color couleurAvant, Color couleurArriere, int toucheHaut, int toucheBas) {
this.demiCercleAvant = new Cercle(90, -180);
this.demiCercleArriere = new Cercle(90, 180);
this.couleurAvant = couleurAvant;
this.couleurArriere = couleurArriere;
this.toucheHaut = toucheHaut;
this.toucheBas = toucheBas;
appliquerCouleurs();
}
// Gère les contrôles du joueur
public void appliquerTouche(int keyCode, boolean pressed) {
if (estMort) return;
if (keyCode == toucheHaut) {
if (pressed) {
demiCercleAvant.Monter();
demiCercleArriere.Monter();
} else {
demiCercleAvant.ArreterMonter();
demiCercleArriere.ArreterMonter();
}
}
if (keyCode == toucheBas) {
if (pressed) {
demiCercleAvant.Descendre();
demiCercleArriere.Descendre();
} else {
demiCercleAvant.ArreterDescendre();
demiCercleArriere.ArreterDescendre();
}
}
}
public void mettreAJourRayon(double rayonBase) {
double rayon = rayonBase;
if (bonusTailleActif) {
rayon += 30;
compteurBonusTaille--;
if (compteurBonusTaille <= 0) {
bonusTailleActif = false;
}
}
demiCercleAvant.setRayon(rayon);
demiCercleArriere.setRayon(rayon);
}
//Appelé chaque frame et permet d'avancer le timer d'invincibilité et de mettre à jour l'effet visuel
public void mettreAJourInvincibilite() {
if (estMort) {
demiCercleAvant.setCouleur(new Color(0, 0, 0, 0));
demiCercleArriere.setCouleur(new Color(0, 0, 0, 0));
return;
}
if (compteurInvincible < 75) {
compteurInvincible++;
if (compteurInvincible % 10 < 5) {
if (invincibiliteRouge) {
demiCercleArriere.setCouleur(new Color(1f, 0f, 0f));
demiCercleAvant.setCouleur(new Color(1f, 0f, 0f));
} else {
demiCercleArriere.setCouleur(new Color(255, 255, 255, 150));
demiCercleAvant.setCouleur(new Color(255, 255, 255, 150));
}
} else {
appliquerCouleurs();
}
} else {
appliquerCouleurs();
}
}
public boolean estInvincible() {
return compteurInvincible < 75;
}
public void verifierCollisionLigne(Ligne li) {
if (estMort || estInvincible()) return;
if (demiCercleArriere.VerifierCollision(li)) {
if (!enCollision) {
vies--;
enCollision = true;
compteurInvincible = 0;
invincibiliteRouge = true;
}
} else {
enCollision = false;
}
if (vies <= 0) {
vies = 0;
estMort = true;
}
}
public boolean verifierCollisionCollectible(double itemX, double itemY, double itemTaille, double vitesseLigne) {
if (estMort) return false;
double centreX = itemX + (itemTaille / 2.0);
if (centreX <= demiCercleAvant.x && centreX > demiCercleAvant.x - vitesseLigne) {
double hautCercle = demiCercleAvant.y - demiCercleAvant.getRayon();
double basCercle = demiCercleAvant.y + demiCercleAvant.getRayon();
return itemY > hautCercle && (itemY + itemTaille) < basCercle;
}
return false;
}
public void resterDansLigne(Ligne li) {
if (estMort) return;
demiCercleArriere.ResterDansLigne(li);
demiCercleAvant.ResterDansLigne(li);
}
public void activerBonusTaille() {
bonusTailleActif = true;
compteurBonusTaille = 150;
}
public void ajouterVie() {
vies++;
}
public void retirerVie() {
vies--;
invincibiliteRouge = true;
compteurInvincible = 0;
if (vies <= 0) {
vies = 0;
estMort = true;
}
}
public void resetInvincibilite() {
compteurInvincible = 0;
invincibiliteRouge = false;
}
public void appliquerCouleurs() {
demiCercleArriere.setCouleur(couleurArriere);
demiCercleAvant.setCouleur(couleurAvant);
}
public void ajouterDansEcran(ZoneDessin ecran) {
ecran.ajouterObjet(demiCercleArriere);
ecran.ajouterObjet(demiCercleAvant);
}
public void reinitialiser(double posY) {
vies = 3;
enCollision = false;
compteurInvincible = 0;
invincibiliteRouge = false;
bonusTailleActif = false;
compteurBonusTaille = 0;
estMort = false;
demiCercleAvant.y = posY;
demiCercleAvant.vitesse = -1.0;
demiCercleArriere.y = posY;
demiCercleArriere.vitesse = -1.0;
appliquerCouleurs();
}
}

View File

@@ -8,43 +8,85 @@ import java.util.ArrayList;
public class Ligne extends ObjetGraphique {
protected int nbSegments = 400;
protected double xCercle = 400;
protected int nbSegments = 50;
protected Segment SegCourant;
protected ArrayList<Segment> listeSegments = new ArrayList<Segment>();
protected double limiteHaut = 50;
protected double limiteBas = 550;
protected Segment dernierSegment;
private double decalageXDernierSegment = 0;
public Ligne(NoiseGenerator noiseGenerator) {
private NoiseGenerator noiseGenerator;
private GestionnaireNiveau gestionnaireNiveau;
private double xActuel;
// Curseur dans le noise : avance plus vite quand la frequence du niveau augmente
private double noiseCurseur = 0;
public Ligne(NoiseGenerator noiseGenerator, GestionnaireNiveau gestionnaireNiveau) {
double x = 0;
double y = 200;
double dx, dy;
Segment s;
this.noiseGenerator = noiseGenerator;
this.gestionnaireNiveau = gestionnaireNiveau;
double dx = GetLargeurSegment();
for (int i = 0; i < nbSegments; i++) {
dx = 10;
double noiseStep = getNoiseStep();
double yDebut = CalculerY(noiseCurseur);
double yFin = CalculerY(noiseCurseur + noiseStep);
dy = noiseGenerator.noise(x / 15) * 8;
if (y + dy > limiteBas) {
dy = limiteBas - y;
}
if (y + dy < limiteHaut) {
dy = limiteHaut - y;
}
s = new Segment(x, y, dx, dy);
Segment s = new Segment(x, yDebut, dx, yFin - yDebut);
s.setCouleur(new Color(0.2f, 0.2f, 0.2f));
listeSegments.add(s);
noiseCurseur += noiseStep;
if (i == nbSegments - 1) {
dernierSegment = s;
xActuel = x + dx;
}
x += dx;
y += dy;
}
}
protected double GetLargeurSegment(){
return (double)ZoneDessin.largeur / nbSegments;
}
private double getNoiseStep() {
return GetLargeurSegment() / gestionnaireNiveau.getNoiseFrequence();
}
// Quand un segment sort de l'écran, génère un nouveau segment à la fin de la ligne.
protected Segment CreerSegmentSuivant(){
double noiseStep = getNoiseStep();
double yDebut = CalculerY(noiseCurseur);
double yFin = CalculerY(noiseCurseur + noiseStep);
noiseCurseur += noiseStep;
Segment s = new Segment(0, yDebut, GetLargeurSegment(), yFin - yDebut);
s.setCouleur(new Color(0.2f, 0.2f, 0.2f));
return s;
}
// Calcule la hauteur de la ligne à un point X.
protected double CalculerY(double noisePos){
double limiteHaut = gestionnaireNiveau.getLimiteHaut();
double limiteBas = gestionnaireNiveau.getLimiteBas();
double hauteur = limiteBas - limiteHaut;
double bruit = noiseGenerator.noise(noisePos, 1);
double normalise = (bruit + 1) / 2;
return limiteBas - normalise * hauteur;
}
@Override
public void Afficher(Graphics g) {
Graphics2D g2D = (Graphics2D) g;
@@ -53,12 +95,12 @@ public class Ligne extends ObjetGraphique {
for (Segment s : listeSegments) {
s.Afficher(g);
if (SegCourant == null) {
if (xCercle <= s.x + s.xLong && xCercle >= s.x) {
if (Cercle.xCercle <= s.x + s.xLong && Cercle.xCercle >= s.x) {
SegCourant = s;
}
} else {
if ((SegCourant.x + SegCourant.xLong) < xCercle) {
if (s.x <= xCercle && (s.x + s.xLong) >= xCercle) {
if ((SegCourant.x + SegCourant.xLong) < Cercle.xCercle) {
if (s.x <= Cercle.xCercle && (s.x + s.xLong) >= Cercle.xCercle) {
SegCourant = s;
}
}
@@ -68,12 +110,36 @@ public class Ligne extends ObjetGraphique {
@Override
public void Animer() {
double vitesse = gestionnaireNiveau.getVitesseScroll();
for (Segment s : listeSegments) {
s.Animer();
s.x -= 10;
s.x -= vitesse;
}
UpdateSegments();
}
// Permet de réutiliser les segments sortis de l'écran au debut
private void UpdateSegments(){
if (dernierSegment == null) throw new RuntimeException("dernierSegment n'existe pas");
for (int i = 0; i < listeSegments.size(); i++) {
Segment s = listeSegments.get(i);
if (s.x + s.xLong < 0) { // le segment est ENTIEREMENT hors de l'écran
Segment nouveauSegment = CreerSegmentSuivant();
nouveauSegment.x = dernierSegment.x + dernierSegment.xLong;
listeSegments.set(i, nouveauSegment);
xActuel += GetLargeurSegment();
dernierSegment = nouveauSegment;
}
}
}
// Renvoie la hauteur à laquelle doit etre le cercle. Utilisé pour la collision
public double GetHauteurPointCercle(){
double t = (400 - SegCourant.x) / SegCourant.xLong;

36
src/Malus.java Normal file
View File

@@ -0,0 +1,36 @@
package linea;
import java.awt.Color;
import java.awt.Graphics;
import java.util.List;
public class Malus extends ObjetCollectible {
public Malus(Ligne l, List<Joueur> joueurs, Jeu j) {
super(l, joueurs, j);
this.taille = 10;
this.couleur = Color.RED;
}
@Override protected int getSeuilActivation() { return 250; }
@Override protected Color getCouleurCapture() { return Color.BLACK; }
@Override
protected double calculerY(double hauteurLigne) {
if (Math.random() > 0.5) return hauteurLigne - 75 - (Math.random() * 30); // position du malus
else return hauteurLigne + 75 + (Math.random() * 30);
}
@Override
protected void appliquerEffet(Joueur joueur) {
// On ne punit pas si le joueur est en cheat mode ou en période d'invincibilité (clignotement)
if (!monJeu.cheatMode && !joueur.estInvincible()) joueur.retirerVie();
}
@Override
protected void dessiner(Graphics g) {
g.fillRect((int)Math.round(x), (int)Math.round(y), (int)taille, (int)taille);
}
}

View File

@@ -1,5 +1,6 @@
package linea;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
@@ -10,10 +11,12 @@ import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.table.DefaultTableModel;
// Classe qui représente le menu principal du jeu (affiché au lancement).
public class MenuPrincipal {
private JFrame fenetre;
@@ -25,37 +28,64 @@ public class MenuPrincipal {
this.jeu = jeu;
}
// Construit et affiche le panneau du menu dans la fenêtre
public void afficher(String pseudoActuel) {
JPanel panneau = new JPanel(new GridLayout(6, 1, 10, 10));
JPanel panneau = new JPanel(new GridLayout(9, 1, 10, 10));
JLabel titre = new JLabel("LINEA", SwingConstants.CENTER);
champPseudo = new JTextField(pseudoActuel, 15);
JButton boutonJouer = new JButton("Jouer");
JButton bouton1Joueur = new JButton("1 Joueur");
JButton bouton2Joueurs = new JButton("2 Joueurs");
JButton boutonClassement = new JButton("Classement");
JButton boutonHistorique = new JButton("Historique");
JButton boutonQuitter = new JButton("Quitter");
JButton boutonCheat = new JButton("Cheat Mode : OFF");
boutonJouer.addActionListener(new ActionListener() {
bouton1Joueur.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
jeu.lancerPartie(champPseudo.getText());
jeu.lancerPartie(champPseudo.getText(), false);
}
});
bouton2Joueurs.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
jeu.lancerPartie(champPseudo.getText(), true);
}
});
boutonClassement.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 1. On récupère les scores depuis la BDD via l'objet 'jeu'
String scores = jeu.getGestionnaireBDD().getTopScores();
// 2. On affiche le résultat dans la petite fenêtre popup
JOptionPane.showMessageDialog(fenetre, scores, "Meilleurs Scores", JOptionPane.INFORMATION_MESSAGE);
}
});
boutonHistorique.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// pour le modele de tableau
DefaultTableModel modele = jeu.getGestionnaireHistorique().getModeleTableau();
JTable tableau = new JTable(modele);
// pour ne pas pouvoir modifier le tableau
tableau.setDefaultEditor(Object.class, null);
// pour ne pas faire bouger les collones
tableau.getTableHeader().setReorderingAllowed(false);
// pour le scroll
JScrollPane scrollPane = new JScrollPane(tableau);
scrollPane.setPreferredSize(new Dimension(400, 300));
// afficher la fenetre pop up
JOptionPane.showMessageDialog(fenetre, scrollPane, "Historique des parties", JOptionPane.PLAIN_MESSAGE);
}
});
boutonQuitter.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@@ -63,14 +93,24 @@ public class MenuPrincipal {
}
});
boutonCheat.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
jeu.cheatMode = !jeu.cheatMode;
boutonCheat.setText(jeu.cheatMode ? "Cheat Mode : ON" : "Cheat Mode : OFF");
}
});
panneau.add(titre);
panneau.add(champPseudo);
panneau.add(boutonJouer);
panneau.add(bouton1Joueur);
panneau.add(bouton2Joueurs);
panneau.add(boutonClassement);
panneau.add(boutonHistorique);
panneau.add(boutonCheat);
panneau.add(boutonQuitter);
// panneau centré dans la fenêtre
JPanel conteneur = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 150));
JPanel conteneur = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 110));
conteneur.add(panneau);
fenetre.setContentPane(conteneur);

25
src/Niveau.java Normal file
View File

@@ -0,0 +1,25 @@
package linea;
import java.awt.Color;
public class Niveau {
public final int numero;
public final Color couleurFond;
public final double vitesseScroll;
public final double noiseFrequence;
public final double rayonCercle;
public final double limiteHaut;
public final double limiteBas;
public Niveau(int numero, Color couleurFond, double vitesseScroll,
double noiseFrequence, double rayonCercle, double limiteHaut, double limiteBas) {
this.numero = numero;
this.couleurFond = couleurFond;
this.vitesseScroll = vitesseScroll;
this.noiseFrequence = noiseFrequence;
this.rayonCercle = rayonCercle;
this.limiteHaut = limiteHaut;
this.limiteBas = limiteBas;
}
}

View File

@@ -109,11 +109,28 @@ public class NoiseGenerator {
return value / initialSize;
}
// Seule fonction publique utilisée, génère une valeur de -1 à 1 à un point x.
public double noise(double x, int octaves) {
double value = 0.0;
double size = default_size;
double weightSum = 0;
int count = 0;
while (size >= 1 && count < octaves) {
value += smoothNoise((x / size), 0.7, 0.3) * size;
weightSum += size;
size /= 2.0;
count++;
}
return value / weightSum;
}
public double smoothNoise(double x, double y, double z) {
// Offset each coordinate by the seed value
x += this.seed;
y += this.seed;
x += this.seed;
z += this.seed;
int X = (int) Math.floor(x) & 255; // FIND UNIT CUBE THAT
int Y = (int) Math.floor(y) & 255; // CONTAINS POINT.

81
src/ObjetCollectible.java Normal file
View File

@@ -0,0 +1,81 @@
package linea;
import java.awt.Color;
import java.awt.Graphics;
import java.util.List;
// Classe de base pour tous les objets qu'on peut ramasser (bonus, malus...)
// Elle gère toute la logique commune : apparition, déplacement, collision
public abstract class ObjetCollectible extends ObjetGraphique {
protected double taille;
protected boolean actif = false;
protected int compteurFrames = 0;
protected boolean dejaCapture = false;
protected Ligne maLigne;
protected List<Joueur> joueurs;
protected Jeu monJeu;
public ObjetCollectible(Ligne l, List<Joueur> joueurs, Jeu j) {
this.maLigne = l;
this.joueurs = joueurs;
this.monJeu = j;
}
// Chaque sous-classe décide quand elle apparaît, où, quel effet elle a et comment elle se dessine
protected abstract int getSeuilActivation();
protected abstract double calculerY(double hauteurLigne);
protected abstract void appliquerEffet(Joueur joueur);
protected abstract Color getCouleurCapture();
protected abstract void dessiner(Graphics g);
@Override
void Afficher(Graphics g) {
if (actif) {
g.setColor(dejaCapture ? getCouleurCapture() : this.couleur);
dessiner(g);
}
}
@Override
void Animer() {
if (!actif) compteurFrames++;
if (compteurFrames >= getSeuilActivation() && !actif) {
// Quand on a attendu assez longtemps, l'objet spawn à droite de l'écran
actif = true;
dejaCapture = false;
x = 800;
double hauteurLigne = 300;
if (maLigne.dernierSegment != null)
hauteurLigne = maLigne.dernierSegment.y;
y = calculerY(hauteurLigne);
if (y < 20) y = 20;
if (y > 550) y = 550;
compteurFrames = 0;
}
if (actif) {
double vitesseLigne = monJeu.gestionnaireNiveau.getVitesseScroll();
x -= vitesseLigne; // l'objet suit la vitesse du niveau
if (!dejaCapture) {
for (Joueur joueur : joueurs) {
if (joueur.verifierCollisionCollectible(x, y, taille, vitesseLigne)) {
appliquerEffet(joueur); // délégué à la sous-classe
dejaCapture = true; // évite d'appliquer l'effet plusieurs fois
break;
}
}
}
if (x + taille < 0) actif = false;
}
}
}

View File

@@ -18,10 +18,20 @@ public class ZoneDessin extends JPanel {
protected boolean estArrete = false;
public static int largeur = 800;
public static int hauteur = 600;
private Color couleurFond = new Color(0, 73, 220);
public ZoneDessin() {
setLayout(new BorderLayout());
setPreferredSize(new Dimension(800, 600));
setBackground(new Color(0, 73, 220));
setPreferredSize(new Dimension(largeur, hauteur));
setBackground(couleurFond);
}
public void setCouleurFond(Color c) {
couleurFond = c;
setBackground(c);
}
public void ajouterObjet(ObjetGraphique unObjet) {