Solución de error en libGDX al compilar para iOS con orientación Landscape

Actualmente estoy trabajando en un videojuego de plataformas con libGDX-1.9.3. Este juego se ejecuta en modo apaisado o Landscape.

Captura Rainbow Diamonds
Captura Rainbow Diamonds

La compilación para iOS ha funcionado correctamente, y en el simulador de iPhone, que ejecuta iOS 9, todo funciona perfectamente. Pero al probar el juego en un iPhone 4 con iOS 7, se produce un error en la interpretación de las coordenadas de los escuchadores de eventos, porque se reciben como si el juego se estuviese ejecutando en posición vertical (Portrait).

Tras buscar información en internet, parece que esto es un error conocido de libGDX, que se introdujo en la versión 1.9.0 y afecta a iOS 7 y 8. Podéis seguir el estado de la incidencia en el sitio oficial de libGDX. Así mismo, en la propia incidencia se da la forma de corregir el problema hasta que sea resuelto en la versión oficial de libGDX.

Por si es de utilidad, a continuación expongo el código que yo utilizo como solución temporal a este error.

 

Detección de la versión de iOS del dispositivo

Esto lo haremos en el lanzador de la aplicación para iOS, clase IOSLauncher del proyecto MyGdxGame-ios. Aquí comprobaremos si el juego se está ejecutando sobre iOS 7 u 8, y almacenaremos el resultado en una variable estática booleana, que podremos consultar desde cualquier punto de nuestra aplicación.

...
import org.robovm.apple.foundation.FoundationVersionNumber
...
public class IOSLauncher extends IOSApplication.Delegate {
 
    @Override
    protected IOSApplication createApplication() {
        // GameConfig.ios7or8 is a static boolean variable
        GameConfig.ios7or8 = 
            FoundationVersionNumber.getVersion() >= FoundationVersionNumber.Version_iOS_7_0
            && FoundationVersionNumber.getVersion() <= FoundationVersionNumber.Version_iOS_8_3;
 
        IOSApplicationConfiguration config = new IOSApplicationConfiguration();
        return new IOSApplication(new MyGdxGame(), config);
    }
    ...
}

 

Aplicar transformación de coordenadas

Ahora sabemos cuándo el dispositivo donde se ejecuta el juego tiene iOS 7 u 8. Lo siguiente es transformar las coordenadas recibidas si se da esta condición. Sobre esto, dejo algunas recomendaciones:

  • Es necesario hacer la transformación en todos los InputProcessor que utilicemos. Recordad que si utilizamos Stage, esta clase también es una implementación de InputProcessor. No es necesario sobrescribir cada escuchador de eventos que utilicemos, sino sólo el método base en el InputProcessor y ya se realizará la propagación a los escuchadores con las coordenadas corregidas.
  • Se deberán sobrescribir los métodos touchDown(), touchUp() y touchDragged() según los que utilicemos en nuestros escuchadores de eventos. Si no estás seguro de cuáles necesitas, puedes sobrescribirlos todos.
  • Si utilizas Touchpad como control en tu juego, entonces es necesario sobrescribir los tres métodos anteriores para que el touchpad funcione correctamente.

La transformación de coordenadas ha sido tomada directamente de la incidencia de libGDX y, cabe destacar que se distinguen dos modos de apaisado: LandscapeLeft (botón home a la izquierda) y LandscapeRight (botón home a la derecha). Para conocer la orientación actual se consulta la rotación del dispositivo, ya que la transformación de coordenadas es distinta en cada caso.

...
public class MyGameLayer extends WidgetGroup implements InputProcessor {
    ...
    @Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) {
        if (GameConfig.ios7or8) {
            int rotation = Gdx.input.getRotation();
            if (rotation == 90) { // Landscape right
                int ox = screenX;
                screenX = screenY;
                screenY = Gdx.graphics.getHeight() - ox;
            } else if (rotation == 270) { // Landscape left
                int oy = screenY;
                screenY = screenX;
                screenX = Gdx.graphics.getWidth() - oy;
            }
        }
        return super.touchDown(screenX, screenY, pointer, button);
    }
    ...
}

El fragmento de código anterior corresponde a la sobrescritura del método touchDown(). Los métodos touchUp() y touchDragged() serían de la misma forma, y en la última linea llamando al método de la clase padre correspondiente.

Saludos!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*