JavaRush /Java-Blog /Random-DE /Abschnitt „Spiele“ auf JavaRush: Nützliche Theorie

Abschnitt „Spiele“ auf JavaRush: Nützliche Theorie

Veröffentlicht in der Gruppe Random-DE
Im Bereich „Spiele“ von JavaRush finden Sie spannende Projekte zum Schreiben beliebter Computerspiele. Möchten Sie Ihre eigene Version der beliebten Spiele „2048“, „Sapper“, „Snake“ und anderer Spiele erstellen? Das ist einfach. Wir haben das Schreiben von Spielen zu einem Schritt-für-Schritt-Prozess gemacht. KapitelUm sich als Spieleentwickler zu versuchen, muss man kein fortgeschrittener Programmierer sein, es sind aber dennoch gewisse Java-Kenntnisse erforderlich. Hier finden Sie Informationen, die Ihnen beim Schreiben von Spielen nützlich sein werden .

1. Vererbung

Die Arbeit mit der JavaRush-Spiel-Engine erfordert die Verwendung von Vererbung. Aber was ist, wenn Sie nicht wissen, was es ist? Einerseits müssen Sie dieses Thema verstehen: Es wird auf Niveau 11 studiert . Andererseits wurde die Engine bewusst sehr einfach konzipiert, sodass man mit oberflächlichen Kenntnissen über Vererbung auskommt. Was ist also Vererbung? Vereinfacht ausgedrückt ist Vererbung die Beziehung zwischen zwei Klassen. Einer von ihnen wird zum Elternteil und der zweite zum Kind (Nachfolgerklasse). In diesem Fall weiß die übergeordnete Klasse möglicherweise nicht einmal, dass sie Nachkommenklassen hat. Diese. Es hat keinen besonderen Nutzen aus der Anwesenheit von Erbklassen. Aber die Vererbung bietet einer Nachkommenklasse viele Vorteile. Und der wichtigste ist, dass alle Variablen und Methoden der übergeordneten Klasse in der untergeordneten Klasse angezeigt werden, als ob der Code der übergeordneten Klasse in die untergeordnete Klasse kopiert worden wäre. Das ist nicht ganz richtig, aber für ein vereinfachtes Verständnis der Vererbung reicht es aus. Hier sind einige Beispiele, um die Vererbung besser zu verstehen. Beispiel 1: die einfachste Vererbung.
public class Родитель {

}
Die Child- Klasse erbt von der Parent- Klasse mithilfe des Schlüsselworts „extends“ .
public class Потомок extends Родитель {

}
Beispiel 2: Verwendung von Variablen der übergeordneten Klasse.
public class Родитель {

   public int age;
   public String name;
}
Die Child- Klasse kann die Alters- und Namensvariablen der Parent- Klasse verwenden , als ob sie in dieser deklariert wären.
public class Потомок extends Родитель {

   public void printInfo() {

     System.out.println(name+" "+age);
   }
}
Beispiel 3: Verwendung von Methoden der übergeordneten Klasse.
public class Родитель {

   public int age;
   public String name;

   public getName() {
      return name;
   }
}
Die Child- Klasse kann die Variablen und Methoden der Parent- Klasse verwenden , als ob sie in dieser deklariert wären. In diesem Beispiel verwenden wir die Methode getName ().
public class Потомок extends Родитель {

   public void printInfo() {

     System.out.println(getName()+" "+age);
   }
}
So sieht die Descendant- Klasse aus Sicht des Compilers aus:
public class Потомок extends Родитель {

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

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

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

2. Methodenüberschreibung

Manchmal gibt es Situationen, in denen wir unsere Descendant-Klasse von einer sehr nützlichen Parent-Klasse geerbt haben, zusammen mit allen Variablen und Methoden, aber einige Methoden funktionieren nicht genau so, wie wir es wollen. Oder gar nicht so, wie wir es nicht wollen. Was tun in dieser Situation? Wir können eine Methode überschreiben, die uns nicht gefällt. Das geht ganz einfach: In unserer Descendant-Klasse deklarieren wir einfach eine Methode mit derselben Signatur (Header) wie die Methode der Parent-Klasse und schreiben unseren Code hinein. Beispiel 1: Methodenüberschreibung.
public class Родитель {

   public String name;

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

   public getName() {
      return name;
  }
}
Die printInfo()-Methode gibt den Satz „Luke, No!!!“ aus.
public class Потомок extends Родитель {

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

   public void printInfo() {

      setName("Luke");
      System.out.println( getName());
   }
}
So sieht die Descendant- Klasse aus Sicht des Compilers aus:
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());
   }
}
Beispiel 2: ein wenig Magie der Vererbung (und des Überschreibens von Methoden).
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 diesem Beispiel: Wenn eine Methode printInfo(aus der Parent-Klasse) in der Descendant-Klasse nicht überschrieben wird und diese Methode für ein Objekt der Descendant-Klasse aufgerufen wird, wird ihre Methode aufgerufen getName()und nicht getName()die Parent-Klasse.
Родитель parent = new Родитель ();
parent.printnInfo();
Dieser Code zeigt die Inschrift „Luke“ auf dem Bildschirm an .
Потомок child = new Потомок ();
child.printnInfo();
Dieser Code zeigt die Aufschrift „Ich bin dein Vater, Luke“; .
So sieht die Descendant- Klasse aus Sicht des Compilers aus:
public class Потомок extends Родитель {

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

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

3. Listen

Wenn Sie Lists noch nicht kennen, finden Sie hier eine kurze Einführung. Vollständige Informationen zu den Levels 6-7 des JavaRush-Kurses finden Sie hier . Listen haben viel mit Arrays gemeinsam:
  • kann viele Daten eines bestimmten Typs speichern;
  • ermöglicht es Ihnen, Elemente anhand ihres Index/ihrer Nummer abzurufen;
  • Elementindizes beginnen bei 0.
Vorteile von Listen: Im Gegensatz zu Arrays können Listen ihre Größe dynamisch ändern. Unmittelbar nach der Erstellung hat die Liste eine Größe von 0. Wenn Sie Elemente zur Liste hinzufügen, erhöht sich ihre Größe. Beispiel für die Erstellung einer Liste:
ArrayList<String> myList = new ArrayList<String>(); // создание нового списка типа ArrayList
Der Wert in den spitzen Klammern gibt den Datentyp an, den die Liste speichern kann. Hier sind einige Methoden zum Arbeiten mit einer Liste:
Code Kurze Beschreibung der Funktionsweise des Codes
ArrayList<String> list = new ArrayList<String>(); Erstellen einer neuen Liste von Zeichenfolgen
list.add("name"); Fügen Sie am Ende der Liste ein Element hinzu
list.add(0, "name"); Fügen Sie am Anfang der Liste ein Element hinzu
String name = list.get(5); Holen Sie sich ein Element anhand seines Index
list.set(5, "new name"); Element anhand seines Index ändern
int count = list.size(); Ermitteln Sie die Anzahl der Elemente in einer Liste
list.remove(4); Entfernen Sie ein Element aus einer Liste
Weitere Informationen zu Listen finden Sie in diesen Artikeln:
  1. ArrayList-Klasse
  2. Funktionierende ArrayList in Bildern
  3. Entfernen eines Elements aus einer ArrayList

4. Arrays

Was ist eine Matrix? Eine Matrix ist nichts anderes als eine rechteckige Tabelle, die mit Daten gefüllt werden kann. Mit anderen Worten, es handelt sich um ein zweidimensionales Array. Wie Sie wahrscheinlich wissen, sind Arrays in Java Objekte. Ein standardmäßiger eindimensionaler Array-Typ intsieht folgendermaßen aus:
int [] array = {12, 32, 43, 54, 15, 36, 67, 28};
Stellen wir uns das einmal visuell vor:
0 1 2 3 4 5 6 7
12 32 43 54 15 36 67 28
Die oberste Zeile zeigt die Zelladressen an. Das heißt, um die Zahl 67 zu erhalten, müssen Sie auf das Array-Element mit Index 6 zugreifen:
int number = array[6];
Hier ist alles ganz einfach. Ein zweidimensionales Array ist ein Array aus eindimensionalen Arrays. Wenn Sie zum ersten Mal davon hören, halten Sie inne und stellen Sie es sich vor. Ein zweidimensionales Array sieht etwa so aus:
0 Eindimensionales Array Eindimensionales Array
1 Eindimensionales Array
2 Eindimensionales Array
3 Eindimensionales Array
4 Eindimensionales Array
5 Eindimensionales Array
6 Eindimensionales Array
7 Eindimensionales Array
Im Code:
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
Um den Wert 47 zu erhalten, müssen Sie auf das Matrixelement unter [4][2] zugreifen.
int number = matrix[4][2];
Wie Sie bemerken, unterscheiden sich die Matrixkoordinaten vom klassischen rechteckigen Koordinatensystem (kartesisches Koordinatensystem). Beim Zugriff auf eine Matrix geben Sie zuerst y und dann x an , während es in der Mathematik üblich ist, zuerst x(x, y) anzugeben. Sie fragen sich vielleicht: „Warum kehren Sie nicht die Matrix in Ihrer Vorstellung um und greifen auf die übliche Weise über (x, y) auf die Elemente zu?“ Der Inhalt der Matrix wird dadurch nicht verändert.“ Ja, es wird sich nichts ändern. In der Programmierwelt ist es jedoch üblich, Matrizen in der Form „zuerst y, dann x“ zu bezeichnen. Dies muss als selbstverständlich angesehen werden. Lassen Sie uns nun über die Projektion der Matrix auf unsere Engine (Klasse Game) sprechen. Wie Sie wissen, verfügt die Engine über viele Methoden, die die Zellen des Spielfelds an bestimmten Koordinaten ändern. Zum Beispiel die setCellValue(int x, int y, String value). Es setzt eine bestimmte Zelle mit den Koordinaten (x, y) auf den Wert value. Wie Sie bemerkt haben, nimmt diese Methode zunächst genau x an, wie im klassischen Koordinatensystem. Die übrigen Engine-Methoden funktionieren auf ähnliche Weise. Bei der Entwicklung von Spielen besteht häufig die Notwendigkeit, den Zustand der Matrix auf dem Bildschirm darzustellen. Wie macht man das? Zunächst müssen Sie in einer Schleife alle Elemente der Matrix durchlaufen. Zweitens rufen Sie für jeden von ihnen eine Methode zur Anzeige mit INVERTED-Koordinaten auf. Beispiel:
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]));
        }
    }
}
Die Inversion funktioniert natürlich in zwei Richtungen. setCellValueSie können (i, j) an die Methode übergeben, aber gleichzeitig das Element [j][i] aus der Matrix übernehmen. Die Umkehrung mag etwas schwierig erscheinen, aber man sollte sie im Hinterkopf behalten. Und immer, wenn Probleme auftreten, lohnt es sich, ein Blatt Papier mit einem Stift zu nehmen, eine Matrix zu zeichnen und zu reproduzieren, welche Prozesse damit passieren.

5. Zufallszahlen

Wie arbeite ich mit einem Zufallszahlengenerator? Die Klasse Gamedefiniert eine Methode getRandomNumber(int). Unter der Haube nutzt es eine Klasse Randomaus dem Paket java.util, was jedoch nichts am Prinzip der Arbeit mit einem Zufallszahlengenerator ändert. getRandomNumber(int)Akzeptiert eine ganze Zahl als Argument . Diese Zahl stellt die Obergrenze dar, die der Generator zurückgeben kann. Die Untergrenze liegt bei 0. Wichtig! Der Generator gibt NIEMALS eine Zahl mit Obergrenze zurück. Wenn es beispielsweise getRandomNumber(3)zufällig aufgerufen wird, kann es 0, 1, 2 zurückgeben. Wie Sie sehen, kann es nicht 3 zurückgeben. Dieser Einsatz eines Generators ist recht einfach, aber in vielen Fällen sehr effektiv. Sie müssen innerhalb bestimmter Grenzen eine Zufallszahl erhalten: Stellen Sie sich vor, Sie benötigen eine dreistellige Zahl (100..999). Wie Sie bereits wissen, ist die zurückgegebene Mindestanzahl 0. Sie müssen also 100 hinzufügen. In diesem Fall müssen Sie jedoch darauf achten, die Obergrenze nicht zu überschreiten. Um 999 als maximalen Zufallswert zu erhalten, sollten Sie die Methode getRandomNumber(int)mit einem Argument von 1000 aufrufen. Aber wir erinnern uns an die anschließende Addition von 100: Dies bedeutet, dass die Obergrenze um 100 gesenkt werden sollte. Das heißt, der Code, um a zu erhalten Eine zufällige dreistellige Zahl würde so aussehen:
int number = 100 + getRandomNumber(900);
Um ein solches Verfahren zu vereinfachen, stellt die Engine jedoch eine Methode bereit getRandomNumber(int, int), die als erstes Argument die minimal zurückzugebende Anzahl verwendet. Mit dieser Methode kann das vorherige Beispiel umgeschrieben werden:
int number = getRandomNumber(100, 1000);
Zufallszahlen können verwendet werden, um ein zufälliges Array-Element zu erhalten:
String [] names = {„Andrei“, "Валентин", "Сергей"};
String randomName = names[getRandomNumber(names.length)]
Bestimmte Ereignisse mit einer bestimmten Wahrscheinlichkeit auslösen. Der Morgen einer Person beginnt entsprechend möglicher Szenarien: Verschlafen – 50 %; Pünktlich aufgestanden – 40 %; Bin eine Stunde früher aufgestanden als erwartet – 10 %. Stellen Sie sich vor, Sie schreiben einen menschlichen Morgenemulator. Sie müssen Ereignisse mit einer bestimmten Wahrscheinlichkeit auslösen. Auch hierfür müssen Sie einen Zufallszahlengenerator verwenden. Die Implementierungen können unterschiedlich sein, die einfachste sollte jedoch dem folgenden Algorithmus folgen:
  1. wir legen die Grenzen fest, innerhalb derer die Zahl generiert werden muss;
  2. eine Zufallszahl generieren;
  3. Wir verarbeiten die resultierende Zahl.
In diesem Fall liegt der Grenzwert also bei 10. Rufen wir die Methode auf getRandomNumber(10)und analysieren, was sie uns zurückgeben kann. Es kann 10 Ziffern (von 0 bis 9) und jede mit der gleichen Wahrscheinlichkeit zurückgeben – 10 %. Jetzt müssen wir alle möglichen Ergebnisse kombinieren und sie mit unseren möglichen Ereignissen abgleichen. Abhängig von Ihrer Vorstellungskraft kann es viele Kombinationen geben, aber die offensichtlichsten klingen: „Wenn eine Zufallszahl innerhalb von [0..4] liegt – nennen Sie das Ereignis „Verschlafen“, wenn die Zahl innerhalb von [5..8] liegt ] – „Pünktlich aufstehen“ und nur wenn die Zahl 9 ist, dann „Ich bin eine Stunde früher aufgestanden als erwartet.“ Alles ist ganz einfach: Innerhalb von [0..4] gibt es 5 Zahlen, von denen jede mit einer Wahrscheinlichkeit von 10 % zurückgegeben werden kann, was insgesamt 50 % entspricht; Innerhalb von [5..8] gibt es 4 Zahlen, und 9 ist die einzige Zahl, die mit einer Wahrscheinlichkeit von 10 % erscheint. Im Code sieht dieses ganze clevere Design noch einfacher aus:
int randomNumber = getRandomNumber(10);
if (randomNumber < 5) {
    System.out.println("Проспал ");
} else if (randomNumber < 9) {
    System.out.println("Встал вовремя ");
} else {
    System.out.println("Встал на час раньше положенного ");
}
Generell gibt es viele Möglichkeiten, Zufallszahlen zu verwenden. Es hängt alles nur von Ihrer Vorstellungskraft ab. Sie werden jedoch am effektivsten eingesetzt, wenn Sie wiederholt ein Ergebnis erzielen müssen. Dann unterscheidet sich dieses Ergebnis vom vorherigen. Natürlich mit einiger Wahrscheinlichkeit. Das ist alles! Wenn Sie mehr über den Abschnitt „Spiele“ erfahren möchten, finden Sie hier einige nützliche Dokumentationen, die Ihnen helfen können:
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION