Tengo algunos programas antiguos que saqué de una computadora Windows de principios de los 90 e intenté ejecutarlos en una computadora relativamente moderna. Curiosamente, corrieron a una velocidad increíblemente rápida: no, no el tipo de velocidad de 60 fotogramas por segundo, sino el tipo de oh-my-god-the-character-is-walking-at-the-speed-of-sound rápido. Presionaría una tecla de flecha y el sprite del personaje se deslizaría por la pantalla mucho más rápido de lo normal. La progresión del tiempo en el juego sucedía mucho más rápido de lo que debería. Incluso hay programas creados para ralentizar su CPU para que estos juegos sean realmente jugables.
He oído que esto está relacionado con el juego dependiendo de los ciclos de la CPU, o algo así. Mis preguntas son:
- ¿Por qué los juegos más antiguos hacen esto y cómo se salieron con la suya?
- ¿Cómo los juegos más nuevos no hacen esto y se ejecutan independientemente de la frecuencia de la CPU?
FOR F IN 0 TO 1000; NEXT F;
Respuestas:
Creo que asumieron que el reloj del sistema funcionaría a una velocidad específica, y vincularon sus temporizadores internos a esa velocidad de reloj. La mayoría de estos juegos probablemente se ejecutaban en DOS, y eran en modo real (con acceso completo y directo al hardware) y suponían que estaba ejecutando un sistema iirc de 4.77 MHz para PC y cualquier procesador estándar que ese modelo ejecutara para otros sistemas como el Amiga.
También tomaron atajos inteligentes basados en esos supuestos, incluido el ahorro de un poco de recursos al no escribir bucles de temporización internos dentro del programa. También tomaron tanta potencia de procesador como pudieron, lo cual fue una idea decente en los días de chips lentos, a menudo pasivamente enfriados.
Inicialmente, una forma de sortear diferentes velocidades de procesador era el viejo y bueno botón Turbo (que ralentizaba su sistema). Las aplicaciones modernas están en modo protegido y el sistema operativo tiende a administrar recursos: no permitirían que una aplicación de DOS (que se ejecuta en NTVDM en un sistema de 32 bits de todos modos) use todo el procesador en muchos casos. En resumen, los sistemas operativos se han vuelto más inteligentes, al igual que las API.
Basada en esta guía en Oldskool PC donde la lógica y la memoria me fallaron, es una gran lectura, y probablemente profundiza en el "por qué".
Cosas como CPUkiller utilizan tantos recursos como sea posible para "ralentizar" su sistema, lo cual es ineficiente. Sería mejor usar DOSBox para administrar la velocidad del reloj que ve su aplicación.
fuente
game loop
. Básicamente hay 2 métodos. 1) Corre lo más rápido posible y escala las velocidades de movimiento, etc., según la rapidez con la que se ejecute el juego. 2) Si eres demasiado rápido, espera (sleep()
) hasta que estemos listos para el próximo 'tic'.Como una adición a la respuesta de Journeyman Geek (porque mi edición fue rechazada) para las personas interesadas en la parte de codificación / perspectiva del desarrollador:
Desde la perspectiva de los programadores, para aquellos que estén interesados, los tiempos de DOS fueron momentos en los que cada tic de CPU era importante, por lo que los programadores mantuvieron el código lo más rápido posible.
Un escenario típico donde cualquier programa se ejecutará a la velocidad máxima de la CPU es este simple (pseudo C):
esto se ejecutará para siempre, ahora, vamos a convertir este fragmento de código en un juego pseudo-DOS:
a menos que las
DrawGameOnScreen
funciones utilicen doble búfer / sincronización V (que era un poco costoso en los días en que se creaban los juegos de DOS), el juego se ejecutará a la velocidad máxima de la CPU. En un i7 móvil moderno, esto funcionaría entre 1,000,000 y 5,000,000 veces por segundo (dependiendo de la configuración de la computadora portátil y el uso actual de la CPU).Esto significaría que si pudiera hacer que un juego de DOS funcione en mi CPU moderna en mis ventanas de 64 bits, podría obtener más de mil (1000) FPS, que es demasiado rápido para que cualquier humano lo juegue si el procesamiento de física "asume" que se ejecuta entre 50-60 fps.
Lo que los desarrolladores actuales (pueden) hacer es:
*** dependiendo de la configuración de la tarjeta gráfica / controlador / sistema operativo puede ser posible.
Para el punto 1 no hay ningún ejemplo que mostraré porque en realidad no es ninguna "programación". Solo está usando las características gráficas.
En cuanto a los puntos 2 y 3, mostraré los fragmentos de código y las explicaciones correspondientes:
2:
Aquí puede ver la entrada del usuario y la física teniendo en cuenta la diferencia horaria, pero aún puede obtener más de 1000 FPS en la pantalla porque el ciclo se ejecuta lo más rápido posible. Debido a que el motor de física sabe cuánto tiempo pasó, no tiene que depender de "ninguna suposición" o "cierta velocidad de cuadros", por lo que el juego funcionará a la misma velocidad en cualquier CPU.
3:
Lo que los desarrolladores pueden hacer para limitar la velocidad de cuadros a, por ejemplo, 30 FPS en realidad no es nada más difícil, solo eche un vistazo:
Lo que sucede aquí es que el programa cuenta cuántos milisegundos han pasado, si se alcanza una cierta cantidad (33 ms), vuelve a dibujar la pantalla del juego, aplicando efectivamente una velocidad de fotogramas cercana a ~ 30.
Además, dependiendo del desarrollador, él / ella puede elegir limitar TODO el procesamiento a 30 fps con el código anterior ligeramente modificado para esto:
Hay algunos otros métodos, y algunos de ellos realmente los odio.
Por ejemplo, usando
sleep(<amount of milliseconds>)
.Sé que este es un método para limitar la velocidad de fotogramas, pero ¿qué sucede cuando el procesamiento de tu juego tarda 3 milisegundos o más? Y luego ejecutas el sueño ...
esto dará como resultado una velocidad de fotogramas más baja que la que solo
sleep()
debería estar causando.Tomemos por ejemplo un tiempo de sueño de 16 ms. esto haría que el programa se ejecute a 60 hz. ahora el procesamiento de los datos, la entrada, el dibujo y todo lo demás lleva 5 milisegundos. Estamos a 21 milisegundos para un ciclo ahora, lo que resulta en un poco menos de 50 hz, mientras que fácilmente podría estar a 60 hz, pero debido al sueño es imposible.
Una solución sería hacer un sueño adaptativo en forma de medir el tiempo de procesamiento y deducir el tiempo de procesamiento del sueño deseado, lo que da como resultado la reparación de nuestro "error":
fuente
Una causa principal es usar un bucle de retardo que se calibra cuando se inicia el programa. Cuentan cuántas veces se ejecuta un bucle en una cantidad de tiempo conocida y lo dividen para generar retrasos más pequeños. Esto se puede usar para implementar una función sleep () para acelerar la ejecución del juego. Los problemas surgen cuando este contador se maximiza debido a que los procesadores son mucho más rápidos en el ciclo que el pequeño retraso termina siendo demasiado pequeño. Además, los procesadores modernos cambian la velocidad en función de la carga, a veces incluso por núcleo, lo que hace que el retraso se reduzca aún más.
Para los juegos de PC realmente antiguos, simplemente corrían tan rápido como podían sin importar el ritmo del juego. Este fue más el caso en los días de IBM PC XT, sin embargo, donde existía un botón turbo que ralentizaba el sistema para que coincida con un procesador de 4.77 mhz por este motivo.
Los juegos y bibliotecas modernas como DirectX tienen acceso a temporizadores de alta precesión, por lo que no es necesario utilizar bucles de retardo basados en código calibrado.
fuente
Al principio, todas las primeras PC funcionaban a la misma velocidad, por lo que no era necesario tener en cuenta la diferencia de velocidades.
Además, muchos juegos al principio tenían una carga de CPU bastante fija, por lo que era poco probable que algunos cuadros se ejecuten más rápido que otros.
Hoy en día, con sus niños y sus sofisticados tiradores de FPS, puede mirar al piso un segundo y al Gran Cañón al siguiente, la variación de carga ocurre con más frecuencia. :)
(Y, pocas consolas de hardware son lo suficientemente rápidas para ejecutar juegos a 60 fps constantemente. Esto se debe principalmente al hecho de que los desarrolladores de consolas optan por 30 Hz y hacen que los píxeles sean dos veces más brillantes ...)
fuente