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.
Um 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>();
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:
- ArrayList-Klasse
- Funktionierende ArrayList in Bildern
- 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
int
sieht 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.
setCellValue
Sie 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
Game
definiert eine Methode
getRandomNumber(int)
. Unter der Haube nutzt es eine Klasse
Random
aus 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:
- wir legen die Grenzen fest, innerhalb derer die Zahl generiert werden muss;
- eine Zufallszahl generieren;
- 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:
GO TO FULL VERSION