El choque fantasma: cuando 30 FPS no son 60
El reporte fue muy preciso: corriendo en el carril derecho, a 1,321 metros y a velocidad máxima, al subir una rampa apareció el game over. Sin cambiar de carril. Sin tocar nada. Un choque fantasma.
Pocas cosas enojan más en un juego que perder sin saber por qué. Si chocas contra un tren, sabes que fue tu culpa y le das otra vez. Si pierdes subiendo una rampa, que es justo lo que el juego te pide hacer, sientes que el juego te hizo trampa. Por eso este reporte no podía esperar.
Un cuadro a la vez
Un juego se dibuja muchas veces por segundo; cada dibujo es un cuadro, como las hojas de un cuaderno que hojeas rápido para ver una animación. En cada cuadro, el juego mueve los obstáculos, luego mueve al jugador y luego revisa si chocaron. El detalle estaba en ese orden: la rampa ya había avanzado, pero la altura del jugador todavía era la del cuadro anterior. Durante un instante, el jugador quedaba "debajo" de la rampa, y el juego lo contaba como si se hubiera estrellado de frente contra ella.
Para eso había una tolerancia fija de 40 centímetros. El problema es cuánto se atrasa el jugador, y eso depende de cuánto dura cada cuadro:
| Cuadros por segundo | Lo que sube la rampa en un cuadro | ¿Cabe en 40 cm? |
|---|---|---|
| 60 | 22 cm | Sí |
| 30 | 43 cm | No: choque |
A 60 cuadros por segundo todo funcionaba. Pero cuando el teléfono se trababa un poco y bajaba a 30 (algo muy normal en teléfonos modestos, y también en el simulador donde probamos), la misma rampa se volvía una pared. Y no sólo eso: ese mismo límite fijo impedía que el piso "levantara" al jugador, así que en lugar de subir, se quedaba atorado abajo.
La corrección
La tolerancia ahora crece con lo que la rampa sube en ese cuadro, con un margen extra. Si el cuadro dura el doble, la rampa sube el doble y el juego te da el doble de espacio. Y pusimos un tope al tiempo de cada cuadro: nunca cuenta más de una vigésima de segundo. Así, si el teléfono se congela un momento, el mundo no avanza varios metros de golpe mientras tú no ves nada.
Tuvimos cuidado de no pasarnos de buenos. Si llegas de lado a media rampa, desde el suelo, eso sigue siendo un choque: la rampa se sube por el frente, no se atraviesa. Una prueba automática reproduce el choque a 30 cuadros por segundo, revisa que ahora sí subas y que entrar de lado siga contando como choque, para que nada de esto vuelva.
Dos días después, otra vez la rampa
Creímos que ahí terminaba la historia. No. Dos días después, varias partidas terminaron otra vez al subir por una rampa, todas después de los 500 metros; una captura marcaba el choque a 651. La raíz era la misma, pero en otro lugar: el paso de la rampa al tren. Le habíamos dado la tolerancia nueva a la rampa, pero el techo del tren, que es plano, se había quedado con los 40 centímetros de siempre.
Para confirmarlo armamos una copia de la subida (rampa, tren y jugador) y la repetimos con distintos ritmos del teléfono. A 60 y a 45 cuadros por segundo no hubo ni un choque. A 30, chocaba uno de cada cinco convoyes a la velocidad de los 500 metros y más de uno de cada tres a la de los 700. A 20, hasta la mitad. Y debajo de los 300 metros casi no pasaba, porque todavía vas lento: por eso nadie lo había visto al principio.
Esta vez no ampliamos otra tolerancia. Cambiamos la forma de avanzar: cada cuadro se parte en pasos pequeños, de 25 centímetros como máximo, y en cada paso se mueven el mundo, el jugador y los choques. Es como bajar una escalera de escalón en escalón en lugar de saltar tres de golpe. Da igual si el teléfono va rápido o lento: el mundo nunca avanza tanto de una sola vez. De paso, una valla delgada ya no se puede "atravesar" entre dos cuadros lentos.
Lo que vas a notar al jugar: nada. Y esa es la idea. En un teléfono que se traba un poco, la rampa y el tren se sienten igual que en uno rápido.
Lo que aprendimos: toda comparación entre cosas que se mueven debe tomar en cuenta cuánto duró el cuadro. Lo que funciona a 60 cuadros por segundo puede fallar a 30, y tus jugadores no tienen todos el mismo teléfono. Y si algo depende de cuánto avanza el mundo en un cuadro, lo mejor no es ensanchar el margen, sino no dejar que avance tanto.