#281 es básicamente lo que dice #282, que la física es sensible a los FPS. Piensa que al fin y al cabo lo que estás haciendo es realizar una integración Euleriana (la ecuación que pone #282) la cuál no es perfecta.
No es lo mismo sumar 2 veces la integración de 1ms que sumar una vez la integración de 2ms (porque las ecuaciones no son lineales, como por ejemplo en la aceleración.) El error se va acumulando en la integración Euleriana (y de hecho puede crear graves problemas, por eso se usan en casos especiales donde se requiere precisión integradores avanzados como RK2 o leapfrog.) También se usas otras técnicas como integración verlet (en la que las variables están implícitas con el delta del estado anterior, no con valores inherentes a los estados a simular.)
Si ves su ecuación deltaTime es lo que se llama el time-step (pasos del tiempo, también llamado deltaTime por el dT de la integración.) El timestep variable significa que en cada ejecución de tu bucle del juego el timeStep va a tener un valor diferente (porque cada vez habrá pasado un tiempo diferente entre cada ejecución de este.)
Lo que pasa es que luego #282 se lía un poco en lo que dice xD
#282 lo que comentas del Quake no es por el timestep si no porque la física estaba mal hecha. ¡Es un bug! Lo que pasa es que llegó a ser tan característico del juego que el bug se mantuvo como una "feature", pero no tiene nada que ver con el timestep.
No encuentro la explicación del bug pero la vi en su día. Era una mezcla de un par de bugs, uno relacionado con el movimiento del ratón (te mueves más rápido en diagonal si mueves el ratón hacia la misma dirección) y otro relacionado con la fricción (que no se activaba bien la fricción al saltar justo al tocar el suelo.) Como digo, esto no tiene NADA QUE VER CON EL TIMESTEP, si no que son bugs de la propia física (y da completamente igual qué integración uses.)
Para obtener una física mas realista, todos los calculos de posicion, orientacion y velocidad de objectos que afectan al gameplay se suelen hacer en un hilo aparte del de los gráficos que asegure un numero fijo de actualizaciones por segundo. Todo esto para asegurar un timestep fijo.
¡Nope! Error. Aunque ejecutes todos los cálculos en un hilo aparte el timestep sigue sin ser fijo. Nadie te asegura que la ejecución de un hilo no se vea afectada por otros hilos. De hecho, te aseguro que se verán afectados. Y aunque no se vean afectados por otros hilos, se verán afectados por otros procesos. Y aunque no se vean afectados por otros procesos, se verán afectados por el planificador de tu SO. Por mucho que cambies tu simulación a un hilo aparte, el tiempo que pasará entre una ejecución y otra es variable.
Para obtener un timestep fijo no necesitas un hilo aparte. De hecho en los videojuegos los hilos extras se usan para cálculos que no dependan de la física o del estado del juego, como puede ser el sonido, la IA, el networking...
De hecho no vale de nada separar el estado del juego del hilo de renderizado porque no puedes renderizar más rápido de lo que cambia tu juego. Por mucho que renderices, estás dibujando frames que son exactamente igual al anterior (al no haber cambiado el estado del juego.)
El timestep fijo se consigue... fijándolo. En definitiva: tu bucle del juego no actúa hasta que no haya pasado un tiempo fijo (en XNA si no me equivoco por defecto son 16.6ms, es decir 60FPS.) Lo que haces es, mientras que el bucle se esté ejecutando y no llegue a esos 16.6ms simplemente lo ignoras y vas sumando el deltaTime en un acumulador. Una vez ese acumulador llegue a 16.6ms ya haces los cálculos pertinentes con ese deltaTime fijo.
Se presenta un caso, y es... ¿qué pasa si en el último "intento de frame" te quedas a 15.6ms y en el siguiente llegas, por ejemplo a 17.6ms? Pues que ese milisegundo que te sobra lo guardas para el acumulador para el próximo marco de juego (por lo que el deltaTime no queda a 0 al terminar la ejecución, si no a 1.)
¿Cuáles son las ventajas de hacer esto? Pues como decía antes, no es lo mismo integrar dos veces 1ms que integrar una sóla vez 2ms. ¿Qué significa esto? Pues que la simulación de tu juego dependerá POR COJONES del timeStep que vaya pasando en cada iteración, y por tanto la simulación será diferente en cada ejecución.
Para un Pong da completamente igual porque no vas a ver apenas diferencias, pero recuerda que los errores se acumulan.
¿Y qué más dará? Me dirás. Pues piensa por ejemplo que quieres hacer un sistema de grabación del partido (ej. el HLTV del Counter-Strike) o que tu juego requiere volver atrás en el tiempo (ej. el control del tiempo en Braid.) En ese caso necesitas que el timeStep sea fijo para que:
- En todas las máquinas se vea igual.
- Entre dos ejecuciones, el estado en t(n) sea el mismo dado un n.
Lo mismo para un sistema de juego en red.
(A partir de aquí caca aleatoria que no tiene que ver del todo.)
De hecho esto da muchos problemas y es la razón por la que haya problemas cuando juegas entre varias arquitecturas y fue lo que llevó al traste uno de mis proyectos.
Entre varias máquinas los números en coma flotante no tienen por qué dar lo mismo (por tema de redondeos, bits de guarda, precisión extra en estados intermedios, etc.) Los errores se acumulan, por lo que varias máquinas acababan viendo un estado del juego completamente diferente.
Esto hace que, una de dos, o haces que uno de los dos sistemas sea autoritativo (malo) y corrija a capón los "errores" del otro o usas matemática en coma fija (definida por ti, por lo que el resultado es determinista.)