2012-03-28 11 views
7

Quería escribir un juego simple en Android usando OpenGL, pero inmediatamente tuve problemas con el ciclo principal del juego. Mientras leo aquí: http://developer.android.com/resources/tutorials/opengl/opengl-es10.html la aplicación llama a public void onDrawFrame(GL10 gl) cada vez que necesita volver a dibujar la superficie. O algo así. Mi problema era cómo crear un ciclo de actualización que es independiente de las llamadas al sorteo. Es decir, no puede funcionar así, no puedo actualizar la lógica del juego solo cuando el dispositivo (¿aplicación?) Quiere volver a dibujar la superficie (¿o estoy equivocado?).¿Cómo crear una actualización/dibujar un bucle adecuadamente con Android OpenGL?

Después de buscar en Google llegué a la conclusión de que tengo que crear otro hilo para el ciclo de actualización. Pero luego tuve otro problema: con un hilo que se encargaba del dibujo y otro que se encargaba de actualizar la lógica del juego, no sabía cómo hacerlos cooperar. Primero, eran dos clases separadas (al menos en mi implementación) por lo que no podían usar las mismas variables y objetos de juego (sprites, temporizadores, diferentes variables, contadores, etc.) prácticamente todo lo que estas dos clases necesitaban hacer. sus trabajos). Ahora creo que de alguna manera podría empacarlos a ambos en una sola clase. Pero, en segundo lugar, necesitaba sincronizar los dos hilos de alguna manera.

Finalmente, salí con esta idea general:

  • 3 clases:
    1. public class MyRenderer implements GLSurfaceView.Renderer con onSurfaceCreated() método de cuidado de dibujo
    2. public class UpdateThread implements Runnable con run() y update() métodos. run() estaba llamando al método update() exactamente 60 veces por segundo (quería un ciclo de paso fijo)
    3. public class SpritesHolder utilizado como contenedor para todos los objetos del juego/variables/cosas (como sprites, temporizadores, variables de estado, etc.) con todos los campos públicos.
  • Así que básicamente la clase SpritesHolder era una caja que sostiene todas las variables necesarias en un solo lugar, por lo MyRendererUpdateThread y clases podrían acceder a ella y utilizarla.
  • En cuanto a la sincronización - que acabo de hacer algo bajo la siguiente manera:

    public void update(float delta) 
    { 
        synchronized (spritesHolder) 
        { 
         // whole method code... 
        } 
    } 
    

    y:

    public void onDrawFrame(GL10 gl) 
    { 
        synchronized (spritesHolder) 
        { 
         // whole method code... 
        } 
    } 
    

    de manera que ambos hilos no utilizaron el spritesHolder al mismo tiempo. Así que las actualizaciones se realizaron 60 veces por segundo y el dibujo se llevó a cabo cada vez que se necesitaba la aplicación (¿dispositivo?).

Mucho que hablar, lo siento, casi he terminado de escribir esta publicación. ;) Así que de todos modos - esto (descrito arriba) funciona e incluso escribí algún juego basado en esta 'plantilla', pero creo que mis ideas podrían ser una locura y uno puede diseñar todo mucho mejor. Estaría muy agradecido por todos los comentarios y consejos.

+0

solo una palabra: http://obviam.net/ :) – akonsu

Respuesta

1

Probablemente su solución funcione, aunque podría no ser óptima para el rendimiento. Si lo piensas bien, el hilo de renderizado y el hilo de actualización no necesitan ser 100% exclusivos.

yo recientemente pasamos un tiempo pensando en esto por mi juego, y esto es lo que terminé subiendo con (no necesariamente mejor, pero sólo algo en que pensar):

Para cada objeto renderable, tengo un objeto propiedad del subproceso de actualización y otro objeto propiedad del subproceso de representación que es simplemente un contenedor simple que contiene instrucciones para dibujar un objeto (matriz de modelo, valores uniformes, mallaID, etc.). Paso por el hilo de actualización calculando todas las posiciones y valores finales para mis objetos renderizables, y luego sincronizo para una ventana pequeña donde paso cualquier valor que haya cambiado durante ese cuadro a los objetos en el hilo renderizable. Luego, tan pronto como la nueva información ha pasado, la representación de cuadros comienza mientras el siguiente cuadro de actualización se ejecuta simultáneamente. Debido a que solo hay una pequeña ventana de exclusión, permite que la actualización y los subprocesos se ejecuten simultáneamente la mayor parte del tiempo.

1

No utilicé esto con OpenGL todavía, pero UpdateThread debería ser un TimerTask. En que la actividad de lanzamiento con

new Timer().schedule(new UpdateThread(view), 0, 15); //where view is your view, and 15 is the wait time 

en su TimerTask llaman la vista con una Handler. por ejemplo (en la clase de vista)

Handler refreshHandler = new Handler() { 
    public void handleMessage(Message msg) { 
       //Handle it; e.g. for canvas invalidate() 
      }}; 

En su método de funcionamiento UpdateThread hacer esto:

view.refreshHandler.sendMessage(new Message()); 

Ahora es independiente de su gameloop. Además, tu gameloop no debería estar en la actividad principal sino en un subproceso (OO unidireccional).

Cuestiones relacionadas