Me preguntaba si hay algún daño posible cuando mi ciclo de juego se ejecuta tan rápido como el sistema lo permite.
Actualmente tengo un bucle que, al medir el tiempo transcurrido en nanosegundos, ejecuta la lógica del juego y la lógica de representación a velocidades predefinidas sin ningún problema. De hecho, cualquier lógica que hago en el bucle se sincroniza con una cierta cantidad de llamadas cada segundo.
Sin embargo, el bucle en sí solo funciona tan rápido como le gusta, lo que equivale a alrededor de 11.7 millones de bucles por segundo en mi máquina.
Bucle (pseudocódigo simple):
while(!isGameOver){
if(canPollInputs){
pollInputs()
}
while(canStepLogic){
stepLogic()
}
if(canRender){
render()
}
}
Mi pregunta es, básicamente, si ese simple bucle, si no está funcionando a una velocidad controlada, ¿puede causar algún daño a un sistema?
Editar: Eso significa que mi lógica se está ejecutando 30 veces por segundo (30 tps), mi procesador se está ejecutando a 60 fps, estoy sondeando entradas a 100 veces por segundo y también hay algo de lógica para hacer frente a la lógica o hacer que el procesamiento tarde más de lo esperado . Pero el bucle en sí no está estrangulado.
Editar: usar, Thread.sleep()
por ejemplo, Acelerar el bucle principal hasta 250 bucles por segundo conduce a una reducción, pero los bucles se ejecutan a alrededor de 570 bucles por segundo en lugar de los 250 deseados (agregaré código cuando estoy en mi máquina de escritorio ...)
Editar: Aquí vamos, un gameloop de Java que funciona para aclarar las cosas. También siéntase libre de usarlo, pero no lo reclame como suyo;)
private void gameLoop() {
// Time that must elapse before a new run
double timePerPoll = 1000000000l / targetPPS;
double timePerTick = 1000000000l / targetTPS;
double timePerFrame = 1000000000l / targetFPS;
int maxFrameSkip = (int) ( (1000000000l / MINIMUM_FPS) / timePerTick);
int achievedPPS = 0;
int achievedFPS = 0;
int achievedTPS = 0;
long timer = TimeUtils.getMillis();
int loops = 0;
int achievedLoops = 0;
long currTime = 0l;
long loopTime = 0l;
long accumulatorPPS = 0l;
long accumulatorTPS = 0l;
long accumulatorFPS = 0l;
long lastTime = TimeUtils.getNano();
while(!isRequestedToStop) {
currTime = TimeUtils.getNano();
loopTime = currTime - lastTime;
lastTime = currTime;
loops = 0;
accumulatorPPS += loopTime;
accumulatorTPS += loopTime;
accumulatorFPS += loopTime;
if(accumulatorPPS >= timePerPoll) {
pollInputs();
playerLogic();
achievedPPS++;
accumulatorPPS -= timePerPoll;
}
while(accumulatorTPS >= timePerTick && loops < maxFrameSkip) {
tick();
achievedTPS++;
accumulatorTPS -= timePerTick;
loops++;
}
// Max 1 render per loop so player movement stays fluent
if(accumulatorFPS >= timePerFrame) {
render();
achievedFPS++;
accumulatorFPS -= timePerFrame;
}
if(TimeUtils.getDeltaMillis(timer) > 1000) {
timer += 1000;
logger.debug(achievedTPS + " TPS, " + achievedFPS + " FPS, "
+ achievedPPS + " Polls, " + achievedLoops + " Loops");
achievedTPS = 0;
achievedFPS = 0;
achievedLoops = 0;
}
achievedLoops++;
}
}
Como puede ver, casi no hay código ejecutado en cada ciclo, pero siempre hay una cierta selección basada en la cantidad de tiempo real que ha pasado. La pregunta se refiere a ese "ciclo de trabajo" y cómo influye en el sistema.
fuente
Respuestas:
Hará que un núcleo de CPU se ejecute siempre al 100%. Esto generalmente no causa ningún daño al sistema. Las CPU están diseñadas para funcionar al 100% durante horas. Pero en un dispositivo móvil agotará la batería rápidamente y calentará el dispositivo, lo que probablemente le costará unas estrellas en las clasificaciones de su tienda. En una computadora de escritorio esto no es un problema, pero consumirá más electricidad de los usuarios, hace que el ventilador de la CPU gire más rápido, lo que podría causar algo de ruido y desperdiciar ciclos de la CPU que de otro modo podrían ser utilizados por otros procesos. Si bien estos no son defectos críticos, siguen siendo de mal estilo, por lo que debe evitarlos cuando sea posible.
No dijiste nada acerca de cómo funciona el bucle lógico del juego internamente, pero cuando estás usando el enfoque delta-time (cada cálculo que estás haciendo toma el tiempo desde la última llamada en cuenta), estás lidiando con un delta muy pequeño. valores de tiempo Esto significa que puede tener problemas con la inexactitud de punto flotante que puede causar todo tipo de comportamientos extraños. Además, la resolución del temporizador del sistema a menudo es limitada, por lo que cuando su bucle lógico es demasiado rápido, puede obtener un valor delta-t de cero, lo que podría causar una división por cero que provocaría un bloqueo.
Para mitigar este problema, debe limitar su velocidad de cuadros (gráfica y lógica) al máximo de lo que el ojo humano puede percibir. Cuánto se disputa y depende del tipo de animación y del tipo de visualización que se muestra, pero las estimaciones oscilan entre 40 FPS y 120 FPS. Eso significa que debe establecer un tiempo mínimo de ejecución de cada ciclo entre 20 ms y 8 ms. Si una iteración de bucle termina más rápido, deje que la CPU se enhebre
sleep
durante el tiempo restante.fuente
Estás desperdiciando ciclos de CPU. Eso significa menos tiempo de batería en computadoras portátiles, tabletas y teléfonos, facturas de electricidad más altas, más calor generado por la máquina, ventiladores más ruidosos. Además, es posible que comas ciclos de otros procesos importantes del sistema (por ejemplo, el servidor de la ventana podría volverse irregular), lo que podría afectar el juego. Algunos programadores de sistemas en los sistemas multitarea preventivos de hoy también penalizan las aplicaciones que usan demasiados ciclos, por lo que puede ser rápido primero, y luego repentinamente ver extrañas sacudidas cuando el sistema lo estrangula.
Muchos jugadores incondicionales también construyen PC personalizadas desde cero que están al borde de las especificaciones de sus fanáticos, en cuyo caso un día caluroso y el calor que genera su juego pueden causar que las seguridades se activen en la máquina (en el mejor de los casos) o incluso sobrecalentar las piezas y morir (en el peor de los casos). Entonces, si ese es su público objetivo, es posible que desee asegurarse de que siempre deja un poco de espacio "en la parte superior".
Finalmente, hay problemas de juego en los que podrías estar beneficiando a los jugadores con máquinas más rápidas que a las que tienen máquinas más lentas. Tener el ciclo del juego limitado a una determinada frecuencia y usar ciclos adicionales únicamente para aspectos que no son relevantes para el juego (como renderizar gráficos de mayor fidelidad, efectos de sonido envolvente o lo que sea) hará que su juego sea más justo.
fuente
No deberías tener movimientos nerviosos / jugabilidad
Hay dos formas de implementar la lógica del juego: vinculada a un tiempo real o vinculada a la cantidad de "turnos" / pasos de procesamiento. Si alguna cosa en su juego se mueve hacia la izquierda, ¿será diferente si su stepLogic () se llamó 100 en lugar de 50 veces?
Si su código trata el tiempo transcurrido explícitamente en todas partes y lo hace correctamente, entonces podría estar bien; pero si hay algo en su código que depende de la cantidad de "pasos", obtendrá efectos secundarios no deseados.
Primero, la velocidad de las cosas que deberían moverse constantemente variará de manera impredecible (dependiendo del uso del procesador), y esto hace que los controles sean muy molestos: no puedes dar un golpe preciso o un salto si de repente el juego se acelera o se ralentiza. Incluso para juegos sin 'twitch' en absoluto, se ve molesto y nervioso si las cosas no se mueven bien.
En segundo lugar, es posible que tengas problemas con las habilidades de los personajes dependiendo de la velocidad de la computadora; un ejemplo clásico es el viejo problema de Quake, donde el rango de salto máximo dependía involuntariamente de tus fps.
Estos problemas pueden aparecer incluso si intenta que el código sea independiente de fps, la acumulación de errores de redondeo a menudo puede causar tales errores.
fuente
El único daño potencial es su consumo de energía, así que no lo haga en dispositivos móviles. Por el contrario, bastantes sistemas integrados pasan toda su vida en un bucle esperando que sucedan cosas.
Solía ser completamente normal simplemente renderizar los marcos del juego lo más rápido posible, a veces sin siquiera un temporizador para compensar el juego por diferentes velocidades de CPU. El juego de carreras de Bullfrog Hi-Octane fue una víctima particularmente mala de esto, y sospecho que esto es a lo que se refiere el afiche que menciona Civ2.
Le recomiendo al menos sondear las entradas en cada pase si está en un sistema Windows o similar, para garantizar una respuesta de entrada rápida.
fuente
swap
/present
/flip
hacer la espera en la señal vsync, para regular el ciclo del juego.