Snake in Java: come realizzarlo

Snake in Java: come realizzarlo

snake in java

Hai sempre desiderato ricreare il gioco snake in java? Ecco come realizzarlo passaggio per passaggio. Copia il codice e provalo subito!

Il programma in questione è una riproduzione del classico gioco “Snake” utilizzando il linguaggio di programmazione Java. Il gioco consiste nel controllare un serpente, rappresentato da una serie di blocchi, e farlo muovere all’interno di un tabellone. Lo scopo del gioco è di far mangiare al serpente delle mele, che appaiono casualmente sul tabellone, facendo crescere il serpente. Il gioco termina quando il serpente collide con un bordo del tabellone o con il proprio corpo. Il gioco è implementato attraverso la gestione degli eventi della tastiera e l’uso di un timer che regola l’aggiornamento del gioco ad ogni ciclo. La grafica del gioco è realizzata utilizzando la libreria grafica Swing di Java.

Snake in Java: Codice

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

// Classe Snake che estende JFrame e implementa ActionListener
public class Snake extends JFrame implements ActionListener {
    // Costanti che rappresentano le dimensioni della finestra di gioco e la grandezza di un blocco
    private static final int BOARD_WIDTH = 300;
    private static final int BOARD_HEIGHT = 300;
    private static final int DOT_SIZE = 10;
    private static final int ALL_DOTS = 900;
    private static final int RAND_POS = 29;
    // Array che rappresenta le coordinate x e y di ogni blocco del serpente
    private final int[] x = new int[ALL_DOTS];
    private final int[] y = new int[ALL_DOTS];
    // Variabili che rappresentano la lunghezza del serpente, la posizione della mela e la velocità del gioco
    private int dots;
    private int apple_x;
    private int apple_y;
    private int delay = 140;
    // Variabili che rappresentano la direzione del serpente
    private boolean leftDirection = false;
    private boolean rightDirection = true;
    private boolean upDirection = false;
    private boolean downDirection = false;
    // Variabili che rappresentano lo stato del gioco
    private boolean inGame = true;
    private Timer timer;
    
    // Costruttore della classe Snake
    public Snake() {
        // Chiama il costruttore della classe base
        super("Snake");
        
        // Crea una nuova istanza della classe TAdapter per gestire gli eventi della tastiera
        TAdapter adapter = new TAdapter();
        // Aggiunge l'adapter alla finestra di gioco
        addKeyListener(adapter);
        // Imposta il background della finestra di gioco
        setBackground(Color.black);
        // Imposta le dimensioni della finestra di gioco
        setPreferredSize(new Dimension(BOARD_WIDTH, BOARD_HEIGHT));
        // Disabilita il ridimensionamento della finestra di gioco
        setResizable(false);
        // Centra la finestra di gioco sullo schermo
        pack();
        setLocationRelativeTo(null);
        // Chiude la finestra di gioco quando l'utente preme la X in alto a destra
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // Crea una nuova istanza della classe GamePanel e aggiunge il pannello alla finestra di gioco
        add(new GamePanel());
        // Imposta lo stato del gioco in corso
        inGame = true;
        // Imposta la posizione iniziale del serpente e la lunghezza iniziale a 3 blocchi
        initGame();
        // Imposta un timer che chiama il metodo actionPerformed() ogni volta che scatta, con un ritardo iniziale di 100ms
        timer = new Timer(delay, this);
        timer.start();
    }
    
    // Metodo per impostare la posizione iniziale del serpente e la lunghezza iniziale
    private void initGame() {
        // Imposta la lunghezza iniziale del serpente è di 3 blocchi
        dots = 3;
        // Imposta la posizione x e y di ogni blocco del serpente
        for (int i = 0; i < dots; i++) {
            x[i] = 50 - i * DOT_SIZE;
            y[i] = 50;
        }
        // Genera una nuova posizione casuale per la mela
        locateApple();
    }
    
    // Metodo per generare una nuova posizione casuale per la mela
    private void locateApple() {
        // Crea un nuovo oggetto Random per generare numeri casuali
        Random rand = new Random();
        // Genera un numero casuale tra 0 e 29 per la posizione x e y della mela
        apple_x = rand.nextInt(RAND_POS) * DOT_SIZE;
        apple_y = rand.nextInt(RAND_POS) * DOT_SIZE;
    }
    
    // Metodo per disegnare il serpente e la mela sulla finestra di gioco
    private void doDrawing(Graphics g) {
        // Se il gioco è in corso, disegna il serpente e la mela
        if (inGame) {
            g.setColor(Color.red);
            g.fillOval(apple_x, apple_y, DOT_SIZE, DOT_SIZE);
            for (int i = 0; i < dots; i++) {
                if (i == 0) {
                    g.setColor(Color.green);
                    g.fillRect(x[i], y[i], DOT_SIZE, DOT_SIZE);
                } else {
                    g.setColor(Color.yellow);
                    g.fillRect(x[i], y[i], DOT_SIZE, DOT_SIZE);
                }
            }
            // Sincronizza la finestra di gioco con il buffer di immagine
            Toolkit.getDefaultToolkit().sync();
        } else {
            // Se il gioco è terminato, mostra il messaggio "Game Over" e ferma il timer
            gameOver(g);
        }
    }
    
    // Metodo per gestire la fine del gioco
    private void gameOver(Graphics g) {
        // Crea un oggetto String che contiene il messaggio "Game Over"
        String msg = "Game Over";
        // Crea un nuovo oggetto Font per il messaggio "Game Over"
        g.setColor(Color.white);
        g.drawString(msg, (BOARD_WIDTH - g.getFontMetrics().stringWidth(msg)) / 2, BOARD_HEIGHT / 2);
        // Ferma il timer
        timer.stop();
    }
    
    // Metodo che viene chiamato ogni volta che il timer scatta
    @Override
    public void actionPerformed(ActionEvent e) {
        // Se il gioco è in corso, aggiorna la posizione del serpente e controlla se il serpente ha mangiato la mela o ha collisionato con i bordi o con se stesso
        if (inGame) {
            checkApple();
            checkCollision();
            move();
        }
        // Richiama il metodo repaint() per ridisegnare la finestra di gioco
        repaint();
    }
    
    // Metodo per controllare se il serpente ha mangiato la mela
    private void checkApple() {
        if ((x[0] == apple_x) && (y[0] == apple_y)) {
            // Se la testa del serpente si trova sulla mela, incrementa la lunghezza del serpente e genera una nuova posizione ca
            dots++;
            locateApple();
        }
    }
    
    // Metodo per controllare se il serpente ha collisionato con i bordi o con se stesso
    private void checkCollision() {
        // Controlla se il serpente ha collisionato con i bordi del gioco
        for (int i = dots; i > 0; i--) {
            if ((i > 4) && (x[0] == x[i]) && (y[0] == y[i])) {
                inGame = false;
            }
        }
        if (y[0] >= BOARD_HEIGHT) {
            inGame = false;
        }
        if (y[0] < 0) {
            inGame = false;
        }
        if (x[0] >= BOARD_WIDTH) {
            inGame = false;
        }
        if (x[0] < 0) {
            inGame = false;
        }
        // Se il serpente ha collisionato con i bordi, imposta inGame a false per terminare il gioco
        if (!inGame) {
            timer.stop();
        }
    }
    
    // Metodo per aggiornare la posizione del serpente
    private void move() {
        // Sposta ogni blocco del serpente nella posizione del blocco precedente
        for (int i = dots; i > 0; i--) {
            x[i] = x[(i - 1)];
            y[i] = y[(i - 1)];
        }
        // Sposta la testa del serpente nella direzione corrente
        if (leftDirection) {
            x[0] -= DOT_SIZE;
        }
        if (rightDirection) {
            x[0] += DOT_SIZE;
        }
        if (upDirection) {
            y[0] -= DOT_SIZE;
        }
        if (downDirection) {
            y[0] += DOT_SIZE;
        }
    }
    
    // Classe interna per gestire i tasti premuti dall'utente
    private class TAdapter extends KeyAdapter {
        
        @Override
        public void keyPressed(KeyEvent e) {
            // Ottiene il codice del tasto premuto
            int key = e.getKeyCode();
            // Controlla se il tasto premuto è uno dei tasti freccia
            if ((key == KeyEvent.VK_LEFT) && (!rightDirection)) {
                leftDirection = true;
                upDirection = false;
                downDirection = false;
            }
            if ((key == KeyEvent.VK_RIGHT) && (!leftDirection)) {
                rightDirection = true;
                upDirection = false;
                downDirection = false;
            }
            if ((key == KeyEvent.VK_UP) && (!downDirection)) {
                upDirection = true;
                rightDirection = false;
                leftDirection = false;
            }
            if ((key == KeyEvent.VK_DOWN) && (!upDirection)) {
                downDirection = true;
                rightDirection = false;
                leftDirection = false;
            }
        }
    }
}


Spero che i commenti siano stati utili per comprendere meglio il funzionamento del codice! Per qualsiasi dubbio ti consiglio di supervisionare i nostri articoli riguardo alla programmazione in java

COMANDI JAVA: i più importanti

COMANDI JAVA: i più importanti

COMANDI JAVA

INTRODUZIONE JAVA

In questo capitolo faremo una panoramica della sintassi del linguaggio java.
Vedremo anche un importantissimo aspetto: la distinzione tra tipi primitivi e oggetti. Prima di iniziare cerchiamo di capire però cos’è questo linguaggio java.

  • Java è un linguaggio imperativo orientato agli oggetti.
  • Contiene espressioni che vengono gestite tramite comandi.
  • I comandi vengono incapsulati in metodi
  • I metodi vengono contenuti in classi
  • A loro volta le classi vengono riunite in raccolte chiamate package.

comandi java comandi java comandi javca

COMANDI JAVA

COMMENTI

Questi sono i comandi che ci permetteranno di creare dei commenti accanto al codice al fine di ricordarci magari dei passaggi creati o per far si che se qualcun altro prenda in nostro programma sia in grado di capirne lo svolgimento.

/* commento */

• Tutti i caratteri compresi tra / e/ sono ignorati.

// commento

• Tutti i caratteri successivi a // fino a fine linea sono ignorati.

.

ESPRESSIONI JAVA

All’interno di un programma in Java possiamo trovare diverse espressioni, ore ne vedremo alcune:

Espressione: a+1

Una espressione si può suddividere in:

  • Costanti: 1 è una costante
  • Operatori: + è un operatore
  • Variabili: a è una variabile

Sintassi comandi

I comandi all’interno di queste espressioni possono essere:

Semplici, ovvero una espressioni che si concludono con ;

a+1;


Composti ovvero un comando contenente un altro comando:

if (a>1)
b=b+1;

Comandi java: DICHIARAZIONE VARIABILE

All’interno di un programma Java sono presenti molte variabili, dato che senza di esse non si potrebbe svolgere un esercizio. Le variabili sono semplicemente dei tipi di dati che possono esser numeri, stringhe (parole), lettere, vero o falso etc. Esistono diversi tipi di valori. Ecco dei comandi java:

  • Interi —> int
  • Stringhe —-> String
  • Lettere —> char
  • Vero o falso —> bool

Una dichiarazione può essere seguita da un’espressione di inizializzazione (opzionale), per tanto per dichiarare una variabile basterà scrivere la tipologia di dato che si vuole salvare e il nome con cui questo dato verrà ricordato.

String s = “hello”;

In questo caso, tramite questo comando, viene registrata una variabile di nome “s” di tipo stringa a cui viene associato il “valore” (in questo caso) “hello”

Metodi JAVA

Un metodo in java, quando si dichiara è simile ad una funzione matematica: ha dei parametri e ritorna un valore. Prendiamo ad esempio questa funzione:

int test(int x, int y)

Bisogna notare che questa funzione è un metodo che prende due interi come parametri e ritorna un intero.

Un metodo è seguito da un comando che definisce il suo comportamento:

int sum (int x, int y)
{
return x+y;
}

Una particolarità dei metodi è che si trovano sempre dentro una classe. Infatti i metodi hanno sempre un contesto (o ambiente).

In un metodo possono esserci dichiarazioni di variabili (locali al metodo):

int test(int x, int y)
{
int r=x+y;
return r;
}

Sintassi classi: comandi java

Le classi contengono campi e metodi come in questo caso:

class Sum
{
int k=1; // campo
int test(int x)
{ // metodo
int h = 2;
return x+h+k;
}
}

Un campo (k) è una cosa diversa da una variabile locale (h) e da parametro di un metodo (x).

Tipi di dato

Come abbiamo detto, ci sono due “gruppi” di tipi di dato:

• Primitivi
• Oggetti


Primitivi:

  • Sono fissi
  • Una “istanza” di tipo primitivo è generata da una costante
  • Si agisce su di essi con gli operatori
  • Una variabile “contiene” un tipo primitivo (il concetto tradizionale di variabile)

Oggetti:

  • Sono in numero illimitato (creati dal programmatore)
  • Una “istanza” di oggetto è generata da un costruttore
  • Si agisce su di essi con i metodi
  • Una variabile “riferisce” un oggetto: è un puntatore

Comandi java: OPERATORI

Gli operatori agiscono sui tipi primitivi e possiamo suddividerli in diverse categorie ma prima di tutto dobbiamo ricordare delle cose. All’interno dei calcoli:

  • Ogni valore intero inferiore ad int diventa int
  • Ogni valore float diventa double
  • Un operatore opera solo su valori della stessa dimensione
  • Tra due operandi, (a + b) il “più grosso” comanda e l’altro viene ingrandito
  • Per assegnare a valori inferiori bisogna “convertire” (troncando) Esempio:

Operatori aritmetici

+ − * / %


Somma, sottrazione, prodotto, divisione e modulo. Prendono due argomenti, di tipo int o float e ritornano un int o float

Operatori Relazionali

= < <= == !=

  • Maggiore, MaggioreUguale, Minore, MinoreUguale, Uguale e Diverso
  • Notare che Uguale è due segni ‘=’ (mentre l’assegnamento è un segno ‘=’)
  • Operano su interi e double
  • Uguale e Diverso operano anche su booleani

Comandi java: Operatori Logici

&& (and)

• opera su valori booleani
• comportamento short − circuit:

valore determinato se il primo operando è false in tal caso non viene valutato il secondo E’ utile:
c != −1 && c = in.read()
se c’è EOF (−1), non viene letto un altro carattere

Entrambi i controlli devono esser veri.

|| (or)

• comportamento short − circuit:

valore determinato se il primo operando è true
n tal caso non viene valutato il secondo E’ utile:
n ? table.min() || n ? table.max()
si risparmia un calcolo (pesante) del max

Basta che un solo controllo sia vero.

Operatori Incremento

++ —

  • ++ incremento di 1
  • −− decremento di 1
  • operano su interi e float

Operatori di Assegnamento:

a = b

a=b è una espressione con effetti collaterali questo perchè viene modificato il valore a con il valore b. Pertanto se prima a=2 e b=3 ora il valore di a=3

a = b = c

Questa espressione equivale ad a = (b = c) dove b=c, modifica b con il valore di c. a=c dato che b abbiamo detto che è uguale a c

a += b

Questa espressione equivale ad a = a + b

Se sei interessato a ad approfondire il linguaggio java, visita il nostro articolo cliccando qui.

Vuoi approfondire tematiche più complesse? Scopri i timer java, visitando il nostro articolo cliccando qui.

Ti piacciono altri linguaggi di programmazione? Per il linguaggio C, ti consiglio di visitare il nostro articolo cliccando qui.

comandi java
TIMER JAVA

TIMER JAVA

Indice

Scrivendo in java può esserti capitato di aver bisogno di utilizzare dei timer per effettuare delle operazioni in modo ripetitivo oppure che non avvenissero immediatamente alla pressione di un tasto ma che che prima trascorresse del tempo.
Adesso andremo a vedere il modo più semplice per fare ciò, con pochissime righe di comando.
Prima di tutto bisogna assicurarsi di includere le seguenti due librerie che ci permetteranno di lavorare con dei timer.

import java.util.Timer;
import java.util.TimerTask;

La prima ci permetterà di dichiarare dei timer mentre la seconda di effettuare delle operazioni (task) dipendenti da un timer.
Adesso la prima cosa da fare è la dichiarazione di un timer.
Per fare ciò basterà scrivere:

Timer timer = new Timer();

Dove ‘timer’ sarà il nome attribuito al timer (potete mettere quello che più preferite).
Il passo successivo sarà quindi la creazione di un task collegato al timer che abbiamo appena dichiarato.

TimerTask task1= new TimerTask() {

Scrivendo questo codice e aprendo una parentesi graffa, ci permetterà di posizionarci con la freccia del mouse su “TimerTask()” e di selezionare “add unimplemented methods” che crearà in automatico una funzione, che useremo per scrivere tutto il codice che si dovrà eseguire allo scadere del timer.

Dove cliccare
Come deve apparire la funzione autocreata

A questo punto non resta che scrivere all’interno del public void run il codice che dovrà eseguire allo scadere del Timer. Ma adesso procediamo a vedere qual è il modo più semplice per dichiarare un Timer funzionante.

Scrivendo il nome che abbiamo assegnato al timer (in questo caso ‘timer1’) e mettendo il punto si possono vedere una preview di tutte le combinazioni di comandi possibili relative al timer.
Vediamone un paio:

timer1.schedule(task1, 0);

Il comando schedule ha due attributi. Il primo dovrà essere il nome del task che dovrà andare a eseguire e il secondo sarà il tempo, espresso in millisecondo, dopo il quale dovrà eseguire il task.

ESERCIZIO JAVA TIMER

Per un esempio dell’esercizio cliccare qui.