CodeGym /Java-Blog /Random-DE /Spielebereich auf CodeGym: Nützliche Theorie
John Squirrels
Level 41
San Francisco

Spielebereich auf CodeGym: Nützliche Theorie

Veröffentlicht in der Gruppe Random-DE
Im Bereich „Spiele“ auf CodeGym finden Sie spannende Projekte, bei denen es um das Schreiben beliebter Computerspiele geht. Möchten Sie Ihre eigene Version der beliebten Spiele 2048, Minesweeper, Snake und anderer Spiele erstellen? Es ist einfach. Wir haben das Schreiben von Spielen zu einem Schritt-für-Schritt-Prozess gemacht. Abschnitt „Spiele“ auf CodeGym: Nützliche Theorie – 1Um Ihre Fähigkeiten als Spieleentwickler zu testen, müssen Sie kein fortgeschrittener Programmierer sein, es sind jedoch spezifische Java-Kenntnisse erforderlich. Hier finden Sie Informationen, die beim Schreiben von Spielen nützlich sein werden .

1. Vererbung

Bei der Arbeit mit der CodeGym-Spiel-Engine kommt die Vererbung zum Einsatz. Aber was ist, wenn Sie nicht wissen, was das ist? Einerseits müssen Sie dieses Thema verstehen: Es wird in Level 11 behandelt. Andererseits wurde die Engine speziell so konzipiert, dass sie sehr einfach ist, sodass Sie mit oberflächlichen Kenntnissen über die Vererbung davonkommen können. Was ist also Vererbung? Vereinfacht ausgedrückt handelt es sich bei der Vererbung um eine Beziehung zwischen zwei Klassen. Einer von ihnen wird zum Elternteil und der andere zum Kind (Nachkomme). Darüber hinaus weiß die übergeordnete Klasse möglicherweise nicht einmal, dass sie Nachkommen hat. Mit anderen Worten: Es hat keinen besonderen Vorteil, wenn es Nachkommen hat. Aber die Vererbung bringt einem Nachkommen viele Vorteile. Und das Wichtigste ist, dass alle Variablen und Methoden der übergeordneten Klasse in der untergeordneten Klasse so angezeigt werden, als ob der Code der übergeordneten Klasse in die untergeordnete Klasse kopiert worden wäre. Dies ist keine ganz genaue Beschreibung, reicht aber für ein vereinfachtes Verständnis der Vererbung aus. Beispiel 1: Die einfachste Vererbung.

public class Parent {

}
Die Child- Klasse erbt die Parent- Klasse mithilfe des Schlüsselworts „extends“ .

public class Child extends Parent {

}
Beispiel 2: Verwendung der Variablen der übergeordneten Klasse.

public class Parent {

   public int age;
   public String name;
}
Die Child- Klasse kann die Alters- und Namensvariablen der Parent-Klasse so verwenden , als wären sie in der Parent- Klasse deklariert worden.

public class Child extends Parent {

   public void printInfo() {

     System.out.println(name+" "+age);
   }
}
Beispiel 3: Verwendung der Methoden der übergeordneten Klasse.

public class Parent {

   public int age;
   public String name;

   public getName() {
      return name;
  }
}
Die Child- Klasse kann die Variablen und Methoden der Parent- Klasse so verwenden , als ob sie in der Child-Klasse deklariert wären. In diesem Beispiel verwenden wir die Methode getName() .

public class Child extends Parent {

   public void printInfo() {

     System.out.println(getName()+" "+age);
   }
}
So sieht die Child- Klasse für den Compiler aus:

public class Child extends Parent{

   public int age;  // Inherited variable
   public String name;  // Inherited variable

   public getName() {  // Inherited method.
      return name;
  }
   public void printInfo() {

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

2. Überschreibende Methoden

Manchmal gibt es Situationen, in denen wir unsere untergeordnete Klasse dazu bringen, eine sehr nützliche übergeordnete Klasse zusammen mit all ihren Variablen und Methoden zu erben, aber einige der Methoden funktionieren nicht ganz so, wie wir es möchten. Oder überhaupt nicht so, wie wir es wollen. Was können wir in dieser Situation tun? Wir können die Methode überschreiben, die uns nicht gefällt. Das geht ganz einfach: In unserer Child-Klasse deklarieren wir einfach eine Methode mit derselben Signatur wie die Methode in der Parent-Klasse und schreiben dann unseren eigenen Code hinein. Beispiel 1: Überschreiben einer Methode.

public class Parent {

   public String name;

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

   public getName() {
      return name;
  }
}
Die Methode printInfo() zeigt „Luke, No!!!“ an.

public class Child extends Parent{

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

   public void printInfo() {
      setName("Luke");
      System.out.println(getName());
   }
}
So sieht die Child- Klasse für den Compiler aus:

public Child extends Parent {

   public String name;  // Inherited variable

   public void setName(String nameNew)  // Overridden method instead of the inherited method {

       name = nameNew + ", No!!!";
   }
   public getName() {  // Inherited method.

      return name;
   }
   public void printInfo() {

     setName("Luke");
     System.out.println( getName());
   }
}
Beispiel 2: Etwas Vererbungsmagie (und Methodenüberschreibung).

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";
  }
}
Wenn in diesem Beispiel die printInfoMethode (aus der Parent-Klasse) in der Child-Klasse nicht überschrieben wird, wird beim Aufruf dieser Methode für ein Child-Objekt deren getName()Methode anstelle der Methode der Parent-Klasse aufgerufen getName().

Parent parent = new Parent ();
parent.printnInfo();
Dieser Code zeigt „Luke“ auf dem Bildschirm an.

Child child = new Child ();
child.printnInfo();
Dieser Code zeigt „Luke, ich bin dein Vater“ auf dem Bildschirm an.
So sieht die Child- Klasse für den Compiler aus:

public class Child extends Parent {

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

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

3. Listen

Falls Sie Listen (List) noch nicht kennengelernt haben, finden Sie hier eine kurze Übersicht. Vollständige Informationen finden Sie in den Levels 6-7 des CodeGym-Kurses . Listen haben viel mit Arrays gemeinsam:
  • Sie können viele Daten eines bestimmten Typs speichern.
  • Sie ermöglichen es Ihnen, Elemente anhand ihres Index abzurufen.
  • Elementindizes beginnen bei 0.
Vorteile von Listen: Im Gegensatz zu Arrays können Listen ihre Größe dynamisch ändern. Wenn eine Liste erstellt wird, beträgt ihre Größe 0. Wenn Sie Elemente zu einer Liste hinzufügen, erhöht sich ihre Größe. Hier ist ein Beispiel für die Erstellung einer Liste:

ArrayList<String> myList = new ArrayList<String>(); // Create a new ArrayList
Der Wert in den spitzen Klammern gibt den Datentyp an, den die Liste speichern kann. Hier sind einige Methoden zum Arbeiten mit der Liste:
Code Kurze Beschreibung der Funktion des Codes
ArrayList<String> list = new ArrayList<String>(); Erstellen Sie eine neue Liste mit 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"); Ändern Sie ein Element anhand seines Index
int count = list.size(); Ermitteln Sie die Anzahl der Elemente in der Liste
list.remove(4); Löschen Sie ein Element aus der Liste
Weitere Informationen zu Listen finden Sie in den folgenden Artikeln:
  1. ArrayList-Klasse
  2. ArrayList in Bildern
  3. Löschen 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äßiges eindimensionales intArray sieht folgendermaßen aus:

int [] array = {12, 32, 43, 54, 15, 36, 67, 28};
Wir können es uns so vorstellen:
0 1 2 3 4 5 6 7
12 32 43 54 15 36 67 28
Die obere Zeile gibt die Adressen der Zellen an. Mit anderen Worten: Um die Zahl 67 zu erhalten, müssen Sie auf das Array-Element mit Index 6 zugreifen:

int number = array[6];
Es ist alles sehr 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 in Ihrem Kopf vor. Ein zweidimensionales Array sieht 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
In 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 bei [4][2] verweisen.

int number = matrix[4][2];
Möglicherweise ist Ihnen aufgefallen, dass sich die Matrixkoordinaten vom klassischen rechteckigen Koordinatensystem (kartesisches Koordinatensystem) unterscheiden. Wenn Sie auf die Matrix zugreifen, geben Sie zunächst die y-Koordinate und dann die x-Koordinate an. In der Mathematik ist es üblich, zuerst die x-Koordinate anzugeben, also (x, y). Sie fragen sich vielleicht: „Warum drehen Sie dann nicht Ihre Darstellung der Matrix und greifen dann auf die übliche Weise mit (x, y) auf die Elemente zu? Dadurch würde sich der Inhalt der Matrix nicht ändern.“ Ja, es würde sich nichts ändern. Aber in der Programmierwelt ist es üblich, auf Matrizen „zuerst nach y, dann nach x“ zuzugreifen. Sie sollten dies als den richtigen Weg akzeptieren. Lassen Sie uns nun über die Projektion der Matrix auf unsere Engine sprechen (GameKlasse). 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)Methode. Es legt eine bestimmte Zelle mit Koordinaten (x, y) fest, die dem Wertparameter entsprechen. Sie haben vielleicht bemerkt, dass diese Methode zuerst x benötigt, genau wie im klassischen Koordinatensystem. Die anderen Methoden der Engine funktionieren auf ähnliche Weise. Bei der Entwicklung von Spielen wird es häufig notwendig sein, den Zustand einer Matrix auf dem Bildschirm nachzubilden. Wie machen wir das? Zunächst müssen Sie alle Matrixelemente in einer Schleife durchlaufen. Zweitens rufen Sie die Anzeigemethode für jeden von ihnen auf, indem Sie REVERSED-Koordinaten verwenden. Zum 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 Umkehrung funktioniert natürlich in beide Richtungen. Sie können (i, j) an die setCellValueMethode übergeben und gleichzeitig das Element [j][i] aus der Matrix übernehmen. Das Umkehren der Koordinaten mag etwas schwierig erscheinen, aber Sie müssen es sich merken. Und immer, wenn Sie auf Probleme stoßen, sollten Sie sich ein Blatt Papier und einen Stift schnappen, die Matrix zeichnen und die Vorgänge mit der Matrix nachbilden.

5. Zufallszahlen

Wie arbeitet man mit einem Zufallszahlengenerator? Die GameKlasse definiert die getRandomNumber(int)Methode. Unter der Haube wird die Klasse aus dem Paket java.util verwendet Random, die Art und Weise, wie Sie mit dem Zufallszahlengenerator arbeiten, ändert sich jedoch nicht. getRandomNumber(int)akzeptiert eine ganze Zahl als Argument. Diese Zahl stellt die Obergrenze dafür dar, was der Generator zurückgeben kann. Die Untergrenze liegt bei 0. Wichtig! Der Generator gibt NIEMALS den oberen Grenzwert zurück. Wenn Sie beispielsweise aufrufen getRandomNumber(3), gibt er zufällig 0, 1 oder 2 zurück. Wie Sie sehen, kann er nicht 3 zurückgeben. Die Verwendung des Generators auf diese Weise ist recht einfach, aber in vielen Fällen sehr effektiv. Angenommen, Sie benötigen eine Zufallszahl in einem bestimmten Bereich: Stellen Sie sich vor, Sie benötigen eine dreistellige Zahl im Bereich [100..999]. Wie Sie bereits wissen, beträgt 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, rufen Sie aufgetRandomNumber(int)Methode mit dem Argument 1000. Aber jetzt erinnern wir uns daran, dass wir 100 zum Ergebnis addieren: Das bedeutet, dass die Obergrenze um 100 reduziert werden sollte. Mit anderen Worten, der Code zum Erhalten unserer zufälligen dreistelligen Zahl sieht so aus :

int number = 100 + getRandomNumber(900);
Um dieses Verfahren zu vereinfachen, stellt die Engine jedoch die getRandomNumber(int, int)Methode bereit, deren erster Parameter die minimal zurückzugebende Anzahl ist. Mit dieser Methode kann das vorherige Beispiel wie folgt umgeschrieben werden:

int number = getRandomNumber(100, 1000);
Zufallszahlen können verwendet werden, um ein zufälliges Array-Element zu erhalten:

String [] names = {"Sarah", "Val", "Sergey"};
String randomName = names[getRandomNumber(names.length)]
Bestimmte Ereignisse mit einer gewissen Wahrscheinlichkeit generieren. Für Menschen beginnt der Morgen mit einigen möglichen Szenarien: Verschlafen – 50 % Wahrscheinlichkeit; Pünktlich aufgewacht – 40 % Chance; Eine Stunde früher aufgestanden – 10 % Chance. Stellen Sie sich vor, Sie schreiben einen Morgenergebnisgenerator. Sie müssen Ereignisse mit einer bestimmten Wahrscheinlichkeit generieren. Dazu müssen Sie wiederum einen Zufallszahlengenerator verwenden. Verschiedene Implementierungen sind möglich, die einfachste sollte jedoch auf dem folgenden Algorithmus basieren:
  1. Legen Sie die Grenzwerte fest, die zum Generieren einer Zahl verwendet werden.
  2. eine Zufallszahl generieren;
  3. Verarbeiten Sie die erhaltene Nummer.
In diesem Fall beträgt das Maximum 10. Rufen Sie angetRandomNumber(10)Methode und analysieren, dass wir es zurückgeben können. Es können 10 Zahlen (von 0 bis 9) zurückgegeben werden, jede mit der gleichen Wahrscheinlichkeit – 10 %. Jetzt müssen wir alle möglichen Ergebnisse kombinieren und sie unseren möglichen Ereignissen zuordnen. Ihre Fantasie kann sich viele mögliche Kombinationen ausdenken, aber hier ist die offensichtlichste: „Wenn die Zufallszahl im Bereich [0..4] liegt, liegt das Ereignis „Verschlafen“ vor; liegt die Zahl im Bereich [5 ..8], wir haben das Ereignis „Pünktlich aufgewacht“; und wenn die Zahl 9 ist, dann haben wir das Ereignis „Eine Stunde früher aufgestanden“. Es ist alles sehr einfach. Es gibt 5 Zahlen im Bereich [0 ..4], von denen jede mit einer Wahrscheinlichkeit von 10 % zurückgegeben werden kann, also insgesamt 50 %; es gibt 4 Zahlen im Bereich [5..8], und 9 ist nur eine Zahl, die mit erscheint eine Wahrscheinlichkeit von 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");
}
Im Allgemeinen gibt es unzählige Möglichkeiten, Zufallszahlen zu verwenden. Sie sind nur durch Ihre Vorstellungskraft begrenzt. Sie werden jedoch am effektivsten eingesetzt, wenn Sie wiederholt ein Ergebnis erzielen müssen. Dann unterscheidet sich das neue Ergebnis vom vorherigen. Natürlich mit einiger Wahrscheinlichkeit. Das ist alles für jetzt! 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