Caccia alla Talpa

This commit is contained in:
2025-11-13 17:08:32 +01:00
parent cc9f2f7ebf
commit 70e46cc65c
6 changed files with 350 additions and 0 deletions

30
CacciaLaTalpa/.gitignore vendored Normal file
View File

@@ -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

8
CacciaLaTalpa/.idea/.gitignore generated vendored Normal file
View File

@@ -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

6
CacciaLaTalpa/.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_25" default="true" project-jdk-name="25" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

8
CacciaLaTalpa/.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/CacciaLaTalpa.iml" filepath="$PROJECT_DIR$/CacciaLaTalpa.iml" />
</modules>
</component>
</project>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -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);
});
}
}