JavaRush /Java Blog /Random-IT /Sezione "Giochi" su JavaRush: teoria utile

Sezione "Giochi" su JavaRush: teoria utile

Pubblicato nel gruppo Random-IT
Nella sezione "Giochi" di JavaRush troverai progetti entusiasmanti per scrivere giochi per computer popolari. Vuoi creare la tua versione dei popolari "2048", "Sapper", "Snake" e altri giochi? È semplice. Abbiamo trasformato la scrittura del gioco in un processo passo passo. CapitoloPer metterti alla prova come sviluppatore di giochi, non devi essere un programmatore avanzato, ma è comunque richiesto un certo insieme di conoscenze Java. Qui troverai informazioni che ti saranno utili durante la scrittura di giochi .

1. Eredità

Lavorare con il motore di gioco JavaRush implica l'utilizzo dell'ereditarietà. Ma cosa succede se non sai di cosa si tratta? Da un lato, devi capire questo argomento: è studiato al livello 11 . D'altra parte, il motore è stato volutamente progettato per essere molto semplice, in modo da poter cavarsela con una conoscenza superficiale dell'ereditarietà. Quindi, cos’è l’eredità? Per dirla in modo molto semplice, l’ereditarietà è la relazione tra due classi. Uno di loro diventa il genitore e il secondo diventa il figlio (classe successore). In questo caso, la classe genitore potrebbe anche non sapere di avere classi discendenti. Quelli. non riceve alcun vantaggio particolare dalla presenza di classi eredi. Ma l’ereditarietà offre molti vantaggi a una classe discendente. E la cosa principale è che tutte le variabili e i metodi della classe genitore appaiono nella classe figlia, come se il codice della classe genitore fosse copiato nella classe figlia. Questo non è del tutto vero, ma va bene per una comprensione semplificata dell'ereditarietà. Ecco alcuni esempi per comprendere meglio l'ereditarietà. Esempio 1: l'eredità più semplice.
public class Родитель {

}
La classe Child eredita dalla classe Parent utilizzando la parola chiave extends .
public class Потомок extends Родитель {

}
Esempio 2: utilizzo delle variabili della classe genitore.
public class Родитель {

   public int age;
   public String name;
}
La classe Child può utilizzare le variabili age e name della classe Parent come se fossero dichiarate al suo interno.
public class Потомок extends Родитель {

   public void printInfo() {

     System.out.println(name+" "+age);
   }
}
Esempio 3: utilizzo dei metodi della classe genitore.
public class Родитель {

   public int age;
   public String name;

   public getName() {
      return name;
   }
}
La classe Child può utilizzare le variabili e i metodi della classe Parent come se fossero dichiarati al suo interno. In questo esempio stiamo utilizzando il metodo getName ().
public class Потомок extends Родитель {

   public void printInfo() {

     System.out.println(getName()+" "+age);
   }
}
Questo è l'aspetto della classe Descendant dal punto di vista del compilatore:
public class Потомок extends Родитель {

   public int age; //  унаследованная переменная
   public String name; //  унаследованная переменная

   public getName() { //  унаследованный метод.
      return name;
  }
   public void printInfo() {

     System.out.println(getName()+" "+age);
   }
}

2. Metodo prioritario

A volte ci sono situazioni in cui abbiamo ereditato la nostra classe Discendente da una classe Genitore molto utile, insieme a tutte le variabili e i metodi, ma alcuni metodi non funzionano esattamente come vorremmo. O per niente nel modo in cui non vogliamo. Cosa fare in questa situazione? Possiamo ignorare un metodo che non ci piace. Questo viene fatto in modo molto semplice: nella nostra classe Discendente dichiariamo semplicemente un metodo con la stessa firma (intestazione) del metodo della classe Genitore e scriviamo al suo interno il nostro codice. Esempio 1: override del metodo.
public class Родитель {

   public String name;

   public void setName (String nameNew) {
       name = nameNew;
  }

   public getName() {
      return name;
  }
}
Il metodo printInfo() stamperà la frase "Luke, No!!!"
public class Потомок extends Родитель {

   public void setName (String nameNew) {
       name = nameNew + ",No!!!";
  }

   public void printInfo() {

      setName("Luke");
      System.out.println( getName());
   }
}
Questo è l'aspetto della classe Descendant dal punto di vista del compilatore:
public Потомок extends Родитель {

   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: un po' di magia dell'ereditarietà (e dell'overriding del metodo).
public class Родитель {

   public getName() {
      return "Luke";
  }
   public void printInfo() {

     System.out.println(getName());
   }
}
public class Потомок extends Родитель {

   public getName() {
      return "I'm your father, Luke";
  }
}
In questo esempio: se un metodo printInfo(della classe Parent) non viene sovrascritto nella classe Descendant, quando questo metodo viene chiamato su un oggetto della classe Descendant, verrà chiamato il suo metodo getName()e non getName()la classe Parent.
Родитель parent = new Родитель ();
parent.printnInfo();
Questo codice visualizza la scritta "Luke" sullo schermo .
Потомок child = new Потомок ();
child.printnInfo();
Questo codice mostra la scritta "Sono tuo padre, Luke"; .
Questo è l'aspetto della classe Descendant dal punto di vista del compilatore:
public class Потомок extends Родитель {

   public getName() {
      return "I'm your father, Luke";
   }
   public void printInfo() {

     System.out.println(getName());
   }
}

3. Elenchi

Se non hai ancora incontrato Lists, ecco una rapida introduzione. Puoi trovare informazioni complete sui livelli 6-7 del corso JavaRush . Le liste hanno molto in comune con gli array:
  • può memorizzare molti dati di un certo tipo;
  • consentire di recuperare gli elementi in base al loro indice/numero;
  • gli indici degli elementi iniziano da 0.
Vantaggi degli elenchi: a differenza degli array, gli elenchi possono cambiare dimensione in modo dinamico. Immediatamente dopo la creazione, l'elenco ha una dimensione pari a 0. Man mano che aggiungi elementi all'elenco, la sua dimensione aumenta. Esempio di creazione di un elenco:
ArrayList<String> myList = new ArrayList<String>(); // создание нового списка типа ArrayList
Il valore tra parentesi angolari è il tipo di dati che l'elenco può memorizzare. Ecco alcuni metodi per lavorare con un elenco:
Codice Breve descrizione di cosa fa il codice
ArrayList<String> list = new ArrayList<String>(); Creazione di un nuovo elenco di stringhe
list.add("name"); Aggiungi un elemento alla fine dell'elenco
list.add(0, "name"); Aggiunge un elemento all'inizio dell'elenco
String name = list.get(5); Ottieni un elemento tramite il suo indice
list.set(5, "new name"); Cambia l'elemento in base al suo indice
int count = list.size(); Ottieni il numero di elementi in un elenco
list.remove(4); Rimuovere un elemento da un elenco
Puoi trovare ulteriori informazioni sugli elenchi in questi articoli:
  1. Classe ArrayList
  2. ArrayList funzionante nelle immagini
  3. Rimozione di un elemento da un ArrayList

4. Array

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 tipo di array unidimensionale standard intsi presenta così:
int [] array = {12, 32, 43, 54, 15, 36, 67, 28};
Immaginiamolo visivamente:
0 1 2 3 4 5 6 7
12 32 43 54 15 36 67 28
La riga superiore indica gli indirizzi delle celle. Cioè, per ottenere il numero 67, devi accedere all'elemento dell'array con indice 6:
int number = array[6];
Qui è tutto molto semplice. Un array bidimensionale è un array di array unidimensionali. Se è la prima volta che ne senti parlare, fermati e immaginalo nella tua testa. Un array bidimensionale assomiglia a questo:
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 accedere all'elemento della matrice in [4][2].
int number = matrix[4][2];
Se noti, le coordinate della matrice sono diverse dal classico sistema di coordinate rettangolari (sistema di coordinate cartesiane). Quando si accede a una matrice, si specifica prima y e poi x , mentre in matematica è comune specificare prima x(x, y). Potresti chiederti: “Perché non invertire la matrice nella tua immaginazione e accedere agli elementi nel solito modo attraverso (x, y)? Ciò non modificherà il contenuto della matrice.” Sì, non cambierà nulla. Ma nel mondo della programmazione è consuetudine riferirsi alle matrici nella forma “prima y, poi x”. Questo deve essere dato per scontato. Ora parliamo di proiettare la matrice sul nostro motore (classe Game). Come sai, il motore ha molti metodi che cambiano le celle del campo di gioco a determinate coordinate. Ad esempio, il setCellValue(int x, int y, String value). Imposta una determinata cella con coordinate (x, y) sul valore value. Come hai notato, questo metodo prende innanzitutto esattamente x, come nel sistema di coordinate classico. Il resto dei metodi del motore funzionano in modo simile. Quando si sviluppano giochi, sarà spesso necessario riprodurre lo stato della matrice sullo schermo. Come fare questo? Innanzitutto, in un ciclo è necessario scorrere tutti gli elementi della matrice. In secondo luogo, per ognuno di essi, chiama un metodo da visualizzare con le coordinate INVERTITE. 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 due direzioni. setCellValuePuoi passare (i, j) al metodo , ma allo stesso tempo prendere l'elemento [j][i] dalla matrice. L'inversione può sembrare un po' difficile, ma è una cosa da tenere a mente. E sempre, se sorgono problemi, vale la pena prendere un pezzo di carta con una penna, disegnare una matrice e riprodurre quali processi gli stanno accadendo.

5. Numeri casuali

Come lavorare con un generatore di numeri casuali? La classe Gamedefinisce un metodo getRandomNumber(int). Sotto il cofano, utilizza una classe Randomdal pacchetto java.util, ma ciò non cambia il principio di lavorare con un generatore di numeri casuali. getRandomNumber(int)Accetta un numero intero come argomento . Questo numero sarà il limite superiore che il generatore può restituire. Il limite inferiore è 0. Importante! Il generatore non restituirà MAI un numero limite superiore. Ad esempio, se chiamato getRandomNumber(3)in modo casuale può restituire 0, 1, 2. Come puoi vedere, non può restituire 3. Questo utilizzo di un generatore è abbastanza semplice, ma in molti casi molto efficace. Devi ottenere un numero casuale entro alcuni limiti: immagina di aver bisogno di un numero di tre cifre (100..999). Come già sai, il numero minimo restituito è 0. Quindi dovrai aggiungervi 100. Ma in questo caso devi fare attenzione a non superare il limite superiore. Per ottenere 999 come valore casuale massimo, dovresti chiamare il metodo getRandomNumber(int)con un argomento 1000. Ma ricordiamo la successiva aggiunta di 100: ciò significa che il limite superiore dovrebbe essere abbassato di 100. Cioè, il codice per ottenere un numero casuale di tre cifre sarebbe simile a questo:
int number = 100 + getRandomNumber(900);
Ma per semplificare tale procedura, il motore fornisce un metodo getRandomNumber(int, int)che accetta come primo argomento il numero minimo da restituire. Utilizzando questo metodo, l'esempio precedente può essere riscritto:
int number = getRandomNumber(100, 1000);
I numeri casuali possono essere utilizzati per ottenere un elemento di un array casuale:
String [] names = {"Andrey", "Валентин", "Сергей"};
String randomName = names[getRandomNumber(names.length)]
Innescare determinati eventi con una certa probabilità. La mattinata di una persona inizia secondo possibili scenari: dormito troppo – 50%; Alzarsi in orario – 40%; Mi sono alzato un'ora prima del previsto – 10%. Immagina di scrivere un emulatore mattutino umano. È necessario attivare eventi con una certa probabilità. Per fare ciò, ancora una volta, è necessario utilizzare un generatore di numeri casuali. Le implementazioni possono essere diverse, ma quella più semplice dovrebbe seguire il seguente algoritmo:
  1. fissiamo i limiti entro i quali dobbiamo generare il numero;
  2. generare un numero casuale;
  3. Elaboriamo il numero risultante.
Quindi, in questo caso, il limite sarà 10. Chiamiamo il metodo getRandomNumber(10)e analizziamo cosa può restituirci. Può restituire 10 cifre (da 0 a 9) e ciascuna con la stessa probabilità: 10%. Ora dobbiamo combinare tutti i possibili risultati e abbinarli ai nostri possibili eventi. Possono esserci molte combinazioni, a seconda della tua immaginazione, ma la più ovvia è: "Se un numero casuale è compreso tra [0..4] - attiva l'evento "Slept troppo", se il numero è compreso tra [5.. 8] - “Sveglia” in orario”, e solo se il numero è 9, allora “Mi sono alzato un'ora prima del previsto”. Tutto è molto semplice: all'interno di [0..4] ci sono 5 numeri, ognuno dei quali può ritornare con una probabilità del 10%, che in totale sarà del 50%; all'interno di [5..8] ci sono 4 numeri e 9 è l'unico numero che appare con una probabilità del 10%. Nel codice, tutto questo design intelligente sembra ancora più semplice:
int randomNumber = getRandomNumber(10);
if (randomNumber < 5) {
    System.out.println("Проспал ");
} else if (randomNumber < 9) {
    System.out.println("Встал вовремя ");
} else {
    System.out.println("Встал на час раньше положенного ");
}
In generale, ci possono essere molte opzioni per l'utilizzo di numeri casuali. Tutto dipende solo dalla tua immaginazione. Ma sono utilizzati in modo più efficace se è necessario ottenere risultati ripetutamente. Quindi questo risultato sarà diverso dal precedente. Con una certa probabilità, ovviamente. È tutto! Se vuoi saperne di più sulla sezione Giochi, ecco qualche documentazione utile che può aiutarti:
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION