Viele Android-Spiele sind nicht einmal groß genug, um das Speichern / Laden oder Optionen / Einstellungen zu rechtfertigen, egal, welche benutzerdefinierten Charaktere und dergleichen, nur weil sie 10 Minuten lang im Zug nach Hause gespielt werden.
Machen Sie nicht den Fehler, etwas mit einem großen Spielraum für ein erstes Android-Spiel zu beginnen. Machen Sie ein paar kleinere Spiele und entscheiden Sie sich dann für etwas Größeres
Android Besonderheiten weise:
Struktur:
Ich würde empfehlen, fast das gesamte Spiel in einer Aktivitätsklasse zu haben. Android arbeitet mit der Idee, dass jede Aktivität wie eine Mini-App ist, halb unabhängig von den anderen Aktivitäten in der App. Die App ist im Wesentlichen ein Stapel von Aktivitäten, bei denen der Benutzer sieht, welche ganz oben steht.
Wenn Sie eine von oben entfernen, wird sie im Allgemeinen zerstört und beim nächsten Start einer neuen Aktivität neu erstellt (StartActivity Intent). Dies macht es schwierig, Zustände zwischen Aktivitäten aufrechtzuerhalten, und führt zu einer einzigen Aktivitätsarchitektur
Möglicherweise möchten Sie eine Aktivität vom Typ Startbildschirm mit dem Menü "Neues Spiel / Spiel laden / Optionen" haben und diese als Startaktivität festlegen. Am Ende müssen Sie jedoch auch ein Menü im Spiel für Ihre Spielaktivität haben, das die meisten der gleichen Funktionen enthält
In meiner eigenen App habe ich eine "MenuActivity" erstellt, die die Funktionen zum Starten eines neuen Spiels, Speichern, Laden und Ändern von Optionen enthält. Dann erweitert meine HomeActivity das ebenso wie meine GameActivity.
Da sich alles in einer Aktivitätsklasse befindet, würde ich empfehlen, eine Hierarchie von Aktivitätsklassen zu erstellen und private, geschützte und Standardbereichslose zu verwenden. Auf diese Weise können Sie zumindest die Dinge in verschiedene Dateien aufteilen, um zu verhindern, dass eine nicht verwaltbare Aktivitätsdatei vorhanden ist. ZB für meine eigene App:
GraphicsEngine extends MenuActivity
.
PhysicsEngine extends GraphicsEngine
.
GameLogicActivity extends PhysicsEngine
.
UIActivity extends GameLogicActivity
.
Da es sich bei meiner App um 3D-Opengl-es handelt, funktionieren viele Dinge, die ich mache, nicht aktivitätsübergreifend, sodass sich alle in derselben Aktivität befinden. Vielleicht bin ich voreingenommen, eine Aktivitätsarchitektur zu verwenden
- -
Einfädeln
Für die Spielaktivität haben Sie zwei Threads (oder 3, wenn Sie 3D-OpenGL-Sachen machen). Ein Thread ist der UI / Haupt-Thread. Dies ist der Thread, in dem die Aktivität gestartet und ausgeführt wird und der Ihnen von Android zur Verfügung gestellt wird.
Dieser UI-Thread ist der einzige, in dem Sie UI-Elemente (Ansichten, Layouts usw.) aktualisieren können. Er ist auch derjenige, in dem Listener für Benutzereingaben ausgeführt werden. Sie sehen keine Mechanik des UI-Threads, nur dass er irgendwo in einer Schleife im Hintergrund ausgeführt wird.
Den zweiten Thread machen Sie selbst (ich würde die Verwendung von AsyncTask empfehlen trotz aller Mängel zu verwenden). Dies erledigt alle Nicht-UI-Aufgaben, die Sie in einer normalen Spielschleife ausführen, z. B. das Aktualisieren von Bewegungen, das Berechnen von Kollisionen, Kampfberechnungen usw.
Sie machen diesen AsyncTask-Thread / diese AsyncTask-Klasse zu einer inneren Klasse Ihrer Aktivität. Auf diese Weise können Sie über einige aktivitätsweite Objekte ( Vector<Spaceship>
) verfügen , auf die sowohl der UI-Thread als auch der Game-Loop-Thread zugreifen können.
Da die Spielelogik im Game-Loop-Thread ausgeführt wird, ist dies der einzige Thread, der die Werte von Variablen tatsächlich ändern muss (Tankgeschwindigkeit aktualisieren, Spieler-HP reduzieren). Der UI-Thread liest nur Werte, daher sollte es nur minimale Probleme mit der Parallelität geben.
Das Knifflige ist, dass der UI-Thread auf Anfrage des Game-Loop-Threads Aktualisierungen vornimmt. Es gibt verschiedene Möglichkeiten, dies zu tun. Wenn Sie die AsyncTask-Dokumentation lesen, verfügt sie über die Methode PublishProgress () / onProgressUpdate (). Dies fügt der Warteschlange des UI-Threads tatsächlich Dinge hinzu, die in der nächsten Schleife zu erledigen sind.
Handler macht genau das Gleiche, wenn Sie die handleMessage () -Methode implementieren und diese Methode tatsächlich von der nächsten Schleife des UI-Threads ausgeführt wird.
Schließlich können Sie bei jeder Benutzereingabe im UI-Thread die UI-Elemente sofort aktualisieren (also innerhalb der Implementierung aller onClick / onTouch-Listener). Wenn Sie die Spielobjekte aktualisieren müssen, können Sie entweder Synchronisierung verwenden oder eine eigene Warteschlange mit Aktualisierungen in AsyncTask implementieren, die wie der UI-Thread beim nächsten Ausführen der Spielschleife durchlaufen wird
Android Threading-Anleitung .
- -
Benutzeroberfläche
Für die eigentliche UI-Struktur innerhalb der einzelnen Aktivität empfehle ich, ein Rahmenlayout als Basislayout zu verwenden. Die untergeordneten Elemente in einem Rahmenlayout funktionieren wie eine Warteschlange. Das erste Element wird zuerst gezeichnet, das zweite wird über das erste, das dritte über das zweite gezeichnet.
Auf diese Weise können Sie über mehrere XML-Layoutdateien verfügen und durch Verwalten der untergeordneten Elemente des Rahmenlayouts problemlos Ansichten in und aus austauschen.
Wenn Sie die Oberflächenansicht immer unten haben (erstes untergeordnetes Element im Rahmenlayout), können Sie alle üblichen Android-Ansichten / Widgets (Schaltflächen, Textansichten, Bildlaufansichten) usw. über der Oberflächenansicht verwenden der grafische Teil des Spiels.
Wenn also etwas geladen wird, können Sie die Spieleschleife anhalten / einfach alles überspringen lassen, einen undurchsichtigen Ladebildschirm als letztes untergeordnetes Element zum Rahmenlayout hinzufügen und der Benutzer sieht, dass das Laden auf seinem Bildschirm angezeigt wird , ganz unbewusst, dass andere Ansichten dahinter stehen. Auf diese Weise müssen Sie Ansichten nicht entfernen, deren Einrichtung lange dauert, oder bei jedem Hinzufügen / Entfernen Komplikationen verursachen.
Ich würde auch empfehlen, View.setVisibility-Lose zu verwenden. Sie können beispielsweise Ihrem Basisrahmen-Layout ein ganzes "Inventar" -Layout hinzufügen und dann einfach "Sichtbarkeit" (View.Visible) darauf setzen, wenn der Benutzer auf klickt, um sein Inventar anzuzeigen, und "Sichtbarkeit" (View.Gone) festlegen, wenn er es wieder schließt. Auf diese Weise verwalten Sie nicht einmal die untergeordneten Elemente des Rahmenlayouts, sondern fügen lediglich alles hinzu und machen Dinge sichtbar / unsichtbar, wenn der Benutzer verschiedene Dinge tut
Dies hilft beim erneuten Einfädeln. Wenn der Benutzer klickt, um sein Inventar zu öffnen, wird der onCLickListener im UI-Thread behandelt, das Inventar wird darin sichtbar gemacht und die updateInventory-Methode wird erneut vom UI-Thread aufgerufen, wobei nur Getter für alle aufgerufenen Spielobjekte verwendet werden
Hier ist das Diagramm, das ich für eine frühere Frage zur Idee der einzelnen Aktivität / des Rahmenlayouts erstellt habe:
Vieles, was ich in Ihrem Diagramm sehe, hängt mit der Benutzeroberfläche zusammen, und das scheint ziemlich vernünftig zu sein. Es gibt nur einen kleinen Teil Ihres Diagramms, der für die eigentliche Spielelogik reserviert ist, und es ist sehr vage.
Ich denke du versuchst es zu sehr. Ich würde vorschlagen, dass Sie einfach anfangen, Code zu schreiben. Wählen Sie ein bestimmtes Problem aus und lösen Sie es. Sie werden so viel lernen, dass Sie, wenn Sie eine bessere Vorstellung von Ihrem Problemraum haben, eine völlig andere (und nützlichere) Perspektive haben werden.
quelle