Android-Threads haben Probleme, meinen Kopf um Design zu wickeln


9

Ich habe Probleme, mich mit dem Spieledesign zu beschäftigen. Auf der Android-Plattform habe ich eine Aktivität und setze ihre Inhaltsansicht mit einer benutzerdefinierten Oberflächenansicht. Die benutzerdefinierte Oberflächenansicht fungiert als Bedienfeld, und ich erstelle Instanzen aller Klassen und führe dort alle Zeichnungen und Berechnungen durch.

Frage: Soll ich stattdessen die Instanzen anderer Klassen in meiner Aktivität erstellen?

Jetzt erstelle ich eine benutzerdefinierte Thread-Klasse, die die Spielschleife behandelt.

Frage: Wie verwende ich diese eine Klasse in all meinen Aktivitäten? Oder muss ich jedes Mal eine separate Instanz der erweiterten Thread-Klasse erstellen?

In meinem vorherigen Spiel hatte ich mehrere Ebenen, die eine Instanz der Thread-Klasse erstellen mussten, und in der Thread-Klasse musste ich Konstruktormethoden für jede einzelne Ebene festlegen und in der Schleife eine switch-Anweisung verwenden, um zu überprüfen, welche Ebene gerendert werden muss und aktualisieren. Entschuldigung, wenn das verwirrend klingt.

Ich möchte nur wissen, ob die von mir verwendete Methode ineffizient ist (was es wahrscheinlich ist) und wie man sie richtig entwirft. Ich habe viele Tutorials da draußen gelesen und habe immer noch große Probleme mit diesem speziellen Thema. Vielleicht ein Link zu einigen Tutorials, die dies erklären? Vielen Dank.

Antworten:


13

Ich empfehle , dass Sie eine Render - Thread (mit Canvas/ OpenGL ES, Canvasist wahrscheinlich ein bisschen leichter zu Setup) und ein Spiel Thread , in dem Sie Ihre Spiellogik setzen.

Um das Spiel tatsächlich zu "laden", können Sie eine GameEngine-Klasse erstellen und diese zum zentralen Punkt Ihrer Anwendung machen. Wenn Ihr Renderer betriebsbereit ist, können Sie einen Rückruf an die GameEngine-Instanz erstellen, der zwei Threads mit einem Runnablefür das Rendern und einem Runnablefür die Spielelogik erstellt und startet .

Beispielcode:

Bewerbungsstart

private GameEngine engine;
private CanvasRenderer renderer;

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   // Create instances of your two Runnable classes and pass that into
   // the GameEngine constructor.
   // Create an instance of the game engine.
   engine = new GameEngine(canvasRunnable, gamelogicRunnable);
   renderer = new CanvasRenderer(this, engine); 
   setContentView(renderer); 
}

CanvasRenderer

private GameEngine engine;    

// Save your instance from the GameEngine reference in your constrcutor and make
// a global initializion for your GameEngine instance.  

@Override
public void surfaceCreated(SurfaceHolder holder) {  
   // One time setup here.
   // When your view is ready, make this callback to the 
   // GameEngine.
   engine.surfaceIsReady();
}

GameEngine

private Thread canvasThread;
private CanvasRunnable canvasRunnable;
// You should be able to figure out how to create a second thread
// where you should put your game logic. :)

// Constructor stuff like creating instances of your threads
// and passing references as you wish to those.
// Don't start the threads here.
// Remember to set references from your Runnable's into your Thread's 
// instances here!

/**
 * Callback. Now your renderer is ready and you
 * can start your threads.
 */
public void surfaceIsReady() {
   thread.setName("Canvas");
   thread.start();
   // Same for game logic.
}

Wow Danke. Mir hat gefallen, wie du es erklärt hast. Diese eine Erklärung beleuchtet das ganze Konzept für mich.
Semajhan

@semajhan: Frag einfach, ob du mehr Probleme hast. :)

Dies ist, was ich in meinem Kopf habe: GameEngine-Klasse, die als "Link" oder "Referenz" zu allen anderen Klassen mit dem Panel fungiert. Aktivität> Panel> GameEngine> alle anderen Klassen.
Semajhan

@ Semajhan: Genau. Nur zu Ihrem Wissen: Wenn Sie sich dazu entschließen, OpenGL ESsollten Sie wissen, dass der Renderer OpenGL ESbereits über einen eigenen Thread verfügt. In diesem Fall müssen Sie kein neues Threadund Runnablefür dieses System manuell erstellen und starten .

Ignoriere diesen Kommentar.
Semajhan

3

Normalerweise ist Ihre Spielschleife in einer einzelnen Aktivität in sich geschlossen.

Wenn Sie die Aktivität wechseln, pausieren / beenden Sie Ihre Spielschleife. Separate Aktivitäten sollten ohnehin einer Spielpause entsprechen (z. B. weil Sie zu einer Aktivität "E-Mail an Freunde senden" oder "Hauptmenü" gewechselt haben).

Für zusätzliche Level sollten Sie keine neuen Threads erstellen oder zerstören ... es sei denn, Sie haben zu einer Aktivität "Level abgeschlossen, nächstes Level laden, bitte warten" gewechselt und müssen das Hauptspiel neu starten "Aktivität sowieso. Aber selbst in diesem Fall erstellen Sie nicht wirklich "zusätzliche" Threads, sondern nur einen Thread in dieser einen Aktivität und beenden / starten diese Aktivität nacheinander / starten neu / beenden / neu starten ... usw. jedes Mal, wenn ein Level abgeschlossen ist.


3

Wenn Sie Deutsch verstehen, ist dieses Tutorial sehr schön.

Für die englische Sprache kann ich dieses Tutorial empfehlen

In Bezug auf die Thread-Klasse: Ich weiß nicht, ob es wirklich notwendig ist, dass Sie aus allen Klassen in Ihrer Anwendung referenzieren können. In meinem Spiel habe ich es so gelöst:

Die Klasse, die für das Zeichnen der Haupt-GUI verantwortlich ist, verfügt über eine überschriebene Rendermethode. Bei dieser Methode wird eine Thread-Klasse aufgerufen, die alle GUI-Elemente aktualisiert und Benutzereingaben verarbeitet.

Der Thread ist auch dafür verantwortlich, eine konstante Framerate aufrechtzuerhalten. Abhängig von dem Spiel, das Sie entwickeln, kann dies wichtig sein.


Das deutsche Tutorial ist nett, aber es wurde grob vai google übersetzt, so dass es schwer zu verstehen ist.
Semajhan
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.