2012-05-22 17 views
5

He estado tratando de buscar una respuesta y parece que no puedo encontrarla (es un enfoque bastante poco convencional para programar un juego de Android, por lo que es de esperar, al menos creo).Escalando un SurfaceView fijo para llenarlo verticalmente y mantener la relación de aspecto

Estoy tratando de crear un juego de rol estilo GBA en Android (para la nostalgia). OpenGL no era lo suficientemente bueno para mí porque no era lo suficientemente personalizable en el ciclo del juego (solo quiero que se llame cuando haya que dibujar algo, ya que quiero que este juego sea súper eficiente en cuanto a su uso). la batería, lo que significa que actúa más como una aplicación de votación que como un juego). Creé una vista de superficie personalizada con su propio hilo que se llama cada vez que se necesita hacer un dibujo (lo modelé después del juego de Android LunarLander de muestra en el SDK).

La cuestión es que quiero que el juego tenga un tamaño fijo (208x160) y luego se amplíe hasta el tamaño de la pantalla. El problema que estoy teniendo no parece ser de todos modos hacerlo desde dentro de los parámetros normales del SurfaceView extendido en XML. El juego en su estado actual se ilustra a continuación. Estoy tratando de hacer que se extienda a la altura de la pantalla y mantener la proporción en el ancho, mientras que también no se agrega al juego visible (manteniéndolo fijo, independientemente del tamaño de la pantalla).

http://i.stack.imgur.com/EWIdE.png (que iba a publicar la imagen real en línea. Prevenir el uso abusivo puede morderme>. <)

Actualmente me estoy haciendo la lona del SurfaceView y dibujar directamente a él, y el suministro de mi tamaño que una dimensión de píxel codificada (208px, 160px).

Así es como se ve actualmente el hilo al obtener el lienzo y dibujarlo. ¿Cuál sería una mejor manera de dibujar en un lienzo sin cambiar el tamaño que quiero que el juego tome prácticamente?

@Override 
    public void run() 
    { 
     Canvas c = null; 
     try 
     { 
      c = surfaceHolder.lockCanvas(null); 
      synchronized (surfaceHolder) 
      { 
       draw(c); 
      } 
     } 
     catch (Exception e) 
     { 
      e.printStackTrace(); 
     } 
     finally 
     { 
      if (c != null) 
       surfaceHolder.unlockCanvasAndPost(c); 
     } 
    } 

El método draw es esto (StringBuilder es mi propio objeto codificado en el motor):

public void draw(Canvas canvas) 
{  
    canvas.drawColor(Color.GRAY); 
    StringBuilder stringBuilder = new StringBuilder(canvas, Color.BLACK, letters); 
    stringBuilder.drawString("Oh, hello there!"); 
    stringBuilder.setLocation(10, 20); 
    stringBuilder.drawString("Why am I so small?"); 
} 

¿Alguna idea?

+0

¿Ha considerado escalar su lienzo para adaptarse al 'SurfaceView'? –

+0

@ K-ballo El lienzo proviene del SurfaceView en sí ... .... al ejecutar run() (que es el método de ejecución del subproceso) crea un lienzo y luego establece el lienzo en el SurfaceHolder, que luego bloquea el lienzo, luego dibujar a ella y luego desbloquear y publicar en la vista cuando haya terminado. A menos que haya leído el código original de la muestra de LunarLander incorrecto ... – TheAssailant

+0

Entonces ...? ¿No puedes simplemente llamar 'scale' en él? –

Respuesta

4

Asuma que su función draw se renombró a drawBase en su lugar. Aquí está cómo hacerlo:.

public void draw(Canvas canvas) 
{ 
    final float scaleFactor = Math.min(getWidth()/208.f, getHeight()/160.f); 
    final float finalWidth = 208.f * scaleFactor; 
    final float finalHeight = 160.f * scaleFactor; 
    final float leftPadding = (getWidth() - finalWidth)/2; 
    final float topPadding = (getHeight() - finalHeight)/2; 

    final int savedState = canvas.save(); 
    try { 
     canvas.clipRect(leftPadding, topPadding, leftPadding + finalWidth, topPadding + finalHeight); 

     canvas.translate(leftPadding, topPadding); 
     canvas.scale(scaleFactor, scaleFactor); 

     drawBase(canvas); 
    } finally { 
     canvas.restoreToCount(savedState); 
    } 
} 
+0

El problema es que obtengo un lienzo de SurfaceView y el SurfaceView ya tiene un tamaño predeterminado del diseño. Aunque me gusta este código, todavía no crea una vista de juego que tenga una relación de 1.3 fija con cajas de pilar como relleno a los lados. Todavía hay juego adicional en el lado derecho y va a ser una distracción para los jugadores. – TheAssailant

+0

@TheAssailant: allí, ajustó el código para el relleno y el recorte. –

+0

¡Gracias! Esto funciona (casi) perfectamente. Para lo que necesito, simplemente configuro topMargin en 0 y usé la altura original para el recorte. Trabajado como un encanto. Pero sí, esto es perfecto, ¡muchas gracias! – TheAssailant

1

(La respuesta aceptada de K-ballo está muy bien, pero en los 2,5 años desde que se escribió pantallas han conseguido una densa mucho, lo que significa que la representación del software es cada vez más caro que es importante obtener el hardware para ayudar a hacer el trabajo.)

Para representar a una resolución específica, puede usar SurfaceHolder#setFixedSize(). Esto establece el tamaño de la superficie para que sean las dimensiones exactas que especifique. La superficie se escalará para que coincida con el tamaño de la Vista mediante el escalador de hardware, que será más eficiente que la escala del software. La función se describe en este blog post, y puede verlo en acción en Grafika's actividad de "hardware scaler exerciser" (demo video).

Puede mantener la relación de aspecto adecuada para pantallas de diferentes tamaños ajustando el tamaño de la superficie (que es lo que Grafika hace para esa demostración) o ajustando la vista a letter o pilar-box en el diseño. Puede encontrar un ejemplo de este último en la clase AspectFrameLayout de Grafika, que se utiliza para varias demostraciones de cámara y video.

Con respecto a esto:

OpenGL no era lo suficientemente bueno para mí porque no era lo suficientemente personalizable en el bucle del juego (sólo quiero sorteo que se llama cuando hay algo que necesita ser dibujado ...

usted tiene dos opciones. en primer lugar, se puede utilizar GLSurfaceView#setRenderMode() a inhabilitar el procesamiento continuo. en segundo lugar, no es necesario utilizar GLSurfaceView usar OpenGL. la mayoría del código GLES en Grafika opera sobre SurfaceView o TextureView.

Cuestiones relacionadas