android - ¿Cómo lidiar con diferentes relaciones de aspecto en libGDX?
opengl-es aspect-ratio (7)
Cómo hacerlo hoy en día:
Dado que esta es una de las preguntas más famosas sobre libgdx aquí, le daré una pequeña actualización :
LibGDX v1.0 presentó Viewport
para manejar este problema. Es mucho más fácil de usar y la estrategia de escalado es conectable, lo que significa que una sola línea puede cambiar el comportamiento y puedes jugar con ella y ver cuál se adapta mejor a tu juego.
Todo lo que necesita saber al respecto se puede encontrar here .
He implementado algunas pantallas usando libGDX que obviamente usaría la clase Screen
proporcionada por el framework libGDX. Sin embargo, la implementación de estas pantallas solo funciona con tamaños de pantalla predefinidos. Por ejemplo, si el sprite fue diseñado para una pantalla de tamaño 640 x 480 (relación de aspecto 4: 3), no funcionará según lo previsto en otros tamaños de pantalla porque los sprites van por los límites de la pantalla y no están ajustados al tamaño de la pantalla en absoluto. Además, si el libGDX hubiera proporcionado escalas simples, el problema al que me enfrentaría todavía habría estado allí porque eso haría que cambiara la relación de aspecto de la pantalla del juego.
Después de investigar en Internet, me encontré con un blog/forum que había discutido el mismo tema. Lo he implementado y hasta ahora está funcionando bien. Pero quiero confirmar si esta es la mejor opción para lograr esto o si hay mejores alternativas. A continuación se muestra el código para mostrar cómo estoy lidiando con este problema legítimo.
ENLACE DEL FORO: blog/forum
public class SplashScreen implements Screen {
// Aspect Ratio maintenance
private static final int VIRTUAL_WIDTH = 640;
private static final int VIRTUAL_HEIGHT = 480;
private static final float ASPECT_RATIO = (float) VIRTUAL_WIDTH / (float) VIRTUAL_HEIGHT;
private Camera camera;
private Rectangle viewport;
// ------end------
MainGame TempMainGame;
public Texture splashScreen;
public TextureRegion splashScreenRegion;
public SpriteBatch splashScreenSprite;
public SplashScreen(MainGame maingame) {
TempMainGame = maingame;
}
@Override
public void dispose() {
splashScreenSprite.dispose();
splashScreen.dispose();
}
@Override
public void render(float arg0) {
//----Aspect Ratio maintenance
// update camera
camera.update();
camera.apply(Gdx.gl10);
// set viewport
Gdx.gl.glViewport((int) viewport.x, (int) viewport.y,
(int) viewport.width, (int) viewport.height);
// clear previous frame
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
// DRAW EVERYTHING
//--maintenance end--
splashScreenSprite.begin();
splashScreenSprite.disableBlending();
splashScreenSprite.draw(splashScreenRegion, 0, 0);
splashScreenSprite.end();
}
@Override
public void resize(int width, int height) {
//--Aspect Ratio Maintenance--
// calculate new viewport
float aspectRatio = (float)width/(float)height;
float scale = 1f;
Vector2 crop = new Vector2(0f, 0f);
if(aspectRatio > ASPECT_RATIO) {
scale = (float) height / (float) VIRTUAL_HEIGHT;
crop.x = (width - VIRTUAL_WIDTH * scale) / 2f;
} else if(aspectRatio < ASPECT_RATIO) {
scale = (float) width / (float) VIRTUAL_WIDTH;
crop.y = (height - VIRTUAL_HEIGHT * scale) / 2f;
} else {
scale = (float) width / (float) VIRTUAL_WIDTH;
}
float w = (float) VIRTUAL_WIDTH * scale;
float h = (float) VIRTUAL_HEIGHT * scale;
viewport = new Rectangle(crop.x, crop.y, w, h);
//Maintenance ends here--
}
@Override
public void show() {
camera = new OrthographicCamera(VIRTUAL_WIDTH, VIRTUAL_HEIGHT); //Aspect Ratio Maintenance
splashScreen = new Texture(Gdx.files.internal("images/splashScreen.png"));
splashScreenRegion = new TextureRegion(splashScreen, 0, 0, 640, 480);
splashScreenSprite = new SpriteBatch();
if(Assets.load()) {
this.dispose();
TempMainGame.setScreen(TempMainGame.mainmenu);
}
}
}
ACTUALIZACIÓN: Recientemente llegué a saber que libGDX tiene algunas de sus propias funcionalidades para mantener las proporciones de aspecto que me gustaría discutir aquí. Mientras buscaba la relación de aspecto en Internet, encontré varios foros / desarrolladores que tenían este problema de "¿Cómo mantener la relación de aspecto en diferentes tamaños de pantalla?" Una de las soluciones que realmente funcionó para mí fue publicada arriba.
Más adelante, cuando procedí con la implementación de los métodos de touchDown()
para la pantalla, descubrí que debido a la escala en el cambio de tamaño, las coordenadas sobre las que había implementado el touchDown()
cambiarían en gran medida. Después de trabajar con algún código para traducir las coordenadas de acuerdo con el cambio de tamaño de la pantalla, reduje esta cantidad en gran medida, pero no tuve éxito en mantenerlas con precisión de punto fijo. Por ejemplo, si hubiera implementado touchDown()
en una textura, cambiar el tamaño de la pantalla desplazaría el touchListener en la región de textura algunos píxeles hacia la derecha o hacia la izquierda, dependiendo del tamaño y esto obviamente no era deseado.
Más tarde, llegué a saber que la clase de escenario tiene su propia funcionalidad nativa para mantener la relación de aspecto ( boolean stretch = false
). Ahora que he implementado mi pantalla utilizando la clase de escenario, la relación de aspecto se mantiene bien. Sin embargo, al cambiar el tamaño o diferentes tamaños de pantalla, el área negra que se genera siempre aparece en el lado derecho de la pantalla; es decir, la pantalla no está centrada, lo que lo hace bastante feo si el área negra es sustancialmente grande.
¿Puede algún miembro de la comunidad ayudarme a resolver este problema?
Consulte la última parte de la sección de la vista en los documentos oficiales: https://code.google.com/p/libgdx/wiki/scene2d#Viewport
Este código funciona para mí con la última actualización: * OrthographicCamera es cámara, esto no hace recorte, solo cambia la ventana gráfica así que el ancho sigue siendo "muchas veces" más grande que la ventana / dispositivo real
public void resize(int width, int height) {
int newW = width, newH = height;
if (cam.viewportWidth > width) {
float scale = (float) cam.viewportWidth / (float) width;
newW *= scale;
newH *= scale;
}
// true here to flip the Y-axis
cam.setToOrtho(true, newW, newH);
}
Estoy usando ese método desde http://blog.acamara.es/2012/02/05/keep-screen-aspect-ratio-with-different-resolutions-using-libgdx/
Hice esta función que devuelve el punto en la pantalla tocado, reducido a la posición del juego que desea.
public Vector2 getScaledPos(float x, float y) {
float yR = viewport.height / (y - viewport.y);
y = CAMERA_HEIGHT / yR;
float xR = viewport.width / (x - viewport.x);
x = CAMERA_WIDTH / xR;
return new Vector2(x, CAMERA_HEIGHT - y);
}
Úselo en la toma de contacto / arriba / arrastre y puede verificar el tacto en su juego.
La clase ResolutionFileResolver permite resolver los nombres de archivo a la mejor resolución. Creo que también funcionará con diferentes relaciones de aspecto, siempre que haya creado sprites para esas proporciones de aspecto. Hay un uso de ejemplo en AssetManagerTest .
Las barras negras a la izquierda / derecha o superior / inferior se ven mejor que simplemente distorsionar toda la escena para que se ajuste a la pantalla. Si se dirige a una relación de aspecto que se encuentra en el medio de los rangos posibles (4: 3 es probablemente de gama baja, 16: 9 es probablemente de gama alta), entonces las barras deben permanecer pequeñas para la mayoría de los dispositivos. Esto también te permite usar la mayor parte de la pantalla incluso en pantallas más grandes, y ya tienes el código de ese tipo, así que es bastante fácil. Sería aún mejor si esto fuera solo una opción integrada en libgdx.
Pero, creo que el mejor enfoque es usar toda la pantalla. No he hecho esto todavía, pero será el enfoque que tome para mi próximo proyecto. La idea es que si alguien tiene una pantalla más amplia, debería ver más en los lados. Chris Pruett habla sobre cómo hacer esto en una de sus charlas ( enlace para verlo en una conversación , en realidad, todo es bastante bueno). La idea es escalar para la altura, y luego establecer su ventana gráfica lo suficientemente amplia como para caber en la pantalla. OpenGL debería ocuparse de mostrar el resto. La forma en que lo hace está here .
Para libgdx, tal vez haya una manera fácil de hacerlo con scene2d moviendo la cámara sobre el escenario, pero nunca he trabajado con scene2d. En cualquier caso, ejecutar la aplicación como una ventana nativa de tamaño variable es una manera mucho más fácil de probar múltiples tamaños de pantalla que crear un grupo de AVD.
EDITAR: libGDX ha evolucionado. La mejor respuesta es ahora esta por el usuario noone. Asegúrese de verificar el enlace a la here .
Cuando SteveBlack publicó el enlace del problema que se informó en la clase de escenario, fui allí solo para descubrir que el problema (que en realidad no era mi problema) se ha resuelto en los últimos nightlies.
Después de investigar aquí y allá en Internet por el problema que estaba teniendo, no pude encontrar ninguna solución, así que decidí contactar a la persona que reportó el error directamente. Después de eso, él me respondió en los foros de libgdx y estoy en deuda con él por haberme ayudado. Aqui esta el link
Era una sola línea de código y todo lo que tienes que hacer es:
En el resize () methond:
stage.setViewport(640, 480, false);
stage.getCamera().position.set(640/2, 480/2, 0);
Donde 640 X 480 es la resolución de su TextureRegion que describe la relación de aspecto deseada. Si su tamaño de TextureRegion era 320 X 240, entonces ambos argumentos deberían cambiarse a la nueva resolución para hacer el truco.
Enlace de perfil de la persona original que realmente resolvió mi problema