2010-05-18 16 views
9

Sto provando a creare un semplice gioco 2D in Java.Il modo migliore per implementare il ciclo di gioco senza congelare il thread dell'interfaccia utente

Finora ho un JFrame, con una barra dei menu, e una classe che si estende JPanel e sovrascrive il suo metodo paint. Ora, ho bisogno di ottenere un ciclo di gioco in corso, dove aggiornerò la posizione delle immagini e così via. Tuttavia, sono bloccato sul modo migliore per raggiungere questo obiettivo. Dovrei usare multi-threading, perché sicuramente, se metti un loop infinito sul thread principale, l'interfaccia utente (e quindi la mia barra dei menu) si bloccherà?

Ecco il mio codice finora:

import java.awt.Color; 
import java.awt.Graphics; 

import javax.swing.JPanel; 

@SuppressWarnings("serial") 
public class GameCanvas extends JPanel { 

    public void paint(Graphics g) { 
     while (true) { 
      g.setColor(Color.DARK_GRAY); 
      try { 
       Thread.sleep(100); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
} 

import javax.swing.JFrame; 
import javax.swing.JMenu; 
import javax.swing.JMenuBar; 
import javax.swing.JMenuItem; 

@SuppressWarnings("serial") 
public class Main extends JFrame { 

    GameCanvas canvas = new GameCanvas(); 
    final int FRAME_HEIGHT = 400; 
    final int FRAME_WIDTH = 400; 

    public static void main(String args[]) { 
     new Main(); 
    } 

    public Main() { 
     super("Game"); 

     JMenuBar menuBar = new JMenuBar(); 
     JMenu fileMenu = new JMenu("File"); 
     JMenuItem startMenuItem = new JMenuItem("Pause"); 
     menuBar.add(fileMenu); 
     fileMenu.add(startMenuItem); 

     super.add(canvas); 
     super.setVisible(true); 
     super.setSize(FRAME_WIDTH, FRAME_WIDTH); 
     super.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     super.setJMenuBar(menuBar); 
    } 
} 

Tutti gli indicatori o suggerimenti? Dove dovrei inserire il mio loop? Nella mia classe principale o nella mia classe GameCanvas?

risposta

5

È necessario un thread per il ciclo di gioco e un thread per gestire gli eventi dell'interfaccia utente Swing come i clic del mouse e la pressione dei tasti.

Quando si utilizza l'API Swing, si ottiene automaticamente un thread aggiuntivo per l'interfaccia utente chiamato thread di invio eventi. I tuoi callback sono eseguiti su questo thread, non sul thread principale.

Il thread principale va bene per il ciclo di gioco se si desidera che il gioco si avvii automaticamente quando vengono eseguiti i programmi. Se si desidera avviare e interrompere il gioco con una GUI Swing, quindi avere il thread principale avviare una GUI, quindi la GUI può creare un nuovo thread per il ciclo di gioco quando l'utente vuole iniziare il gioco.

No, la barra dei menu non si bloccherà se si inserisce il ciclo di gioco nella discussione principale. La barra dei menu si bloccherà se i callback Swing impiegano molto tempo per terminare.

I dati condivisi tra i thread devono essere protetti con i blocchi.

Ti suggerisco di inserire il tuo codice Swing nella sua classe e di inserire il tuo ciclo di gioco nella tua classe principale. Se stai usando il thread principale per il tuo ciclo di gioco, questa è un'idea approssimativa di come potresti crearlo.

import javax.swing.JFrame; 
import javax.swing.JMenu; 
import javax.swing.JMenuBar; 
import javax.swing.JMenuItem; 

class GUI extends JFrame { 
    GameCanvas canvas = new GameCanvas(); 
    final int FRAME_HEIGHT = 400; 
    final int FRAME_WIDTH = 400; 


    public GUI() { 
     // build and display your GUI 
     super("Game"); 

     JMenuBar menuBar = new JMenuBar(); 
     JMenu fileMenu = new JMenu("File"); 
     JMenuItem startMenuItem = new JMenuItem("Pause"); 
     menuBar.add(fileMenu); 
     fileMenu.add(startMenuItem); 

     super.add(canvas); 
     super.setVisible(true); 
     super.setSize(FRAME_WIDTH, FRAME_WIDTH); 
     super.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     super.setJMenuBar(menuBar); 
    } 
} 

public class Main { 

    public static void main(String args[]) { 
     GUI ui = new GUI(); // create and display GUI   

     gameLoop(); // start the game loop 
    } 

    static void gameLoop() { 
     // game loop  
    } 
} 
11

Il tuo ciclo di gioco (modello) non dovrebbe essere vicino a nessuna delle tue classi GUI (vista). Usa le tue classi GUI - ma anche quella che probabilmente vuoi fare attraverso un intermediario (controller). Un buon modo per assicurarti che lo stai facendo bene è controllare che il tuo modello non abbia un singolo "include javax.swing. ???".

La cosa migliore che si può fare è mantenere il ciclo di gioco nella sua stessa trama. Ogni volta che vuoi apportare un cambiamento nella GUI, usa SwingWorker o qualunque cosa i ragazzini ora usano per forzare il thread della GUI per quella sola operazione.

Questo è davvero impressionante perché ti fa pensare in termini di operazioni GUI (che costituiscono il tuo controller). Ad esempio, potresti avere una classe chiamata "Move" che avrebbe la logica della GUI dietro una mossa. Il tuo ciclo di gioco potrebbe creare un'istanza di un "Spostamento" con i valori corretti (elemento da spostare, posizione finale) e passarlo a un loop della GUI per l'elaborazione.

Una volta arrivati ​​a quel punto, ci si rende conto che semplicemente aggiungendo un banale "annullamento" per ciascuna operazione della GUI è possibile annullare facilmente un numero qualsiasi di operazioni. Troverai anche più facile sostituire la tua GUI Swing con una GUI Web ...

4

Java è davvero adatto per event-driven programming. Fondamentalmente, imposta un evento del timer e ascolta. Ad ogni "tick-tock" aggiorni la tua logica di gioco. Ad ogni evento della GUI aggiorni le tue strutture dati che il metodo della logica di gioco leggerà.

Problemi correlati