diff --git a/CacciaLaTalpa/.gitignore b/CacciaLaTalpa/.gitignore new file mode 100644 index 0000000..13275f1 --- /dev/null +++ b/CacciaLaTalpa/.gitignore @@ -0,0 +1,30 @@ +### IntelliJ IDEA ### +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ +.kotlin + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/CacciaLaTalpa/.idea/.gitignore b/CacciaLaTalpa/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/CacciaLaTalpa/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/CacciaLaTalpa/.idea/misc.xml b/CacciaLaTalpa/.idea/misc.xml new file mode 100644 index 0000000..188022c --- /dev/null +++ b/CacciaLaTalpa/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/CacciaLaTalpa/.idea/modules.xml b/CacciaLaTalpa/.idea/modules.xml new file mode 100644 index 0000000..ed35cee --- /dev/null +++ b/CacciaLaTalpa/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/CacciaLaTalpa/CacciaLaTalpa.iml b/CacciaLaTalpa/CacciaLaTalpa.iml new file mode 100644 index 0000000..c90834f --- /dev/null +++ b/CacciaLaTalpa/CacciaLaTalpa.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/CacciaLaTalpa/src/CacciaAllaTalpa.java b/CacciaLaTalpa/src/CacciaAllaTalpa.java new file mode 100644 index 0000000..1044c1d --- /dev/null +++ b/CacciaLaTalpa/src/CacciaAllaTalpa.java @@ -0,0 +1,287 @@ +import javax.swing.*; // Importa componenti GUI (JFrame, JButton, JLabel, ecc.) +import java.awt.*; // Importa layout e colori (BorderLayout, GridLayout, Color) +import java.awt.event.*; // Importa gestione eventi (ActionListener, ActionEvent) +import java.util.Random; // Importa classe per numeri casuali + +// Classe principale che estende JFrame (la finestra dell'applicazione) +public class CacciaAllaTalpa extends JFrame { + // === COSTANTI === + private static final int NUM_BUCHI = 6; // Numero totale di buchi + private static int TEMPO_TALPA = 2000; // Millisecondi che la talpa rimane visibile + + // === COMPONENTI GUI === + private JButton[] buchi; // Array di 6 bottoni che rappresentano i buchi + private JLabel lblPunteggio; // Etichetta per mostrare il punteggio + private JLabel lblVite; // Etichetta per mostrare le vite rimaste + + // === VARIABILI DI GIOCO === + private int punteggio = 0; // Punteggio corrente del giocatore + private int vite = 5; // Vite rimanenti (inizi con 5) + private int posizioneCorrente = -1; // Indice del buco dove si trova la talpa (-1 = nessuna talpa) + private Timer timerTalpa; // Timer per spostare la talpa ogni 2 secondi + private Random random; // Generatore di numeri casuali + private boolean giocoAttivo = true; // Flag per sapere se il gioco è in corso + + // === COSTRUTTORE === + // Qui viene inizializzata tutta l'interfaccia grafica + public CacciaAllaTalpa() { + // Imposta il titolo della finestra + setTitle("Caccia alla Talpa"); + + // Chiudi l'applicazione quando chiudi la finestra + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + // BorderLayout: divide la finestra in 5 zone (NORTH, SOUTH, EAST, WEST, CENTER) + // I numeri (10, 10) sono gli spazi orizzontali e verticali tra le zone + setLayout(new BorderLayout(10, 10)); + + // Impedisci il ridimensionamento della finestra + setResizable(false); + + // Inizializza il generatore di numeri casuali + random = new Random(); + + // === PANNELLO SUPERIORE (Punteggio e Vite) === + // GridLayout(1, 2): 1 riga, 2 colonne + // 20 = spazio orizzontale tra le colonne, 0 = nessuno spazio verticale + JPanel panelInfo = new JPanel(new GridLayout(1, 2, 20, 0)); + + // BorderFactory.createEmptyBorder(top, left, bottom, right) + // Crea un margine interno di 15 pixel su tutti i lati + panelInfo.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15)); + + // Colore verde per il pannello superiore + panelInfo.setBackground(new Color(34, 139, 34)); + + // === LABEL PUNTEGGIO === + lblPunteggio = new JLabel("Punteggio: 0", SwingConstants.CENTER); + lblPunteggio.setFont(new Font("Arial", Font.BOLD, 20)); // Font grande e grassetto + lblPunteggio.setForeground(Color.WHITE); // Testo bianco + + // === LABEL VITE === + lblVite = new JLabel("Vite: 5", SwingConstants.CENTER); + lblVite.setFont(new Font("Arial", Font.BOLD, 20)); + lblVite.setForeground(Color.WHITE); + + // Aggiungi le due label al pannello + panelInfo.add(lblPunteggio); + panelInfo.add(lblVite); + + // === PANNELLO CENTRALE (I 6 buchi) === + // GridLayout(2, 3): 2 righe, 3 colonne = 6 celle totali + // 15, 15 = spazi tra le celle (orizzontale, verticale) + JPanel panelBuchi = new JPanel(new GridLayout(2, 3, 15, 15)); + panelBuchi.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + panelBuchi.setBackground(new Color(139, 69, 19)); // Colore marrone (terra) + + // Crea l'array di 6 bottoni + buchi = new JButton[NUM_BUCHI]; + + // Ciclo per creare tutti i 6 buchi + for (int i = 0; i < NUM_BUCHI; i++) { + // IMPORTANTE: final per usare 'i' dentro la lambda + final int index = i; + + // Crea un nuovo bottone + buchi[i] = new JButton(); + + // Imposta dimensione fissa del bottone (120x120 pixel) + buchi[i].setPreferredSize(new Dimension(120, 120)); + + // Font grande per l'emoji della talpa + buchi[i].setFont(new Font("Arial", Font.BOLD, 40)); + + // Colore di sfondo marrone scuro + buchi[i].setBackground(new Color(101, 67, 33)); + + // Rimuovi il bordo tratteggiato quando il bottone ha il focus + buchi[i].setFocusPainted(false); + + // Bordo nero spesso 3 pixel attorno al bottone + buchi[i].setBorder(BorderFactory.createLineBorder(Color.BLACK, 3)); + + // === EVENT LISTENER === + // Quando clicchi il bottone, chiama clickBuco(index) + // 'e' è l'evento (ActionEvent) che contiene info sul click + buchi[i].addActionListener(e -> clickBuco(index)); + + // Aggiungi il bottone al pannello + panelBuchi.add(buchi[i]); + } + + // === AGGIUNGI I PANNELLI ALLA FINESTRA === + // BorderLayout.NORTH = zona superiore + add(panelInfo, BorderLayout.NORTH); + // BorderLayout.CENTER = zona centrale (prende tutto lo spazio rimanente) + add(panelBuchi, BorderLayout.CENTER); + + // pack() ridimensiona la finestra per contenere tutti i componenti + pack(); + + // Centra la finestra sullo schermo (null = centro dello schermo) + setLocationRelativeTo(null); + + // === TIMER PRINCIPALE === + // Timer che ogni 2 secondi (TEMPO_TALPA) chiama spostaOPerdiVita() + // 'e' è l'ActionEvent generato dal timer + timerTalpa = new Timer(TEMPO_TALPA, e -> spostaOPerdiVita()); + + // === AVVIO DEL GIOCO === + // Timer che aspetta 1 secondo prima di iniziare il gioco + Timer startTimer = new Timer(1000, e -> { + mostraTalpa(); // Mostra la prima talpa + timerTalpa.start(); // Avvia il timer principale + }); + startTimer.setRepeats(false); // Esegui solo una volta + startTimer.start(); // Avvia questo timer + } + + // === METODO: MOSTRA LA TALPA === + // Questo metodo nasconde la talpa precedente e la mostra in una nuova posizione casuale + private void mostraTalpa() { + // Se il gioco non è attivo, esci subito dal metodo + if (!giocoAttivo) return; + + // Nascondi la talpa dalla posizione precedente + if (posizioneCorrente >= 0) { + buchi[posizioneCorrente].setText(""); // Rimuovi l'emoji + // Ripristina il colore originale del buco + buchi[posizioneCorrente].setBackground(new Color(101, 67, 33)); + } + + // Genera una nuova posizione casuale (da 0 a 5) + posizioneCorrente = random.nextInt(NUM_BUCHI); + + // Mostra la talpa nella nuova posizione + buchi[posizioneCorrente].setText("🐭"); // Emoji della talpa + // Schiarisci leggermente il colore per evidenziare la talpa + buchi[posizioneCorrente].setBackground(new Color(139, 90, 43)); + } + + // === METODO: GESTIONE CLICK SU UN BUCO === + // Parametro: index = quale buco è stato cliccato (da 0 a 5) + private void clickBuco(int index) { + // Se il gioco non è attivo, non fare nulla + if (!giocoAttivo) return; + + // Controlla se hai cliccato sul buco giusto (dove c'è la talpa) + if (index == posizioneCorrente) { + // === HAI COLPITO LA TALPA! === + punteggio++; // Incrementa il punteggio + // Aggiorna la label del punteggio + lblPunteggio.setText("Punteggio: " + punteggio); + + // Feedback visivo: colora di verde il buco + buchi[index].setBackground(Color.GREEN); + + // Resetta il timer principale (ricomincia il conto di 2 secondi) + timerTalpa.restart(); + + // Timer per mostrare subito una nuova talpa dopo 200ms + // Questo da il tempo di vedere il verde prima che la talpa si sposti + Timer feedbackTimer = new Timer(200, e -> mostraTalpa()); + feedbackTimer.setRepeats(false); // Esegui una sola volta + feedbackTimer.start(); + + } else { + // === HAI MANCATO! === + // Feedback visivo: colora di rosso il buco sbagliato + buchi[index].setBackground(Color.RED); + + // Timer per ripristinare il colore originale dopo 300ms + Timer resetColor = new Timer(300, e -> + buchi[index].setBackground(new Color(101, 67, 33))); + resetColor.setRepeats(false); + resetColor.start(); + } + } + + // === METODO: SPOSTA LA TALPA O PERDI UNA VITA === + // Questo metodo viene chiamato dal timer ogni 2 secondi + private void spostaOPerdiVita() { + if (!giocoAttivo) return; + + // Se arrivi qui, significa che i 2 secondi sono passati + // e il giocatore NON ha cliccato sulla talpa + vite--; // Perdi una vita + + // Aggiorna la label delle vite + lblVite.setText("Vite: " + vite); + + // Controlla se hai finito le vite + if (vite <= 0) { + fineGioco(); // Game Over + } else { + mostraTalpa(); // Mostra la talpa in una nuova posizione + } + } + + // === METODO: FINE DEL GIOCO === + private void fineGioco() { + giocoAttivo = false; // Ferma il gioco + timerTalpa.stop(); // Ferma il timer principale + + // Nascondi l'ultima talpa + if (posizioneCorrente >= 0) { + buchi[posizioneCorrente].setText(""); + buchi[posizioneCorrente].setBackground(new Color(101, 67, 33)); + } + + // Mostra un dialog con il punteggio finale + // JOptionPane.showConfirmDialog mostra una finestra con bottoni SI/NO + int scelta = JOptionPane.showConfirmDialog( + this, // Finestra padre + "Game Over!\nPunteggio finale: " + punteggio + "\n\nVuoi giocare ancora?", + "Fine Gioco", // Titolo del dialog + JOptionPane.YES_NO_OPTION // Tipo di bottoni + ); + + // Controlla quale bottone ha cliccato l'utente + if (scelta == JOptionPane.YES_OPTION) { + resetGioco(); // Ricomincia il gioco + } else { + System.exit(0); // Chiudi l'applicazione + } + } + + // === METODO: RESET DEL GIOCO === + // Ripristina tutte le variabili e ricomincia una nuova partita + private void resetGioco() { + // Azzera le variabili di gioco + punteggio = 0; + vite = 5; + posizioneCorrente = -1; + giocoAttivo = true; + + // Aggiorna le label + lblPunteggio.setText("Punteggio: 0"); + lblVite.setText("Vite: 5"); + + // Ripulisci tutti i buchi + for (JButton buco : buchi) { + buco.setText(""); // Rimuovi eventuali talpe + buco.setBackground(new Color(101, 67, 33)); // Colore originale + } + + // Aspetta 1 secondo e poi riavvia il gioco + Timer startTimer = new Timer(500, e -> { + mostraTalpa(); // Mostra la prima talpa + timerTalpa.restart(); // Riavvia il timer principale + }); + startTimer.setRepeats(false); + startTimer.start(); + } + + // === METODO MAIN === + // Punto di ingresso del programma + public static void main(String[] args) { + // SwingUtilities.invokeLater() esegue il codice nel thread della GUI + // È la best practice per creare interfacce Swing + SwingUtilities.invokeLater(() -> { + // Crea una nuova istanza del gioco + CacciaAllaTalpa gioco = new CacciaAllaTalpa(); + // Rendi visibile la finestra + gioco.setVisible(true); + }); + } +} \ No newline at end of file