2011-12-15 12 views
14

Ho studiato e fatto piccoli giochi per un po 'e ho deciso ultimamente di provare a sviluppare giochi per Android.Il modo migliore per separare la logica di gioco dal rendering per un gioco frenetico per Android con OpenGL?

Per me, passare dal codice C++ nativo ad Android Java non è stato difficile, ma mi dà mal di testa pensare a come mantenere la logica separata dal rendering.

ho letto qui e su altri siti che:

E 'meglio non creare un altro thread per esso, proprio perché Android volontà di avere certo problemi per l'elaborazione.

Significato del codice sarebbe qualcosa di simile:

public void onDrawFrame(GL10 gl) { 
    doLogicCalculations(); 
    clearScreen(); 
    drawSprites(); 
} 

Ma io non sono sicuro se questo sarebbe l'approccio migliore. Dal momento che non penso che mi piaccia come sarà se inserissi la mia logica nel metodo GLRenderer::onDrawFrame. Per quanto ne so, questo metodo è pensato per disegnare, e posso rallentare i frame se inserisco la logica lì. Per non parlare del fatto che mi feriscono i concetti di POO nella mia comprensione.

Penso che utilizzando thread potrebbe essere il modo, questo è come stavo progettando:

attività principale:

public void onCreate(Bundle savedInstanceState) { 
    //set fullscreen, etc 

    GLSurfaceView view = new GLSurfaceView(this); 
    //Configure view 

    GameManager game = new GameManager(); 
    game.start(context, view); 

    setContentView(view); 
} 

GameManager:

OpenGLRenderer renderer; 
Boolean running; 
public void start(Context context, GLSurfaceView view) { 
    this.renderer = new OpenGLRenderer(context); 
    view.setRenderer(this.renderer); 

    //create Texturelib, create sound system... 

    running = true; 
    //create a thread to run GameManager::update() 
} 

public void update(){ 
    while(running){ 
     //update game logic here 
     //put, edit and remove sprites from renderer list 
     //set running to false to quit game 
    } 
} 

e, infine, OpenGLRenderer:

ListOrMap toDraw; 
public void onDrawFrame(GL10 gl) { 
    for(sprite i : toDraw) 
    { 
     i.draw(); 
    } 
} 

Questa è un'idea approssimativa, non completamente completa. Questo schema terrebbe tutto separato e sembrerebbe un po 'migliore, ma è il migliore per le prestazioni?

Fintanto che ho cercato, la maggior parte degli esempi di giochi con thread utilizza canvas o surfaceview, quelli che non si adattano al mio caso, perché sto usando OpenGLES.

Così qui sono le mie domande:

Qual è il modo migliore per separare la mia logica gioco dalla prestazione quando si utilizza OpenGLES? Threading my applicazione? Metti la logica in un metodo separato e basta chiamarla dal metodo ?

risposta

10

Quindi penso che ci sono due modi per andare qui.

  1. fare tutti gli aggiornamenti da onDrawFrame(): Questo è simile all'uso di GLUT, e Android chiamerà questa funzione il più spesso possibile. (Disattivi con setRenderMode(RENDERMODE_WHEN_DIRTY).) Questa funzione viene chiamata sul suo stesso thread (non sul thread dell'interfaccia utente) e significa che chiami il tuo aggiornamento logico qui. Il tuo problema iniziale è che sembra un po 'complicato, e sono d'accordo, ma solo perché la funzione è denominata onDrawFrame(). Se fosse chiamato onUpdateScene(), l'aggiornamento della logica si adatterebbe bene a questo modello. Ma non è la cosa peggiore del mondo, è stato progettato in questo modo e le persone lo fanno.

  2. logica dare il proprio filo: Questo è più complicato dal momento che ora hai a che fare con tre fili: il thread dell'interfaccia utente per l'input, il filo onDrawFrame() di rendering per disegnare roba, e il filo logico per lavorare in modo continuo sia con input e rendering dei dati. Usalo se hai bisogno di avere un modello veramente accurato di ciò che sta accadendo anche se il framerate sta calando (ad esempio, una precisa risposta di collisione). Questo può essere concettualmente un po 'più pulito, ma non praticamente più pulito.

Consiglierei # 1. Non hai davvero bisogno del # 2. Se lo fai, puoi aggiungerlo in un secondo momento, immagino, ma la maggior parte delle persone usa solo la prima opzione perché l'hardware è abbastanza veloce da non dover essere progettato attorno ad esso.

+0

Ottima risposta Steve, grazie!Penso che anche se non mi piace rovinare il design, seguirò il numero 1. Il mio gioco è attivo, ma non ci sono calcoli pesanti su di esso, come la fisica o un sacco di controllo delle collisioni. Per essere sicuro dei miei pensieri, il mio approccio al threading nella domanda sarebbe corretto se lo selezionassi (la scrittura logica in una mappa sincronizzata e il thread di rendering che la legge)? –

+0

Oh, un'altra cosa. la gente mi ha detto di limitare i miei aggiornamenti logici a 30 fps, questo vale anche per il rendering? Dovrei limitare l'intera funzione ad aspettare 33ms per ogni aggiornamento, o semplicemente aggiornare la logica se è stata superata 33ms dall'ultimo aggiornamento? –

+0

Non penso che tu debba limitarlo, ma forse non aspettarti di meglio su alcuni telefoni. Questo perché il framerate di alcuni dei primi telefoni HDPI (penso al tempo del Droid 1) era pieno, il che significa che non potevano disegnare uno schermo pieno di pixel più di circa 30 volte al secondo. Forse la GPU può lanciare i frame più velocemente, ma la CPU non può spostarli sullo schermo abbastanza velocemente. Questo non è il caso sui nuovi telefoni, penso. –

6

Mantenete il vostro disegno più semplice possibile :) Lo standard (e forse il migliore) approccio è il seguente:

public void update(){ 
    while(running){ 
     updateAll(); 
     renderAll(); 
    } 
} 

pagherei attenzione su alcuni momenti:

  • voi bisogno di chiamare sequently update e render metodi, evitare di chiamare update due volte a tempo
  • , se si preferisce m ultithreading (Io non), scrive i tuoi dati in modo update scrive solo render legge solo
  • tieni presente che OpenGL ha il suo "thread", quindi quando chiami la funzione GL invia solo qualche comando a OpenGL (eccetto glFlush() - completa tutti i comandi)
+0

hmm, come suggerisce l'ultimo argomento, onDrawFrame di OpenGLrenderer viene chiamato su un altro thread? o solo gl.GLxxx() che vengono inviati come richieste ad altri thread pertinenti a GL? –

+0

@Gtoknu Quando ottieni la chiamata 'onDrawFrame()', sei su un'altra discussione. Vedi qui: http://developer.android.com/reference/android/opengl/GLSurfaceView.Renderer.html –

+0

@SteveBlackwell Oh, grazie, non me ne sono reso conto. Ma come potrebbe la risposta di brigadir essere vera se non riesco a chiamare suDrawFrame() poiché viene chiamato automaticamente da un altro thread? quelli sono confusi. –

Problemi correlati