He implementado algunas pantallas usando libGDX que obviamente usarían la Screen
clase proporcionada por el marco libGDX. Sin embargo, la implementación de estas pantallas solo funciona con tamaños de pantalla predefinidos. Por ejemplo, si el sprite estaba destinado a una pantalla de tamaño 640 x 480 (relación de aspecto 4: 3), no funcionará como se esperaba en otros tamaños de pantalla porque los sprites se ajustan a los límites de la pantalla y no se ajustan al tamaño de la pantalla. en absoluto. Además, si libGDX hubiera proporcionado un escalado simple, el problema al que me enfrento aún habría estado ahí porque eso haría que la relación de aspecto de la pantalla del juego cambiara.
Después de investigar en Internet, me encontré con un blog / foro 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 lograrlo o si existen mejores alternativas. A continuación se muestra el código para mostrar cómo estoy lidiando con este problema legítimo.
ENLACE DEL FORO: http://www.java-gaming.org/index.php?topic=25685.new
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: Hace poco me enteré de que libGDX tiene algunas de sus propias funciones para mantener relaciones de aspecto que me gustaría discutir aquí. Mientras buscaba el problema de 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í se publicó arriba.
Más tarde, cuando procedí a implementar los touchDown()
métodos para la pantalla, descubrí que debido a la escala al cambiar el tamaño, las coordenadas en las que había implementado touchDown()
cambiarían en gran medida. Después de trabajar con un 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 pude mantenerlas con una precisión milimétrica. Por ejemplo, si lo hubiera implementado touchDown()
en una textura, cambiar el tamaño de la pantalla desplazaría el touchListener en la región de la textura algunos píxeles hacia la derecha o hacia la izquierda, dependiendo del cambio de tamaño y esto obviamente no era deseado.
Más tarde supe 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 usando 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.
¿Algún miembro de la comunidad puede ayudarme a resolver este problema?
fuente
Respuestas:
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 introducido
Viewport
para manejar este problema. Es mucho más fácil de usar y la estrategia de escala 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 aquí .
fuente
TextureRegion
Streches. Si deja lareszie(int width, int height)
función vacía. LATextureRegion
no strectch.EDITAR: libGDX ha evolucionado. La mejor respuesta es ahora esta del usuario nadie. Asegúrese de consultar el enlace a la
Viewport
documentación. .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 había resuelto en las últimas noches.
Después de investigar aquí y allá en Internet para el problema que estaba teniendo, no pude encontrar ninguna solución, así que decidí contactar a la persona que informó el error directamente. Después de eso, me respondió en los foros de libgdx y estoy en deuda con él por ayudarme. Aqui esta el link
Era una sola línea de código y todo lo que tienes que hacer es:
En el método resize ():
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 el tamaño de TextureRegion era 320 X 240, entonces ambos argumentos deben cambiarse a la nueva resolución para hacer el truco.
Enlace de perfil de la persona original que realmente resolvió mi problema
fuente
setViewport
con 3 parámetros en no disponible ahora!Las barras negras a la izquierda / derecha o arriba / abajo se ven mejor que simplemente distorsionar toda la escena para que se ajuste a la pantalla. Si apunta a una relación de aspecto que se encuentra en el medio de los rangos posibles (4: 3 es probablemente el extremo bajo, 16: 9 es probablemente el extremo superior), entonces las barras deberían 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, por lo que es bastante fácil. Sería aún mejor si esta fuera solo una opción integrada en libgdx.
Pero creo que el mejor enfoque es usar toda la pantalla. Aún no he hecho esto, pero será el enfoque que tomaré para mi próximo proyecto. La idea es que si alguien tiene una pantalla más ancha, debería ver más en los lados. Chris Pruett habla sobre cómo hacer esto en una de sus charlas ( enlace a spot in talk ; de hecho, todo es bastante bueno). La idea es escalar la altura y luego configurar la ventana de visualización lo suficientemente amplia para adaptarse a la pantalla. OpenGL debería encargarse de mostrar el resto. La forma en que lo hace es aquí .
Para libgdx, tal vez haya una manera fácil de hacer esto 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 forma mucho más fácil de probar varios tamaños de pantalla que crear un montón de AVD.
fuente
Vea la última parte de la sección Viewport en los documentos oficiales: https://code.google.com/p/libgdx/wiki/scene2d#Viewport
fuente
La clase ResolutionFileResolver le permite resolver nombres de archivos con la mejor resolución. Creo que también funcionará con diferentes relaciones de aspecto, siempre que haya creado sprites para esas relaciones de aspecto. Hay un ejemplo de uso en AssetManagerTest .
fuente
Estoy usando ese método de 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 de 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); }
Use esto en el touchdown / up / drag y puede verificar el toque en su juego.
fuente
Este código me funciona con la última actualización: * OrthographicCamera es una cámara, esto no hace recortes, solo cambia la ventana gráfica para que el ancho sea todavía "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); }
fuente