So schreiben Sie Ihr erstes Android-Spiel in Java

Autor: John Stephens
Erstelldatum: 1 Januar 2021
Aktualisierungsdatum: 19 Kann 2024
Anonim
Grundgerüst | Spiel programmieren | Java | #01 [ger/1080p]
Video: Grundgerüst | Spiel programmieren | Java | #01 [ger/1080p]

Inhalt


Es gibt viele Möglichkeiten, ein Spiel für Android zu erstellen. Eine wichtige Möglichkeit besteht darin, es in Android Studio mit Java von Grund auf neu zu erstellen. Dies gibt Ihnen die maximale Kontrolle darüber, wie Ihr Spiel aussehen und sich verhalten soll, und der Prozess vermittelt Ihnen Fähigkeiten, die Sie auch in einer Reihe anderer Szenarien einsetzen können - unabhängig davon, ob Sie einen Begrüßungsbildschirm für eine App erstellen oder nur möchten Fügen Sie einige Animationen hinzu. In diesem Tutorial erfahren Sie, wie Sie mit Android Studio und Java ein einfaches 2D-Spiel erstellen. Sie können den gesamten Code und die Ressourcen bei Github finden, wenn Sie mitmachen möchten.

Einrichten

Um unser Spiel zu erstellen, müssen wir uns mit einigen spezifischen Konzepten befassen: Spielschleifen, Threads und Leinwände. Starten Sie zunächst Android Studio. Wenn Sie es nicht installiert haben, lesen Sie unsere vollständige Einführung in Android Studio, die den Installationsprozess durchläuft. Starten Sie nun ein neues Projekt und stellen Sie sicher, dass Sie die Vorlage "Leere Aktivität" auswählen. Dies ist ein Spiel, daher brauchen Sie natürlich keine Elemente wie die FAB-Taste, die die Sache komplizieren.


Das erste, was Sie tun möchten, ist zu ändern AppCompatActivity zu Aktivität. Dies bedeutet, dass wir die Funktionen der Aktionsleiste nicht verwenden.

In ähnlicher Weise möchten wir unser Spiel auch als Vollbild anzeigen. Fügen Sie onCreate () vor dem Aufruf von setContentView () den folgenden Code hinzu:

getWindow (). setFlags (WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); this.requestWindowFeature (Window.FEATURE_NO_TITLE);

Beachten Sie, dass Sie möglicherweise eine Klasse importieren müssen, wenn Sie Code schreiben, der rot unterstrichen ist. Mit anderen Worten, Sie müssen Android Studio mitteilen, dass Sie bestimmte Anweisungen verwenden und verfügbar machen möchten. Wenn Sie einfach irgendwo auf das unterstrichene Wort klicken und dann Alt + Enter drücken, wird das automatisch für Sie erledigt!


Erstellen Sie Ihre Spielansicht

Sie können an Apps gewöhnt sein, die ein XML-Skript verwenden, um das Layout von Ansichten wie Schaltflächen, Bildern und Beschriftungen zu definieren. Das ist was die Linie setContentView tut für uns.

Aber auch dies ist ein Spiel, für das weder Browserfenster noch scrollende Recycler-Ansichten erforderlich sind. Stattdessen möchten wir stattdessen eine Leinwand anzeigen. In Android Studio ist eine Leinwand genauso wie in der Kunst: Sie ist ein Medium, auf das wir zeichnen können.

Ändern Sie diese Zeile so, dass sie so lautet:

setContentView (neues GameView (dies))

Sie werden feststellen, dass dies erneut rot unterstrichen ist. Aber jetzt Wenn Sie Alt + Eingabetaste drücken, können Sie die Klasse nicht importieren. Stattdessen haben Sie die Möglichkeit, erstellen eine Klasse. Mit anderen Worten, wir sind dabei, eine eigene Klasse zu erstellen, die definiert, was auf der Leinwand passieren wird. Auf diese Weise können wir auf den Bildschirm zeichnen, anstatt nur vorgefertigte Ansichten anzuzeigen.

Klicken Sie also mit der rechten Maustaste auf den Paketnamen in Ihrer Hierarchie und wählen Sie Neu> Klasse. Nun wird ein Fenster zum Erstellen Ihrer Klasse angezeigt, das Sie aufrufen werden GameView. Schreiben Sie unter SuperClass: android.view.SurfaceView Dies bedeutet, dass die Klasse Methoden - ihre Funktionen - von SurfaceView erbt.

In das Feld Schnittstelle (n) schreiben Sie android.view.SurfaceHolder.Callback. Wie bei jeder Klasse müssen wir jetzt unseren Konstruktor erstellen. Verwenden Sie diesen Code:

privater MainThread-Thread; public GameView (Kontext-Kontext) {super (Kontext); getHolder (). addCallback (this); }

Jedes Mal, wenn unsere Klasse aufgerufen wird, um ein neues Objekt (in diesem Fall unsere Oberfläche) zu erstellen, wird der Konstruktor ausgeführt und eine neue Oberfläche erstellt. Die Zeile "super" ruft die Superklasse auf und in unserem Fall ist dies die SurfaceView.

Durch Hinzufügen von Callback können wir Ereignisse abfangen.

Überschreiben Sie nun einige Methoden:

@Override public void surfaceChanged (SurfaceHolder-Halter, int-Format, int-Breite, int-Höhe) {} @Override public void surfaceCreated (SurfaceHolder-Halter) {} @Override public void surfaceDestroyed (SurfaceHolder-Halter) {}

Diese ermöglichen es uns im Grunde, Methoden in der Oberklasse (SurfaceView) zu überschreiben (daher der Name). Sie sollten jetzt keine roten Unterstreichungen mehr in Ihrem Code haben. Nett.

Sie haben gerade eine neue Klasse erstellt und jedes Mal, wenn wir uns darauf beziehen, wird die Zeichenfläche für Ihr Spiel erstellt, auf die Sie malen können. Klassen erstellen Objekte und wir brauchen noch einen.

Themen erstellen

Unsere neue Klasse wird heißen Haupt-Bedroung. Und seine Aufgabe wird es sein, einen Thread zu erstellen. Ein Thread ist im Wesentlichen wie eine parallele Code-Abzweigung, die gleichzeitig neben dem ausgeführt werden kann Main Teil Ihres Codes. Es können viele Threads gleichzeitig ausgeführt werden, sodass Dinge gleichzeitig stattfinden können, anstatt sich an eine strikte Reihenfolge zu halten. Dies ist wichtig für ein Spiel, da wir sicherstellen müssen, dass es reibungslos weiterläuft, auch wenn viel los ist.

Erstellen Sie Ihre neue Klasse wie zuvor und diesmal wird sie erweitert Faden. Im Konstruktor rufen wir einfach auf Super(). Denken Sie daran, das ist die Superklasse, die Thread ist und die das ganze schwere Heben für uns erledigen kann. Dies ist wie das Erstellen eines Programms zum Waschen des gerade aufgerufenen Geschirrs Waschmaschine().

Wenn diese Klasse aufgerufen wird, wird ein separater Thread erstellt, der als Ableger der Hauptsache ausgeführt wird. Und es ist von Hier dass wir unser GameView erstellen wollen. Das bedeutet, dass wir auch auf die GameView-Klasse verweisen müssen und auch SurfaceHolder verwenden, das die Zeichenfläche enthält. Wenn die Leinwand die Oberfläche ist, ist SurfaceHolder die Staffelei. Und GameView ist das, was alles zusammenbringt.

Das Ganze sollte so aussehen:

public class MainThread erweitert Thread {private SurfaceHolder surfaceHolder; privates GameView gameView; public MainThread (SurfaceHolder surfaceHolder, GameView gameView) {super (); this.surfaceHolder = surfaceHolder; this.gameView = gameView; }}

Schweet. Wir haben jetzt ein GameView und einen Thread!

Erstellen der Spieleschleife

Wir haben jetzt die Rohstoffe, die wir brauchen, um unser Spiel zu machen, aber es passiert nichts. Hier kommt die Spieleschleife ins Spiel. Grundsätzlich handelt es sich um eine Codeschleife, die sich ständig dreht und Eingaben und Variablen überprüft, bevor der Bildschirm gezeichnet wird. Unser Ziel ist es, dies so konsistent wie möglich zu gestalten, damit es in der Framerate zu keinen Stottern oder Schluckauf kommt, die ich später untersuchen werde.

Im Moment sind wir noch in der Haupt-Bedroung Klasse und wir werden eine Methode aus der Oberklasse überschreiben. Dieser ist Lauf.

Und es geht ein bisschen so:

@Override public void run () {while (läuft) {canvas = null; try {canvas = this.surfaceHolder.lockCanvas (); synchronized (surfaceHolder) {this.gameView.update (); this.gameView.draw (canvas); }} catch (Ausnahme e) {} finally {if (canvas! = null) {try {surfaceHolder.unlockCanvasAndPost (canvas); } catch (Ausnahme e) {e.printStackTrace (); }}}}}

Sie werden eine Menge Unterstreichungen sehen, daher müssen wir einige weitere Variablen und Referenzen hinzufügen. Gehe zurück nach oben und füge hinzu:

private SurfaceHolder surfaceHolder; privates GameView gameView; privates Boolesches Laufen; öffentliche statische Leinwand Leinwand;

Denken Sie daran, Canvas zu importieren. Leinwand ist das, worauf wir tatsächlich zeichnen werden. Was 'lockCanvas' betrifft, ist dies wichtig, da dies im Wesentlichen die Leinwand einfriert, damit wir darauf zeichnen können. Dies ist wichtig, da ansonsten möglicherweise mehrere Threads gleichzeitig versuchen, darauf zu zeichnen. Nur wissen, dass Sie zuerst die Zeichenfläche bearbeiten müssen, um sie zu bearbeiten sperren die Leinwand.

Update ist eine Methode, die wir entwickeln werden, und hier werden die lustigen Dinge später passieren.

Das Versuchen und Fang In der Zwischenzeit gibt es lediglich Java-Anforderungen, die zeigen, dass wir bereit sind, Ausnahmen (Fehler) zu behandeln, die auftreten können, wenn die Zeichenfläche nicht bereit ist usw.

Schließlich möchten wir in der Lage sein, unseren Thread zu starten, wenn wir ihn brauchen. Dazu benötigen wir hier eine andere Methode, mit der wir Dinge in Bewegung setzen können. Das ist was zum Laufen Variable ist für (beachten Sie, dass ein Boolescher Wert ein Variablentyp ist, der immer nur wahr oder falsch ist). Fügen Sie diese Methode der hinzu Haupt-Bedroung Klasse:

public void setRunning (boolescher Wert isRunning) {running = isRunning; }

An dieser Stelle sollte jedoch noch eines hervorgehoben werden: aktualisieren. Dies liegt daran, dass wir die Aktualisierungsmethode noch nicht erstellt haben. Also komm wieder rein GameView und jetzt Methode hinzufügen.

public void update () {}

Wir müssen auch Start der Faden! Wir werden dies in unserem tun surfaceCreated Methode:

@Override public void surfaceCreated (SurfaceHolder-Halter) {thread.setRunning (true); thread.start (); }

Wir müssen auch den Faden stoppen, wenn die Oberfläche zerstört ist. Wie Sie vielleicht erraten haben, behandeln wir dies in der oberflächenzerstört Methode. Da es jedoch mehrere Versuche erfordern kann, einen Thread anzuhalten, werden wir dies in eine Schleife einfügen und verwenden Versuchen und Fang nochmal. Wie so:

@Override public void surfaceDestroyed (SurfaceHolder-Halter) {boolean retry = true; while (erneut versuchen) {try {thread.setRunning (false); thread.join (); } catch (InterruptedException e) {e.printStackTrace (); } retry = false; }}

Und schließlich gehen Sie zum Konstruktor und stellen Sie sicher, dass Sie die neue Instanz Ihres Threads erstellen, da sonst die gefürchtete Nullzeiger-Ausnahme angezeigt wird! Und dann werden wir GameView fokussierbar machen, was bedeutet, dass es Ereignisse verarbeiten kann.

thread = new MainThread (getHolder (), this); setFocusable (true);

Jetzt kannst du endlich Tatsächlich teste dieses Ding! Das ist richtig, klicken Sie auf "Ausführen" und dann auf "OK" sollte eigentlich ohne fehler laufen. Bereiten Sie sich darauf vor, umgehauen zu werden!

Es ist ... es ist ... ein leerer Bildschirm! Der ganze Code. Für einen leeren Bildschirm. Aber das ist ein leerer Bildschirm von Gelegenheit. Sie haben Ihre Oberfläche mit einer Spieleschleife zum Abwickeln von Ereignissen zum Laufen gebracht. Jetzt müssen nur noch Dinge passieren. Es spielt keine Rolle, ob Sie bis zu diesem Punkt nicht alles im Tutorial befolgt haben. Der Punkt ist, dass Sie diesen Code einfach recyceln können, um großartige Spiele zu erstellen!

Eine Grafik machen

Nun haben wir einen leeren Bildschirm zum Zeichnen. Alles was wir tun müssen, ist darauf zu zeichnen. Zum Glück ist das der einfache Teil. Alles, was Sie tun müssen, ist, die Zeichenmethode in unserer zu überschreiben GameView Klasse und dann ein paar schöne Bilder hinzufügen:

@Override public void draw (Leinwand) {super.draw (Leinwand); if (canvas! = null) {canvas.drawColor (Color.WHITE); Paint paint = new Paint (); paint.setColor (Color.rgb (250, 0, 0)); canvas.drawRect (100, 100, 200, 200, paint); }}

Wenn Sie dies ausführen, sollte oben links auf einem ansonsten weißen Bildschirm ein hübsches rotes Quadrat angezeigt werden. Dies ist sicherlich eine Verbesserung.

Sie könnten theoretisch so ziemlich Ihr gesamtes Spiel erstellen, indem Sie es in diese Methode einbauen (und überschreiben) onTouchEvent Dies wäre jedoch keine besonders gute Vorgehensweise. Das Einfügen von neuem Paint in unsere Schleife verlangsamt die Arbeit erheblich, und selbst wenn wir dies an einer anderen Stelle einfügen, wird dem Code zu viel hinzugefügt zeichnen Methode würde hässlich und schwer zu folgen.

Vielmehr ist es sinnvoller, Spielobjekte mit eigenen Klassen zu behandeln. Wir beginnen mit einem, der einen Charakter zeigt, und diese Klasse wird aufgerufen CharacterSprite. Gehen Sie voran und machen Sie das.

Diese Klasse wird ein Sprite auf die Leinwand zeichnen und so aussehen

öffentliche Klasse CharacterSprite {privates Bitmap-Bild; public CharacterSprite (Bitmap bmp) {image = bmp; } public void draw (Canvas canvas) {canvas.drawBitmap (image, 100, 100, null); }}

Um dies zu verwenden, müssen Sie zuerst die Bitmap laden und dann die Klasse von aufrufen GameView. Verweis auf hinzufügen private CharacterSprite characterSprite und dann in der surfaceCreated Methode, fügen Sie die Zeile hinzu:

characterSprite = new CharacterSprite (BitmapFactory.decodeResource (getResources (), R.drawable.avdgreen));

Wie Sie sehen, ist die Bitmap, die wir laden, in Ressourcen gespeichert und heißt avdgreen (sie stammt aus einem früheren Spiel). Jetzt müssen Sie nur noch diese Bitmap an die neue Klasse in der Datei übergeben zeichnen Methode mit:

characterSprite.draw (canvas);

Klicken Sie nun auf Ausführen und Sie sollten sehen, dass Ihre Grafik auf Ihrem Bildschirm erscheint! Das ist BeeBoo. Ich habe ihn in meine Schulbücher gemalt.

Was wäre, wenn wir diesen kleinen Kerl bewegen wollten? Ganz einfach: Wir erstellen einfach x- und y-Variablen für seine Positionen und ändern diese Werte in einem aktualisieren Methode.

Fügen Sie also die Referenzen zu Ihren hinzu CharacterSprite und zeichne dann deine Bitmap auf x, y. Erstellen Sie hier die Aktualisierungsmethode. Im Moment versuchen wir Folgendes:

y ++;

Jedes Mal, wenn die Spielrunde läuft, bewegen wir den Charakter auf dem Bildschirm nach unten. Merken, y Koordinaten werden also von oben gemessen 0 ist der obere Rand des Bildschirms. Natürlich müssen wir die anrufen aktualisieren Methode in CharacterSprite von dem aktualisieren Methode in GameView.

Drücken Sie erneut die Wiedergabetaste, und Sie werden sehen, dass Ihr Bild langsam auf dem Bildschirm angezeigt wird. Wir gewinnen noch keine Spielpreise, aber es ist ein Anfang!

Okay, um Dinge zu machen leicht Interessanter ist, dass ich hier nur einen 'Bouncy Ball'-Code ablegen werde. Dadurch springt unsere Grafik wie bei den alten Windows-Bildschirmschonern über den Bildschirmrand. Weißt du, die seltsam hypnotischen.

public void update () {x + = xVelocity; y + = yVelocity; if ((x & gt; screenWidth - image.getWidth ()) || (x & lt; 0)) {xVelocity = xVelocity * -1; } if ((y & gt; screenHeight - image.getHeight ()) || (y & lt; 0)) {yVelocity = yVelocity * -1; }}

Sie müssen auch diese Variablen definieren:

private int xVelocity = 10; private int yVelocity = 5; private int screenWidth = Resources.getSystem (). getDisplayMetrics (). widthPixels; private int screenHeight = Resources.getSystem (). getDisplayMetrics (). heightPixels;

Optimierung

Es gibt viel Hier gibt es mehr zu tun, angefangen von der Eingabe durch den Player über das Skalieren von Bildern bis hin zur Verwaltung, dass sich viele Zeichen gleichzeitig auf dem Bildschirm bewegen. Im Moment springt die Figur auf und ab, aber wenn Sie genau hinsehen, gibt es ein leichtes Stottern. Es ist nicht schrecklich, aber die Tatsache, dass Sie es mit bloßem Auge sehen können, ist so etwas wie ein Warnzeichen. Die Geschwindigkeit des Emulators ist im Vergleich zu einem physischen Gerät sehr unterschiedlich. Nun stellen Sie sich vor, was passiert, wenn Sie haben Tonnen sofort auf dem Bildschirm los!

Es gibt einige Lösungen für dieses Problem. Zunächst möchte ich eine private Ganzzahl in erstellen Haupt-Bedroung und nenne das targetFPS. Dies hat den Wert 60.Ich werde versuchen, mein Spiel mit dieser Geschwindigkeit zum Laufen zu bringen. In der Zwischenzeit werde ich überprüfen, ob dies der Fall ist. Dafür möchte ich auch ein privates Doppel genannt averageFPS.

Ich werde auch das aktualisieren Lauf Methode, um zu messen, wie lange jede Spielrunde dauert und dann zu Pause diese Spielrunde vorübergehend, wenn sie vor der Ziel-FPS liegt. Wir werden dann berechnen, wie lange es dauert jetzt nahm und druckte das dann, damit wir es im Protokoll sehen können.

@Override public void run () {lange Startzeit; lange Zeit lange Wartezeit; long totalTime = 0; int frameCount = 0; long targetTime = 1000 / targetFPS; while (running) {startTime = System.nanoTime (); canvas = null; try {canvas = this.surfaceHolder.lockCanvas (); synchronized (surfaceHolder) {this.gameView.update (); this.gameView.draw (canvas); }} catch (Ausnahme e) {} finally {if (canvas! = null) {try {surfaceHolder.unlockCanvasAndPost (canvas); } catch (Ausnahme e) {e.printStackTrace (); }}} timeMillis = (System.nanoTime () - startTime) / 1000000; waitTime = targetTime - timeMillis; try {this.sleep (waitTime); } catch (Ausnahme e) {} totalTime + = System.nanoTime () - startTime; frameCount ++; if (frameCount == targetFPS) {averageFPS = 1000 / ((totalTime / frameCount) / 1000000); frameCount = 0; totalTime = 0; System.out.println (averageFPS); }}}

Jetzt versucht unser Spiel, die FPS auf 60 zu beschränken, und Sie sollten feststellen, dass die FPS auf einem modernen Gerät im Allgemeinen ziemlich konstant sind und zwischen 58 und 62 liegen. Auf dem Emulator erhalten Sie möglicherweise ein anderes Ergebnis.

Ändern Sie diese 60 auf 30 und sehen Sie, was passiert. Das Spiel verlangsamt sich und es sollte Lesen Sie jetzt 30 in Ihrem Logcat.

Schlussgedanken

Wir können noch einige andere Maßnahmen ergreifen, um die Leistung zu optimieren. Hier gibt es einen großartigen Blog-Beitrag zu diesem Thema. Versuchen Sie, keine neuen Instanzen von Paint oder Bitmaps innerhalb der Schleife zu erstellen und alle Initialisierungen durchzuführen draußen bevor das Spiel beginnt.

Wenn Sie vorhaben, das nächste erfolgreiche Android-Spiel zu erstellen, gibt es diese bestimmt Heutzutage sind dies einfachere und effizientere Wege. Es gibt jedoch immer noch Anwendungsszenarien, um auf eine Leinwand zeichnen zu können, und es ist eine äußerst nützliche Fähigkeit, Ihr Repertoire zu erweitern. Ich hoffe, dieser Leitfaden hat ein wenig geholfen und wünsche Ihnen viel Glück bei Ihren bevorstehenden Codierungsprojekten!

NächsterEine Einführung in Java

Update, 8. März 2019 (12:02 Uhr): ony hat nach der Veröffentlichung der Preemitteilung eine Erklärung abgegebenVertrauenwürdige Bewertungen Interview mit dem ony-Manager Adam Marh....

Aktualiierung, 26. April 2019 (16:11 ET): Laut ony-Finanzdaten für da vierte Quartal 2018 chneidet die mobile parte von ony ancheinend chlechter ab al gedacht....

Verwaltung Auswählen