Problema de escalado en Android – ¿por qué la imagen es tan torpe?

No tengo gráficos 2D y experiencia de juego. Me enseñé a mí mismo por cientos de errores y decenas de horas perdidas. Comencé con el juego simple Dress Up. Utilicé Nexus 5x para el desarrollo donde una pantalla parecía bien. Cuando terminé un hito probé el juego en la tableta grande de Lenovo y el minúsculo teléfono Samsung Mini. Se veía horriblemente.

Introduzca aquí la descripción de la imagen

Un original vector PSD archivo parece perfecto, PNG exportación no tiene ningún problema tampoco. Pero cuando la escala de la imagen es desigual. Sé que es bitmap. Pero hay otra imagen que escala en otro lugar y se ve bien (ambas imágenes son de 32 bits):

Introduzca aquí la descripción de la imagen

Cuando juego algún juego de Google Play, nunca tienen problemas de escala. ¿Cómo se implementan? ¿Usan vectores? ¿Hay algún truco?

Puse todo en carpeta de assets y aunque tomó 1 MB. He descompilado algunos apk y no tienen conjunto de variantes para cada resolución. Aunque escalan cuadros agradable.

Algunos fragmentos de código fuente:

 protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); this.w = w; this.h = h; canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); drawCanvas = new Canvas(canvasBitmap); } protected void onDraw(Canvas canvas) { if (baseBitmap != null) { double scale = Math.min((double) w / (double) figure.getW(), (double) h / (double) figure.getH()); figure.setScaleRatio(scale); int sw = (int) (scale * figure.getW()); int x = ((w - sw) >> 1); figure.setX(x); paintDressPart(canvas, figure, figure.getMain()); if (displayedParts != null) { for (DressPart dressPart : figure.getParts()) { if (displayedParts.contains(dressPart.getId())) { paintDressPart(canvas, figure, dressPart); } } } } } private void paintDressPart(Canvas canvas, Figure figure, DressPart part) { double scale = figure.getScaleRatio(); int sh = (int) (scale * part.getH()); int sw = (int) (scale * part.getW()); int sdx = (int) (scale * part.getDestX()); int sdy = (int) (scale * part.getDestY()); scaledRect.set(figure.getX() + sdx, sdy, figure.getX() + sw + sdx, sh + sdy); Rect partRect = part.getRect(); canvas.drawBitmap(baseBitmap, partRect, scaledRect, canvasPaint); } 

Y si quieres verlo tú mismo preparé el proyecto completo en GitHub para que puedas descargarlo y ejecutarlo tú mismo:

Https://github.com/literakl/DressUp

Actualizar

Downscaling chupa también. Pero gracias al comentario de Paavnet me di cuenta de que Paint importa. Vea la diferencia en una imagen:

Introduzca aquí la descripción de la imagen

Ejecuté la aplicación de demostración en 3,2 "AVD imagen.La imagen 278×786 es escalado a 107×303.

Actualización de Octubre

Reescribí la aplicación para usar la carpeta de recursos en lugar de los recursos. Android escalas imágenes y luego volver a escala de nuevo. A pesar de que se ve mejor que cuando no uso Android escala de recursos. Los recursos de imágenes en escala mejoran normalmente mejor que los nodpi sin escala / la imagen de activos.

Me pareció que mdpi funciona mejor. Incluso tenía imágenes xxhdpi y se veía peor que mdpi. Creo que incluso en el dispositivo xxhdpi! Pero puede ser un problema del cuadro que no fue pintado bien. La escala de recursos de Android puede suavizar los bordes de las líneas.

Me enfrenté a la misma cuestión .. que la escala no tan suave .. mejor método estándar

 Bitmap resized = Bitmap.createScaledBitmap(yourBitmap, newWidth, newHeight, true); 

Usted puede encontrar más tamaño optimizado convertidor en la web .. pero en realidad la mejor solución que terminó con el uso:

1er. Utilice el recurso del SVG del vector. Esto es trabajo 100% con calidad perfecta. Sólo asegúrese de que los elementos SVG son compatibles con android (consulte: https://developer.android.com/studio/write/vector-asset-studio.html )

Pros

  • mejor calidad
  • Tamaño eficiente
  • Editable fácilmente

contras:

  • No todos los elementos son compatibles.

O

2do. Proporcionar una imagen de alta resolución (uno es suficiente en xxxhdpi)

Pros

  • buena calidad

contras:

  • Podría conducir a problemas de rendimiento

Espero que pueda ayudar, '.

¿Usan vectores?

SVG / Vector es una solución práctica, pero el arte vectorial requiere una precisión extremadamente alta, por lo que no es adecuado para muchos estilos de arte. Es fácil de usar arte vectorial con formas básicas, pero puede ser difícil añadir un detalle simple con SVG estilos simbólicos, aunque se puede agregar Fácilmente con pintura con png,jpeg . Puedes ver videos de patrones de rendimiento en SVG donde los googleadores sugieren SVG para diseños de iconos. La mayoría de los juegos no lo utilizan para imágenes complejas y ricas.

Así que no voy a ir para SVG especialmente donde pequeño detalle importa mucho en los juegos.

¿Cómo se implementan? ¿Hay algún truco?

  1. Una forma es simplemente publicar la aplicación con un solo soporte de activos regulares (MDPI, HDPI) y si la densidad de pantalla requiere alta resolución, entonces mostrar un diálogo para el usuario, preguntándole si quiere descargar los activos de alta resolución.

  2. Usted puede tener una mayor densidad de imágenes y la escala hacia abajo en tiempo de ejecución basados ​​en el requerimiento de densidad de teléfono utilizando DisplayMetrics hecho, debe mantener la misma relación de aspecto.Conjuntar un juego hecho para una pantalla 4: 3 se ve horrible en un 16: Pero encajando un 16: 9 encendido a un 16:10, nadie pudo notar. Leer para más .

Puede utilizar esta forma para obtener fácilmente la altura y el ancho de la pantalla ( teniendo en cuenta que está utilizando SurfaceView como mejor práctica )

 DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); int screenHeight = metrics.heightPixels; int screenWidth = metrics.widthPixels; 

Para obtener una nueva anchura-altura en la rotación:

surfaceChanged(SurfaceHolder holder, int format, int width, int height)

Ese método le da la anchura / altura de su superficie, por lo que ahora podría usar:

 Bitmap.createScaledBitmap (Bitmap src, int dstWidth, int dstHeight, boolean filter) 

Desde la clase Bitmap para cambiar el tamaño de las imágenes en proporción al tamaño de la superficie que está dibujando. Puede buscar en alguna técnica para encontrar factores de escala apropiados.

  1. OpenGL,kotlin puede darle ventaja para la creación de aplicaciones gráficas ricas.Con estos se puede controlar la memoria y el rendimiento de la GPU que básicamente son el hueso de la mayoría de los juegos además de que puede tomar ventaja de controlar la prestación de manera más eficiente con GPU and native memory space Además hay mucho más que se puede pensar, tomará algún tiempo si no está familiarizado con estos pero una vez que lo consigas pueden hacer muchos trucos mágicos.

  2. Webp le ayudará a reducir el tamaño de las grandes imágenes a una diferencia considerable. Debería probar webp. (Sugerencia, webp tiene un pequeño problema para el canal alfa de la imagen en algunos dispositivos pero demasiado bueno para la compresión del tamaño de la imagen)

Conclusión: Implementa las mejores prácticas usando OpenGL, SurfaceView, NDK más cargando imágenes eficientemente usando factores de escala docs link y debería probar esto también.

También puede echar un vistazo a 9patch imágenes 9patch donde se pueden poner restricciones para escalar sólo una parte de la imagen en lugar de whole.it es bastante útil.

Actualización : Como se sugiere, si va a utilizar una imagen de alta resolución, entonces también mirar en esto y esto para desactivar la escala o el factor de escala de cálculo manual. Buena suerte

Nota: Los chicos se sienten libres de editar esta respuesta con información válida si lo desea.

  • Convertir juego Spritekit a Android?
  • Android OpenGL ES y 2D
  • Implementación de Pinch and Zoom en Android SurfaceView
  • ¿Diferencia entre SurfaceView y View?
  • Eliminar una forma de otra con android.graphics.Path
  • ¿Cuál es el mejor lenguaje para la programación gráfica en tiempo real en Android?
  • Dibuja una imagen 2D con OpenGL ES 2.0
  • Ayúdame a configurar OpenGL para 2D
  • Android: buscando un método drawArc () con radio interior y exterior
  • Biblioteca de gráficos 2D para Android
  • Animación con animationSet () en android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.