Escala de un SurfaceView fijo para rellenar verticalmente y mantener la relación de aspecto

He estado tratando de buscar una respuesta y no puedo encontrar uno (es un enfoque bastante poco convencional para la programación de un juego de Android, por lo que es de esperar, al menos creo).

Estoy tratando de crear un juego GBA estilo RPG en Android (para la nostalgia). OpenGL no era lo suficientemente bueno para mí porque no era lo suficientemente personalizable en el bucle del juego (solo quiero que se llame cuando hay algo que necesita dibujarse, ya que quiero que este juego sea muy eficiente en cómo lo usa La batería, lo que significa hacer que actúe más como una aplicación de sondeo que un juego). He creado una vista de superficie personalizada con su propio hilo que se llama siempre que el dibujo tiene que ser hecho (que modelado después de la muestra LunarLander android juego en el SDK).

La cosa es, quiero que el juego en sí sea un tamaño fijo (208×160) y luego escala hasta el tamaño de la pantalla. El problema que estoy teniendo es que no parece ser de todos modos hacerlo desde dentro de los parámetros normales de la SurfaceView extendida en XML. El juego en su estado actual se ilustra a continuación. Estoy tratando de hacer estirar a la altura de la pantalla y mantener la relación en el ancho, mientras que también no añadir al juego visible (mantenerlo fijo, independientemente del tamaño de la pantalla).

Http://i.stack.imgur.com/EWIdE.png (Iba a publicar la imagen real en línea. La prevención del spam puede morderme. <)

Actualmente estoy recibiendo el lienzo de SurfaceView y dibujándolo directamente, y suministrando mi tamaño como una dimensión de píxel codificada (208px, 160px).

Esto es lo que el hilo de rosca parece actualmente en conseguir el lienzo y dibujarlo. ¿Cuál sería una mejor manera de dibujar a un lienzo sin cambiar el tamaño que quiero que el juego a tomar 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 éste (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?"); } 

¿Algunas ideas?

Supongamos que la función de draw se ha cambiado a drawBase . Aquí es cómo lo haces:

 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); } } 

(La respuesta aceptada de K-ballo está bien, pero en los 2,5 años desde que se escribió las pantallas se han vuelto mucho más densas, lo que significa que la renderización de software es cada vez más costosa. Es importante obtener el hardware para ayudar a hacer el trabajo.

Para renderizar con una resolución específica, puede utilizar SurfaceHolder # setFixedSize () . Esto establece el tamaño de la Superficie para que sea las dimensiones exactas que especifique. La superficie se ampliará para que coincida con el tamaño de la vista por el escalador de hardware, que va a ser más eficiente que la escala de software. La característica se describe en esta entrada de blog , y se puede ver en acción en Grafika "hardware escalador ejercicio" actividad ( video de demostración ).

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 hace Grafika para esa demostración) o ajustando la vista a la carta o el cuadro de pilar del 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 vídeo.

Con respecto a esto:

OpenGL no era lo suficientemente bueno para mí porque no era lo suficientemente personalizable en el bucle de juego (sólo quiero dibujar a ser llamado cuando hay algo que necesita ser dibujado …

Tienes dos opciones. En primer lugar, puede utilizar GLSurfaceView # setRenderMode () para desactivar la representación continua. En segundo lugar, no es necesario utilizar GLSurfaceView para utilizar OpenGL. La mayor parte del código GLES en Grafika opera en SurfaceView o TextureView.

  • Cómo obtener un SurfaceHolder con una superficie válida (necesario por EGL.eglCreateWindowSurface)?
  • ERROR: createWindowSurface falló EGL_BAD_ALLOC
  • ¿Cómo lograr 30 fotogramas por segundo utilizando Android SurfaceView?
  • Cómo conciliar la diferencia en la relación de aspecto entre el tamaño de vista previa de la cámara y el tamaño de la imagen
  • Cómo encontrar el mejor PixelFormat para un Android SurfaceView
  • Establecer el color de fondo de la vista de superficie
  • Android Advertencia: CHECK surface infomation creating = false
  • Tutorial de cámara para Android (con vista de superficie)
  • WaitingInMainSignalCatcherLoop Error en la aplicación de Android
  • Cómo hacer transparente la superficie
  • El EditText de Android se oculta cuando se muestra el teclado virtual y está involucrado SurfaceView
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.