2011-01-03 1 views
2

Ich arbeite seit einiger Zeit an einem Java-Spiel, das ich in meiner Collegezeit begonnen habe. Nachdem ich aufgrund meiner beruflichen Laufbahn beträchtliche Pausen gemacht habe, komme ich wieder darauf zurück und merke, wie schrecklich der Code ist. Ich hatte im Grunde ein "monolithisches Haupt" mit sowohl GUI als auch Spiellogik in der gleichen Klassendatei. Was ich versuche, ist abstrakt und "komponiert" die GUI in kleinere Stücke. Meine exportierte Klasse erweitert sich um JFrame, dem ich Felder hinzufüge und entferne, wenn Schaltflächen geklickt werden. Ex.Wie implementiere ich ein gutes Spielmenü in Java?

public class GameFrame extends JFrame{ 
    private JPanel[] _panels = {new MainPanel(), new OptionsPanel(), new DifficultyPanel()}; 
    private int _currentPanelIndex = 0; 
    public GameFrame(){ 
     ... 
     add(_panels[_currentPanelIndex]); 
     ... 
    } 
} 

Innerhalb jeder Panel-Klasse habe ich privat ActionListeners für die Tasten. In Mainpanel, erhalte ich die Singleton Gameframe Instanz und die aktuelle Panel Art wie Einstellung:

class SinglePlayerButtonListener implements ActionListener{ 
    public void actionPerformed(ActionEvent e){ 
     GameFrame instance = GameFrame.getInstance(); 
     JPanel[] panels = instance.getPanels(); 
     int currentPanelIndex = instance.getCurrentPanelIndex(); 
     instance.remove(panels[currentPanelIndex]); 
     int newPanelIndex; 
     for(newPanelIndex = 0; newPanelIndex < panels.length; newPanelIndex++){ 
      if(panels[newPanelIndex] instanceof DifficultyPanel){ 
       break; 
      } 
     } 
     instance.add(panels[newPanelIndex]); 
    } 
} 

ich diese Kopplung in meinen Klassen tief nicht mögen, aber ich kann damit leben. Allerdings ist das eigentliche Problem, dass wenn ich den letzten Knopf klicken, der mich in das Spiel dauert, kann ich nicht haben:

public void actionPerformed(ActionEvent e){ 
    GameFrame.getInstance().startGame(); 
} 

weil dies mein Spiel kann in Java Ereignis Thread ausgeführt, wodurch keine anderen Ereignisse zulassen. Zuvor hatte ich eine geschäftige while-Schleife:

... 
while(waiting){ 
    //Do nothing 
} 
remove(_panels[_currentPanelIndex]); 
startGame(); 
... 
... 
public void actionPerformed(ActionEvent e){ 
    waiting = false; 
} 

Was ist der beste Weg, um meine Gameframe Klasse wissen zu lassen, dass ich die Play-Taste geklickt haben? Kann ich ein Ereignis oder eine Nachricht von einem seiner Unterfelder aus an dieses senden, um es zu starten? Wenn ja, wie kann ich verhindern, dass das Spiel im Event-Thread ausgeführt wird? Soll ich es in der actionPerformed() Methode behandeln und einfach einen neuen Thread spawnen? Ich würde es vorziehen, es im Hauptthread zu behalten. Vielen Dank.

Antwort

0

Sie sollten die Spiellogik auf ihrem eigenen Thread ausführen lassen, möglicherweise wenn der Benutzer auf eine Schaltfläche klickt. Ich verstehe deine bisherige Vorgehensweise mit while (wait) nicht - das würde immer noch Probleme verursachen, wenn deine Spiellogik eine zeitaufwendige Berechnung durchführen würde, die den even thread daran hindert, Updates zu machen, weil der even thread nicht aufhört auszuführen, wenn du startGame aufruft ().

EDIT:

Es ist nicht klar, aus dem Code, den Sie eingefügt, dass die GUI-Updates und die Spiellogik werden auf separaten Ausführungs-Threads geschieht - Sie könnten, dass in Ihrem Code demonstrieren wollen.

+0

Richtig, und ich habe die Logik in einem separaten Thread, aber die Zeichnung muss in dem Thread ausgeführt werden, die GUI ausgeführt, oder? Mein Ansatz mit der While-Schleife war es, den Bildschirm mit der Spielwelt zu malen, bis die Play-Taste geklickt wurde. Du hast Recht, dass der Event-Thread nicht aufhört zu laufen, aber wenn du das Spiel _in_ im Event-Thread ausführst, kann nichts anderes darin laufen, einschließlich aller anderen Events, die gefeuert werden. – Wagan8r

+0

Ich verstehe nicht, warum Sie verhindern müssen, dass die Container, die die Welt enthalten, neu gezeichnet werden? –

+0

Ich fürchte, ich habe falsch verstanden. Ich tippte den obigen Code aus dem Speicher und erkannte nicht, dass das Spiel im Moment vollständig single-threaded ist. Aus diesem Grund steuert die GameFrame-Klasse die GUI und die Spiellogik und das aktive Rendering. Wenn ich sie auf separaten Threads laufen lasse, stehe ich immer noch vor dem Problem, das Spiel zu starten. Es ist der Übergang von der GUI zur Spielesimulation, den ich nicht lösen kann. Wie sage ich der Simulation zu beginnen? – Wagan8r

1

Gehen Sie für Slick 2D (ein leichtes OpenGL 2D-Spiel-Entwicklungs-Framework mit vielen coolen Sachen) oder Nifty-GUI.

Slick hat auch einige Beispiele und Tutorials und ist leicht zu erlernen, zum Beispiel kann das StateBasedGame einfach verwendet werden, um mehrere In-Game-Menüs zu implementieren (wie Hauptmenü, Einstellungsmenü, In-Game-Optionen, Pause im Spiel)/resume etc.)