import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.sql.Connection; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.Timer; public class Jeu implements KeyListener, ActionListener{ //------------------------------------------------------------------------- // PROPRIETES //------------------------------------------------------------------------- // Ecran : instance de ZoneDessin, qui contiendra tous les objets graphiques // On ne vapas créer directement l'écran car ça va créer un flash // Dès le lancement du jeu avec l'image de fond par défaut et l'imga du niveau // et les animera protected ZoneDessin ecran; // Le cercle : en fait 2 demis-cercles, un qui passera sous la ligne // un qui passera dessus 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 // A FAIRE : ajouter les objets graphiques manquants, s'il y en a protected Ligne laLigne = new Ligne(); // Ligne infinie du jeu // Timer : un objet qui émet des événements à un intervalle choisi, // il sert à donner le pas de l'animation protected Timer horloge; // Une variable qui contiendra le score protected double score=0; // un label qui servira à afficher le score protected JLabel labScore; protected JLabel labTriche; protected boolean jeuCommence = false; protected boolean modeTriche = false; // Propriété de ma connexion à ma base de données Connection conn = null; private int utilisateurId; // Variables actuelles du début de jeu protected int idNiveauActuel = 1; protected Niveau niveauEnCours; protected int segmentsTermines = 0; // Variable compteur de segments protected Segment dernierSegmentValide = null; //------------------------------------------------------------------------- // METHODES //------------------------------------------------------------------------- //------------------------------------------------------------------------- // Constructeur de la classe //------------------------------------------------------------------------- public Jeu(int utilisateurId){ JFrame fenetre = new JFrame(); this.utilisateurId = utilisateurId; Background premierFond = null; // On crée le jeu avec sa base de données try { conn = NiveauxDataConnect.getInstance().getConnection(); System.out.println("Connexion réussie !!!"); } catch (Exception ex) { ex.printStackTrace(); javax.swing.JOptionPane.showMessageDialog(fenetre,"Erreur de connexion à la base de données. Le jeu ne peut pas démarrer.", "Erreur Fatale", javax.swing.JOptionPane.ERROR_MESSAGE ); } // On récupère le niveau 1 Niveau n1 = NiveauxDataConnect.recupererNiveau(conn, 1); if( n1 != null ){ try { // On charge l'mage du niveau 1 java.net.URL url = Jeu.class.getResource("/" + n1.getImage()); if(url != null){ java.awt.Image img = javax.imageio.ImageIO.read(url); premierFond = new Background(img); } } catch (Exception e) { } } this.ecran = new ZoneDessin(premierFond); // Gestion du score : a réactiver en fin de TP, inutile au début ecran.setLayout(null); labScore = new JLabel(); labScore.setText("

score : 0

"); labScore.setBounds(20, 0, 200, 50); ecran.add(labScore); labTriche = new JLabel(); labTriche.setText("

Mode de triche activé

"); labTriche.setBounds(600, 0, 200, 50); // Placé en haut à droite (la fenêtre fait 800 de large) labTriche.setVisible(false); // Caché par défaut au lancement ecran.add(labTriche); } //------------------------------------------------------------------------- // Méthodes qu'il faut implémenter pour être // conforme à un KeyListener //------------------------------------------------------------------------- //------------------------------------------------------------------------- // Appui sur une touche // -> l'événement est émis lorsqu'on appuie, puis selon le rythme de // répétition du clavier //------------------------------------------------------------------------- @Override public void keyPressed(KeyEvent e){ // keyCode 38 : up // keyCode 40 : down int keyCode = e.getKeyCode(); if (keyCode==38){ // touche "flèche vers le haut" // On demande aux deux demi-cercle de "monter" demiCercleAvant.Monter(); demiCercleArriere.Monter(); } if(keyCode==32){//touche espace modeTriche =!modeTriche; labTriche.setVisible(modeTriche); //afficher ou cacher le label demiCercleAvant.setModeTriche(modeTriche); demiCercleArriere.setModeTriche(modeTriche); } } //------------------------------------------------------------------------- // Relâchement de la touche //------------------------------------------------------------------------- @Override public void keyReleased(KeyEvent e){ // keyCode 38 : up // keyCode 40 : down int keyCode = e.getKeyCode(); if (keyCode==38){ // On demande aux deux demi-cercle "d'arrêter de monter" demiCercleAvant.ArreterMonter(); demiCercleArriere.ArreterMonter(); } } //------------------------------------------------------------------------- // Une méthode que nous n'utilisons pas //------------------------------------------------------------------------- @Override public void keyTyped(KeyEvent e) { // TODO Auto-generated method stub } //------------------------------------------------------------------------- // Démarrage du jeu : // création de diverses instances et //------------------------------------------------------------------------- public void demarrer(){ // Création d'une fenêtre JFrame fenetre = new JFrame(); // A FAIRE : // placer dans l'instance de l'écran tous les objets graphiques nécessaires // par exemple : ecran.ajouterObjet(demiCerleArriere); this.ecran.ajouterObjet(demiCercleArriere); this.ecran.ajouterObjet(laLigne); this.ecran.ajouterObjet(demiCercleAvant); // on indique que c'est le jeu qui traitera les appuis sur une touche ecran.addKeyListener(this); ecran.setFocusable(true); fenetre.setContentPane(ecran); fenetre.pack(); fenetre.setLocation(100, 100); fenetre.setVisible(true); // s'assurer que l'écran reçoit le focus clavier ecran.requestFocusInWindow(); fenetre.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); javax.swing.JButton boutonscores = BoutonsManager.creerBoutonScores(fenetre, utilisateurId); this.ecran.add(boutonscores); // Création du timer horloge = new Timer(40, this); //propriétés dont on aura besoin pour utiliser NiveauxDataConnect //--------------------------------------------------------------------------------- // C'est ici qu'on appelle NiveauxDataConnect pour initialiser la connexion à la base de données des niveaux // On fera une synchronisation pour éviter que le jeu se fige // pendant l'initialisation de la base de données, qui peut prendre un peu de temps //-------------------------------------------------------------------------------- // démarrer le timer sur l'EDT même si l'initialisation BDD a échoué if (horloge != null && !horloge.isRunning()) { chargerNiveau(idNiveauActuel); horloge.start(); } // A FAIRE : // donner la couleur des 2 demi-cercles, par exemple : demiCerleArriere.setCouleur(new Color(0.8f,0.0f,0.0f)); //demiCercleArriere.setCouleur(new Color(26, 95, 161)); //demiCercleAvant.setCouleur(new Color(26, 95, 161)); } //------------------------------------------------------------------------------------------------ // Méthode permettant de charger le niveau et de l'appliquer //------------------------------------------------------------------------------------------------ public void chargerNiveau(int id){ System.out.println(conn); this.niveauEnCours = NiveauxDataConnect.recupererNiveau(conn, id); if(this.niveauEnCours != null){ // Remise à zéro de l'état propre au niveau this.segmentsTermines = 0; this.dernierSegmentValide = null; this.ecran.partiePerdue = false; // On corse le jeu avec son ID //On applique les paramètres aux options de jeu this.laLigne.generer(niveauEnCours.getNbSegments(), niveauEnCours.getId()); this.laLigne.setVitesseLigne(niveauEnCours.getVitesseLigne()); // On modifie la vitesse de déplacement this.demiCercleAvant.setCouleur(niveauEnCours.getCouleurCercle()); this.demiCercleArriere.setCouleur(niveauEnCours.getCouleurCercle()); this.ecran.changerImageFond(niveauEnCours.getImage()); }else{ JFrame fenetre = new JFrame(); JOptionPane.showMessageDialog(fenetre, "CONGRATULATIONS !!! BRAVO VOUS AVEZ TERMINE LE JEU"); System.out.println("Fin du jeu !!! BRAVO VOUS AVEZ TERMINE LE JEU"); horloge.stop(); } } //------------------------------------------------------------------------------------------------ // Méthode permettant de passer au niveau suivant à travers l'id //------------------------------------------------------------------------------------------------ private void passerAuNiveauSuivant(){ // Nettoyage de l'état de validation avant de charger le niveau suivant this.segmentsTermines = 0; this.dernierSegmentValide = null; // On incrémente l'ID du niveau actuel idNiveauActuel++; JFrame fenetre = new JFrame(); // Petite pause avec un message horloge.stop(); JOptionPane.showMessageDialog(fenetre, "Niveau terminé ! Préparez-vous pour le niveau suivant ;)"); chargerNiveau(idNiveauActuel); horloge.start(); } //------------------------------------------------------------------------------------------------ // Méthode appelée lorsqu'un événement timer se produit // -> C'est ici que la loqique et l'animation du jeu sont traitées // -> C'est ici que la vérification de la collision entre la ligne et le cercle doit être faite //------------------------------------------------------------------------------------------------ @Override public void actionPerformed(ActionEvent e) { // 1. Animer et recalculer le segment courant this.ecran.traiterBoucleAnimation(); this.laLigne.actualiserSegCourant(); // Mode triche : centrer le cercle sur le milieu du segment courant if (modeTriche && this.laLigne.getSegCourant() != null) { double milieuY = this.laLigne.getSegCourant().getMilieuY(); this.demiCercleAvant.y = milieuY; this.demiCercleArriere.y = milieuY; } // 2. On vérifie si la ligne traverse bien le cercle boolean verification = this.laLigne.estDansCercle(this.demiCercleAvant); // NB: Le nombre de segment s'incrémente qu'il y est collision ou pas if(verification){ // On compte seulement lorsqu'on change de segment Segment segmentCourant = this.laLigne.getSegCourant(); if(segmentCourant != null && segmentCourant != this.dernierSegmentValide){ this.dernierSegmentValide = segmentCourant; this.segmentsTermines++; // Ajouter les points continuellement tant que le segment est vert (cyan) this.score += this.niveauEnCours.getMultiplicateurScore(); this.jeuCommence = true; } // Vérification si on a atteint l'objectif du niveau : Nb de Segments du niveau atteint if(this.segmentsTermines >= this.niveauEnCours.getNbSegments()){ passerAuNiveauSuivant(); } }else{ // On compte seulement lorsqu'on change de segment Segment segmentCourant = this.laLigne.getSegCourant(); if(segmentCourant != null && segmentCourant != this.dernierSegmentValide){ this.dernierSegmentValide = segmentCourant; this.segmentsTermines++; } //------------------------------------------------------------------------------------------------------------------- // A FAIRE: Le jeu peut s'arrêter si la ligne n'est pas dans le cercle // NB: Le jeu commence quand la ligne est dans le cercle // Au début le ligne n'est pas dans le cercle car la ligne est à droite du cercle, et elle se déplace vers la gauche //------------------------------------------------------------------------------------------------------------------- if (this.laLigne.getSegCourant()!=null && !this.modeTriche) { // Le jeu s'arrête si le joueur n'a pas traversé la première ligne this.horloge.stop(); // 1. Arrêter le temps this.ecran.partiePerdue = true; // 2. Signaler à l'écran this.ecran.repaint(); // 3. Forcer l'affichage du texte // GestionBDD.ajouterScore((int)this.score);// enregistrement du score dans la base de donne } } labScore.setText("

score : " + this.score + "

"); } }