En nuestro recorrido por LibGDX, ahora nos adentramos en cómo manejar la entrada del usuario para controlar un sprite, en este caso un coche, de forma fluida y ajustada al tiempo. Partimos de un código limpio que solo muestra el sprite, eliminando elementos innecesarios como fuentes o texturas adicionales para centrarnos en la interacción.
Para procesar la entrada, LibGDX nos ofrece dos formas: una sencilla y directa, y otra más profesional que veremos en episodios posteriores. Por ahora, nos quedamos con la forma sencilla, que consiste en consultar en cada fotograma si ciertas teclas están siendo pulsadas mediante el método Gdx.input.isKeyPressed(). Este método recibe como parámetro una constante de la clase Input.Keys que representa la tecla que queremos detectar.
Queremos que nuestro coche responda tanto a las teclas clásicas de movimiento WASD como a las flechas del teclado, para cubrir diferentes preferencias. Así, definimos variables booleanas para cada dirección, por ejemplo, para arriba:
boolean arriba = Gdx.input.isKeyPressed(Input.Keys.W) || Gdx.input.isKeyPressed(Input.Keys.UP);
Y de forma similar para izquierda, abajo y derecha, combinando A con LEFT, S con DOWN y D con RIGHT.
Con estas variables, actualizamos la posición del coche. Primero obtenemos su posición actual:
float x = coche.getX();
float y = coche.getY();
Luego, según qué teclas estén pulsadas, modificamos x e y para mover el coche en la dirección correspondiente. Sin embargo, para evitar conflictos cuando se pulsan teclas opuestas simultáneamente (por ejemplo, arriba y abajo), usamos una lógica que solo permite moverse si una tecla está pulsada y la opuesta no, implementando esta condición con un operador XOR para mayor claridad y seguridad.
Un detalle importante es que no incrementamos la posición en valores fijos, sino que multiplicamos la velocidad por el tiempo transcurrido desde el último fotograma, obtenido con Gdx.graphics.getDeltaTime(). Esto garantiza que el movimiento sea consistente y no dependa de la tasa de frames por segundo, evitando que el coche se mueva más rápido en máquinas potentes o más lento en otras menos capaces.
Por ejemplo, si definimos una velocidad en píxeles por segundo, multiplicamos esta velocidad por el delta para calcular el desplazamiento real en cada fotograma:
float delta = Gdx.graphics.getDeltaTime();
float velocidad = 100f; // píxeles por segundo
if (arriba && !abajo) {
y += velocidad * delta;
}
if (abajo && !arriba) {
y -= velocidad * delta;
}
if (derecha && !izquierda) {
x += velocidad * delta;
}
if (izquierda && !derecha) {
x -= velocidad * delta;
}
coche.setPosition(x, y);
Para hacer el movimiento más realista, añadimos aceleración y rozamiento. La aceleración cambia según la dirección en la que queremos movernos, y el rozamiento reduce la velocidad gradualmente cuando no hay entrada, evitando que el coche se detenga bruscamente o que quede moviéndose con valores muy pequeños por errores de precisión en los flotantes. Usamos la fórmula del movimiento rectilíneo uniformemente acelerado para actualizar la velocidad y la posición:
velocidad += aceleracion * delta;
x += velocidad * delta + 0.5f * aceleracion * delta * delta;
Pasando a la entrada por ratón o pantalla táctil, LibGDX nos permite obtener la posición actual del cursor o del último toque con Gdx.input.getX() y Gdx.input.getY(). Sin embargo, hay que tener en cuenta que el sistema de coordenadas para el ratón tiene el origen en la esquina superior izquierda, mientras que para dibujar en pantalla el origen está en la esquina inferior izquierda. Por eso, para alinear correctamente la posición del ratón con la del sprite, invertimos la coordenada Y restándola de la altura de la ventana:
float ratonX = Gdx.input.getX();
float ratonY = Gdx.graphics.getHeight() - Gdx.input.getY();
coche.setPosition(ratonX, ratonY);
Esto hace que el coche siga la posición del ratón o del dedo en pantalla.
Además, podemos detectar si el usuario está tocando o haciendo clic con Gdx.input.isTouched(). Esto nos permite, por ejemplo, hacer que el coche se teletransporte a la posición del clic o que se mueva hacia allí de forma gradual. Para un movimiento más natural, calculamos la distancia entre la posición actual del coche y el objetivo, y aceleramos o frenamos según corresponda, usando la anchura del coche para ajustar el punto de llegada y evitar que el coche se pase.
Cuando el coche debe moverse hacia un objetivo, desactivamos la entrada por teclado para que la prioridad la tenga el control por ratón o pantalla táctil. Así, el coche avanza hacia el punto indicado, frenando suavemente cuando se acerca para evitar movimientos bruscos.
En resumen, con estas técnicas podemos controlar la entrada del usuario de forma sencilla pero efectiva, combinando teclado y ratón o pantalla táctil, y asegurando que el movimiento del sprite sea fluido y consistente en cualquier dispositivo. Más adelante exploraremos métodos más profesionales para gestionar la entrada, con procesadores y listeners que nos permitirán organizar mejor el código y manejar eventos de forma más limpia.