"Super Meat Boy" es un juego de plataformas difícil que recientemente salió para PC, que requiere un control excepcional y saltos perfectos en píxeles. El código de física en el juego depende de la velocidad de fotogramas, que está bloqueada a 60 fps; Esto significa que si tu computadora no puede ejecutar el juego a toda velocidad, la física se volverá loca, causando (entre otras cosas) que tu personaje corra más lento y caiga por el suelo. Además, si vsync está desactivado, el juego se ejecuta extremadamente rápido.
¿Podrían los expertos en programación de juegos en 2D ayudar a explicar por qué el juego se codificó de esta manera? ¿No sería un bucle de física funcionando a una velocidad constante una mejor solución? (En realidad, creo que se usa un bucle de física para partes del juego, ya que algunas de las entidades continúan moviéndose normalmente independientemente de la velocidad de fotogramas. Tu personaje, por otro lado, corre exactamente [fps / 60] tan rápido).
Lo que me molesta de esta implementación es la pérdida de abstracción entre el motor del juego y la representación gráfica, que depende de elementos específicos del sistema, como el monitor, la tarjeta gráfica y la CPU. Si, por alguna razón, su computadora no puede manejar vsync, o no puede ejecutar el juego exactamente a 60 fps, se romperá espectacularmente. ¿Por qué el paso de representación influye de alguna manera en los cálculos físicos? (La mayoría de los juegos de hoy en día ralentizarían el juego o se saltearían marcos). Por otro lado, entiendo que los juegos de plataformas de la vieja escuela en NES y SNES dependían de una tasa de cuadros fija para gran parte de su control y física. ¿Por qué es esto, y sería posible crear un patrón en esa línea sin tener la dependencia de framerate? ¿Hay necesariamente una pérdida de precisión si separa la representación gráfica del resto del motor?
Gracias, y lo siento si la pregunta fue confusa.
Respuestas:
Un puñado de razones, elige: no sabían nada mejor. Es más rápido y fácil de implementar. Se centraron más en el juego y menos en los casos extremos que podrían no surgir en la mayoría de los casos.
Hiciste un trabajo bastante bueno al explicar por qué no. Estoy seguro de que has notado que hay muchos temas que cubren el tema . No estoy seguro de que encuentre una respuesta satisfactoria más allá de las que mencioné.
fuente
SMB era originalmente un juego de consola en el que es seguro asumir que es capaz de ejecutarse a 60 fps en todos los Xbox360 (bueno, tal vez 50 para algunos jugadores PAL). Asumir un paso de tiempo fijo simplifica un poco el código.
Si bien es fácil escalar muchas cosas por un paso de tiempo variable: 'pos + = velocidad * paso de tiempo', se vuelve bastante difícil hacerlo correctamente cuando se trata de aceleraciones y tasas de cambio de aceleración, y así sucesivamente.
Desacoplar el juego y el renderizado es una buena solución en teoría , pero implementarlo bien (con una buena interpolación) es bastante complicado, y las cosas pueden complicarse fácilmente. Es bastante raro que esta técnica se use en juegos reales (aunque algunos grandes juegos lo hacen, particularmente los juegos RTS, pero más para la sincronización de juegos en red).
Al diseñar también para una resolución de pantalla fija y una velocidad de fotogramas fija, hay otra cosa que puede hacer para que el desplazamiento sea más suave. Puedes asegurarte de que el juego se desplaza a un número entero de píxeles por fotograma, evitando cualquier `` oscilación de subpíxeles '' que puedas obtener al desplazar un número fraccionario de píxeles por fotograma.
fuente
La solución obvia es tener 2 bucles ejecutándose en paralelo: el renderizado cada 1/60 de segundo y el bucle del juego cada 1/60 de segundo.
Pero con mi experiencia en Flash (AS3, en la que estoy seguro de que se creó Super Meat Boy), el programador no siempre es muy preciso. La precisión también depende en gran medida del medio ambiente. En el reproductor flash independiente, puede tener una resolución inferior a milisegundos. Pero cuando se ejecuta en algunos navegadores web, su precisión se convierte en la de la velocidad de fotogramas.
Entonces, la forma más cercana de desacoplar los bucles de renderizado y lógica del juego es hacer que todos los movimientos se basen en el tiempo (y ejecutar cada fotograma en función del tiempo transcurrido desde el último fotograma). Eso puede introducir algunas matemáticas más complicadas (como hacer que la gravedad se aplique de forma continua, en lugar de aumentar la velocidad de un objeto a intervalos establecidos). Debido a que el juego podría retrasarse por un segundo y luego su jugador se movería 200 píxeles en un solo paso, la detección y respuesta de colisión puede ser aún más complicada. Si el programador estaba haciendo una detección de colisión basada en cuadros (buscando una colisión cada vez), también tendrían que cambiar a la detección de colisión basada en el tiempo. Y si quisieran que se sintiera natural, tendrían que usar el método de gravedad descrito anteriormente, que hace que el movimiento del objeto sea una curva (en lugar de una línea),
fuente
No creo que sea mucho pedir más juegos 2D para PC para jugar a 60 fps. Incluso la mayoría de los juegos 2D están acelerados por hardware ahora, así que personalmente no me preocuparía por el requisito de fps.
La verdadera pregunta es por qué no usarías un píxel, los juegos están llenos de trucos y atajos.
Si estás haciendo un juego basado en la física (¿quizás lanzar pájaros?) La respuesta es obvia, pero ¿un clon de super mario? movimiento basado en el tiempo puede ser un poco demasiado.
fuente
¿Para evitar comportamientos extraños en la física 2D que están usando?
Honestamente, solo puedo adivinar. Probaré una explicación:
En el corazón del juego está el bucle principal del juego. Que básicamente se ve así:
updateGame actualiza gameState: comprueba la entrada del jugador, aplica la entrada del jugador al mundo del juego y ejecuta la simulación física, etc.
renderGame dibuja y anima el juego.
Esto combina la actualización física con el renderizado. Si desea desacoplarlo, necesitaría usar hilos y sincronizar adecuadamente cada acceso de datos de la representación y el hilo de GameUpdate a los datos compartidos, por ejemplo, la posición del jugador. Esto puede hacerse.
Otro problema podría ser que la simulación física requiere un paso de tiempo constante para funcionar de manera estable. Esto depende de cómo Supermeatboy calcula el movimiento (Nuevamente, podemos adivinar cómo lo han hecho;)).
Un enfoque ingenuo sería (que estoy usando en mi juego * suspiro *):
Esto se llama integración de Euler y generalmente se considera una mala idea. Si el paso de tiempo es no constante, se producen errores de cálculo que harán que la simulación sea menos estable. El objeto puede moverse a velocidades excesivas o no todos o volar a través de las paredes fuera de la pantalla. Incluso si el paso de tiempo es constante, la integración de Euler causa errores menores de cálculo. Mejor use otro método de integración como RK4 o use un motor de física.
Aparte de eso, puede haber problemas para hacer la detección de colisión si el paso de tiempo es demasiado grande. Como las colisiones no se verifican entre dos actualizaciones del juego, los objetos pueden pasar por obstáculos.
fuente