Nella
sezione "Giochi" di CodeGym troverai progetti entusiasmanti che prevedono la scrittura di famosi giochi per computer. Vuoi creare la tua versione dei popolari giochi 2048, Minesweeper, Snake e altri giochi? È semplice. Abbiamo trasformato la scrittura di giochi in un processo graduale.
Per mettere alla prova le tue capacità di sviluppatore di giochi, non devi essere un programmatore avanzato, ma è necessario un insieme specifico di conoscenze Java. Qui troverai
informazioni che ti saranno utili nella scrittura del gioco .
1. Ereditarietà
Lavorare con il motore di gioco CodeGym comporta l'utilizzo dell'ereditarietà. Ma cosa succede se non sai cos'è? Da un lato, devi capire questo argomento: è studiato al
livello 11. D'altra parte, il motore è stato appositamente progettato per essere molto semplice, quindi puoi farla franca con una conoscenza superficiale dell'ereditarietà. Quindi cos'è l'eredità? In parole povere, l'ereditarietà è una relazione tra due classi. Uno di loro diventa il genitore e l'altro diventa un figlio (discendente). Inoltre, la classe genitore potrebbe anche non sapere di avere discendenti. In altre parole, non trae alcun vantaggio particolare dall'avere discendenti. Ma l'eredità offre molti vantaggi a un discendente. E il più importante è che tutte le variabili ei metodi della classe genitore appaiono nel discendente come se il codice della classe genitore fosse stato copiato nella classe discendente. Questa non è una descrizione del tutto accurata, ma sarà sufficiente per una comprensione semplificata dell'ereditarietà.
Esempio 1: L'eredità più semplice.
public class Parent {
}
|
La classe Child eredita la classe Parent utilizzando la parola chiave extends . |
public class Child extends Parent {
}
|
Esempio 2: utilizzo delle variabili della classe genitore.
public class Parent {
public int age;
public String name;
}
|
La classe Child può usare le variabili age e name della classe Parent come se fossero dichiarate nella classe Parent . |
public class Child extends Parent {
public void printInfo() {
System.out.println(name+" "+age);
}
}
|
Esempio 3: utilizzo dei metodi della classe genitore.
public class Parent {
public int age;
public String name;
public getName() {
return name;
}
}
|
La classe Child può utilizzare le variabili ei metodi della classe Parent come se fossero dichiarati nella classe Child. In questo esempio, utilizziamo il metodo getName() . |
public class Child extends Parent {
public void printInfo() {
System.out.println(getName()+" "+age);
}
}
|
Ecco come appare la classe
Child al compilatore:
public class Child extends Parent{
public int age;
public String name;
public getName() {
return name;
}
public void printInfo() {
System.out.println(getName()+" "+age);
}
}
2. Metodi di override
A volte ci sono situazioni in cui facciamo ereditare alla nostra classe Child una classe Parent molto utile, insieme a tutte le sue variabili e metodi, ma alcuni metodi non funzionano esattamente come vorremmo. O per niente come vorremmo che lo facessero. Cosa possiamo fare in questa situazione? Possiamo sovrascrivere il metodo che non ci piace. Questo è molto facile da fare: nella nostra classe Child, dichiariamo semplicemente un metodo con la stessa firma del metodo nella classe Parent, e poi scriviamo il nostro codice al suo interno.
Esempio 1: sostituzione di un metodo.
public class Parent {
public String name;
public void setName(String nameNew) {
name = nameNew;
}
public getName() {
return name;
}
}
|
Il metodo printInfo() visualizzerà "Luke, No!!!" |
public class Child extends Parent{
public void setName(String nameNew) {
name = nameNew + ", No!!!";
}
public void printInfo() {
setName("Luke");
System.out.println(getName());
}
}
|
Ecco come appare la classe
Child al compilatore:
public Child extends Parent {
public String name;
public void setName(String nameNew)
name = nameNew + ", No!!!";
}
public getName() {
return name;
}
public void printInfo() {
setName("Luke");
System.out.println( getName());
}
}
Esempio 2: alcune magie di ereditarietà (e override del metodo).
public class Parent {
public getName() {
return "Luke";
}
public void printInfo() {
System.out.println(getName());
}
}
|
public class Child extends Parent {
public getName() {
return "Luke, I am your father";
}
}
|
In questo esempio, se il
printInfo
metodo (della classe Parent) non viene sovrascritto nella classe Child, quando questo metodo viene chiamato su un oggetto Child,
getName()
verrà chiamato il suo metodo invece del
getName()
metodo della classe Parent.
Parent parent = new Parent ();
parent.printnInfo();
|
Questo codice visualizza "Luke" sullo schermo. |
Child child = new Child ();
child.printnInfo();
|
Questo codice visualizza "Luke, io sono tuo padre" sullo schermo. |
Ecco come appare la classe
Child al compilatore:
public class Child extends Parent {
public getName() {
return "Luke, I am your father";
}
public void printInfo() {
System.out.println(getName());
}
}
3. Liste
Se non hai ancora incontrato le liste (Lista), ecco una breve panoramica. Puoi trovare informazioni complete nei livelli
6-7 del corso CodeGym .
Le liste hanno molto in comune con gli array:
- puoi memorizzare molti dati di un tipo specifico;
- ti permettono di ottenere gli elementi in base al loro indice;
- gli indici degli elementi iniziano da 0.
Vantaggi degli elenchi: a differenza degli array, gli elenchi possono cambiare dimensione in modo dinamico. Quando viene creato un elenco, la sua dimensione è 0. Man mano che aggiungi elementi a un elenco, la sua dimensione aumenta. Ecco un esempio di creazione di un elenco:
ArrayList<String> myList = new ArrayList<String>();
Il valore tra parentesi angolari indica il tipo di dati che l'elenco può memorizzare. Ecco alcuni metodi per lavorare con l'elenco:
Codice |
Breve descrizione di cosa fa il codice |
ArrayList<String> list = new ArrayList<String>(); |
Crea un nuovo elenco di stringhe |
list.add("name"); |
Aggiungi un elemento alla fine dell'elenco |
list.add(0, "name"); |
Aggiungi un elemento all'inizio dell'elenco |
String name = list.get(5); |
Ottieni un elemento dal suo indice |
list.set(5, "new name"); |
Cambia un elemento in base al suo indice |
int count = list.size(); |
Ottieni il numero di elementi nell'elenco |
list.remove(4); |
Elimina un elemento dall'elenco |
Puoi saperne di più sugli elenchi dai seguenti articoli:
- Classe ArrayList
- ArrayList nelle immagini
- Eliminazione di un elemento da un ArrayList
4. Matrici
Cos'è una matrice? Una matrice non è altro che una tabella rettangolare che può essere riempita di dati. In altre parole, è un array bidimensionale. Come probabilmente saprai, gli array in Java sono oggetti. Un array unidimensionale standard
int
si presenta così:
int [] array = {12, 32, 43, 54, 15, 36, 67, 28};
Possiamo visualizzarlo così:
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
32 |
43 |
54 |
15 |
36 |
67 |
28 |
La riga superiore indica gli indirizzi delle celle. In altre parole, per ottenere il numero 67, è necessario accedere all'elemento dell'array con indice 6:
int number = array[6];
È tutto molto semplice. Un array bidimensionale è un array di array unidimensionali. Se ne senti parlare per la prima volta, fermati e immaginalo nella tua testa. Un array bidimensionale ha questo aspetto:
0 |
Matrice unidimensionale |
Matrice unidimensionale |
1 |
Matrice unidimensionale |
2 |
Matrice unidimensionale |
3 |
Matrice unidimensionale |
4 |
Matrice unidimensionale |
5 |
Matrice unidimensionale |
6 |
Matrice unidimensionale |
7 |
Matrice unidimensionale |
Nel codice:
int [][] matrix = {
{65, 99, 87, 90, 156, 75, 98, 78},
{76, 15, 76, 91, 66, 90, 15, 77},
{65, 96, 17, 25, 36, 75, 54, 78},
{59, 45, 68, 14, 57, 1, 9, 63},
{81, 74, 47, 52, 42, 785, 56, 96},
{66, 74, 58, 16, 98, 140, 55, 77},
{120, 99, 13, 90, 78, 98, 14, 78},
{20, 18, 74, 91, 96, 104, 105, 77}
}
0 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
65 |
99 |
87 |
90 |
156 |
75 |
98 |
78 |
1 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
76 |
15 |
76 |
91 |
66 |
90 |
15 |
77 |
2 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
65 |
96 |
17 |
25 |
36 |
75 |
54 |
78 |
3 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
59 |
45 |
68 |
14 |
57 |
1 |
9 |
63 |
4 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
81 |
74 |
47 |
52 |
42 |
785 |
56 |
96 |
5 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
66 |
74 |
58 |
16 |
98 |
140 |
55 |
77 |
6 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
120 |
99 |
13 |
90 |
78 |
98 |
14 |
78 |
7 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
20 |
18 |
74 |
91 |
96 |
104 |
105 |
77 |
Per ottenere il valore 47, è necessario fare riferimento all'elemento della matrice in [4][2].
int number = matrix[4][2];
Potresti aver notato che le coordinate della matrice sono diverse dal classico sistema di coordinate rettangolari (sistema di coordinate cartesiane).
Quando si accede alla matrice, si specifica prima la coordinata y e poi la coordinata x. In matematica, è consuetudine specificare prima la coordinata x, cioè (x, y). Forse ti starai chiedendo: "Beh, perché non ruotare la tua rappresentazione della matrice e quindi accedere agli elementi nel solito modo usando (x, y)? Facendo questo non cambierebbe il contenuto della matrice". Sì, non cambierebbe nulla. Ma nel mondo della programmazione, la pratica accettata è quella di accedere alle matrici "prima per y, poi per x". Dovresti accettare questo come il modo corretto. Ora parliamo della proiezione della matrice sul nostro motore (
Game
classe). Come sai, il motore ha molti metodi che cambiano le celle del campo di gioco a coordinate specifiche. Ad esempio, il
setCellValue(int x, int y, String value)
metodo. Imposta una cella specifica con coordinate (x, y) uguali al parametro value. Potresti aver notato che questo metodo richiede prima x, proprio come nel classico sistema di coordinate. Gli altri metodi del motore funzionano in modo simile. Durante lo sviluppo di giochi, sarà spesso necessario riprodurre sullo schermo lo stato di una matrice. Come lo facciamo? Innanzitutto, devi scorrere tutti gli elementi della matrice in un ciclo. In secondo luogo, chiama il metodo di visualizzazione per ciascuno di essi, utilizzando le coordinate REVERSED. Per esempio:
private void drawScene() {
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
setCellValue(j, i, String.valueOf(matrix[i][j]));
}
}
}
Naturalmente, l'inversione funziona in entrambe le direzioni. Puoi passare (i, j) al
setCellValue
metodo e contemporaneamente prendere l'elemento [j][i] dalla matrice. Invertire le coordinate può sembrare un po' difficile, ma devi ricordartelo. E sempre, se incontri qualche problema, dovresti prendere un pezzo di carta e una penna, disegnare la matrice e riprodurre i processi che coinvolgono la matrice.
5. Numeri casuali
Come lavori con un generatore di numeri casuali? La
Game
classe definisce il
getRandomNumber(int)
metodo. Sotto il cofano, utilizza la
Random
classe del pacchetto java.util, ma il modo in cui lavori con il generatore di numeri casuali non cambia.
getRandomNumber(int)
accetta un numero intero come argomento. Questo numero sarà il limite massimo su ciò che il generatore può restituire. Il limite inferiore è 0.
Importante! Il generatore non restituirà MAI il numero limite superiore. Ad esempio, se chiami
getRandomNumber(3)
, restituirà casualmente 0, 1 o 2. Come puoi vedere, non può restituire 3. Usare il generatore in questo modo è abbastanza semplice, ma molto efficace in molti casi.
Supponiamo di dover ottenere un numero casuale in un intervallo: immagina di aver bisogno di un numero di tre cifre nell'intervallo [100..999]. Come già sai, il numero minimo restituito è 0. Quindi dovrai aggiungere 100. Ma in questo caso, devi fare attenzione a non superare il limite massimo. Per ottenere 999 come valore casuale massimo, chiama the
getRandomNumber(int)
metodo con l'argomento 1000. Ma ora ricordiamo che stiamo aggiungendo 100 al risultato: ciò significa che il limite superiore dovrebbe essere ridotto di 100. In altre parole, il codice per ottenere il nostro numero casuale di tre cifre sarà simile a questo :
int number = 100 + getRandomNumber(900);
Ma per semplificare questa procedura, il motore fornisce il
getRandomNumber(int, int)
metodo il cui primo parametro è il numero minimo da restituire. Utilizzando questo metodo, l'esempio precedente può essere riscritto come segue:
int number = getRandomNumber(100, 1000);
I numeri casuali possono essere utilizzati per ottenere un elemento dell'array casuale:
String [] names = {"Sarah", "Val", "Sergey"};
String randomName = names[getRandomNumber(names.length)]
Generazione di determinati eventi con una certa probabilità. Per gli umani, le mattine iniziano con alcuni possibili scenari: Dormito troppo – 50% di possibilità; Svegliato in orario – 40% di possibilità; Mi sono svegliato un'ora prima: 10% di possibilità. Immagina di scrivere un generatore di risultati mattutini. Devi generare eventi con una certa probabilità. Per fare ciò, devi nuovamente utilizzare un generatore di numeri casuali. Sono possibili diverse implementazioni, ma la più semplice dovrebbe basarsi sul seguente algoritmo:
- impostare i limiti utilizzati per generare un numero;
- generare un numero casuale;
- elaborare il numero ottenuto.
In questo caso, il massimo sarà 10. Chiama il
getRandomNumber(10)
metodo e analizzare che possiamo tornare. Può restituire 10 numeri (da 0 a 9), ciascuno con la stessa probabilità: 10%. Ora dobbiamo combinare tutti i possibili risultati e mapparli ai nostri possibili eventi. La tua immaginazione potrebbe pensare a molte combinazioni possibili, ma ecco la più ovvia: "Se il numero casuale è nell'intervallo [0..4], abbiamo l'evento "Overslept"; se il numero è nell'intervallo [5 ..8], abbiamo l'evento "Svegliato in orario" e se il numero è 9, allora abbiamo l'evento "Svegliato un'ora prima". È tutto molto semplice. Ci sono 5 numeri nell'intervallo [0 ..4], ognuno dei quali può essere restituito con una probabilità del 10%, per un totale del 50%; ci sono 4 numeri nell'intervallo [5..8], beh, e 9 è solo un numero che appare con una probabilità del 10%.
int randomNumber = getRandomNumber(10);
if (randomNumber < 5) {
System.out.println("Overslept");
} else if (randomNumber < 9) {
System.out.println("Woke up on time");
} else {
System.out.println("Woke up an hour early");
}
In generale, ci sono tantissimi modi per usare i numeri casuali. Sei limitato solo dalla tua immaginazione. Ma sono utilizzati in modo più efficace se è necessario ottenere ripetutamente qualche risultato. Quindi il nuovo risultato sarà diverso dal precedente. Con una certa probabilità, ovviamente. È tutto per ora! Se vuoi saperne di più sulla sezione "Giochi", ecco una documentazione utile che può aiutarti: