Quiero que ocurra algo cada N segundos, ¿cómo haría eso? Tal vez use un temporizador, pero ¿cómo?
Quiero que ocurra algo cada N segundos, ¿cómo haría eso? Tal vez use un temporizador, pero ¿cómo?
Respuestas:
Un enfoque común para esto es usar el ciclo de actualización y el tiempo delta.
float timerCurrent = 0f;
float timerTotal = 5f;
Update() {
timerCurrent += deltaTime;
if(timerCurrent >= timerTotal) {
//do timer action
timerCurrent -= timerTotal;
}
}
Esto supone que tiene acceso a una deltaTime
variable. El tiempo delta es simplemente el tiempo transcurrido desde el último fotograma. Muchos motores tendrán esto a su disposición, o puede obtener más información sobre cómo configurar el suyo aquí .
En la mayoría de los idiomas, debe iniciar el reloj con algún tipo de llamada a la función clock.startTimer()
antes de ingresar al bucle principal. Luego, debe almacenar el valor de la hora del reloj antes de ingresar el bucle principal en una variable con una función como time = clock.getTime()
. Almacene su tiempo de paso en variable n
.
En su bucle principal, la verificación que desea hacer es algo similar a
if(time + n <= clock.getTime())
//do stuff
time = clock.getTime() //important to assign new time value here
Nota: no estoy seguro de qué idioma / biblioteca estás viendo, así que este es solo un algoritmo genérico que pensé en la parte superior de mi cabeza. Puede que no se adapte exactamente a sus necesidades. Algunos idiomas / bibliotecas requieren que cree un objeto de reloj, mientras que otros simplemente puede hacer una llamada de función directamente.
Según los comentarios a continuación, debe tener cuidado con los problemas de subprocesos según el idioma que esté utilizando. También debe usar un flotador doble para almacenar time
.
time
va a almacenar el tiempo transcurrido del juego, debe usar un formato de punto flotante de doble precisión.
Como ya señalaron otras respuestas, la implementación de un temporizador se puede hacer incrementando un valor almacenado por cada cuadro deltaTime
y comparándolo con la duración esperada. Para completar, incluiré código que es muy similar a las otras respuestas:
float elapsed = 0.0f;
float duration = 4.0f;
void update(float deltaTime) {
elapsed += deltaTime;
if (elapsed <= duration) {
// Run code.
elapsed = 0.0f;
// Maybe remove from update loop?
}
}
La forma en que desea manejar la // Run code.
porción depende de usted. Tal vez tenga una Timer
clase, una instancia de la cual toma un delegate
(C #) o un callback
(C ++) y la llama cuando expira el temporizador. Además, pausar el temporizador es cuestión de eliminarlo del ciclo de actualización.
Un enfoque alternativo es marcar el tiempo de inicio del temporizador y, en su lugar, hacer un cálculo bajo demanda del tiempo transcurrido:
double startTime = 0.0; // This is a double for a reason, I'll explain below.
bool running = false;
void start() {
startTime = getTime(); // This is whatever system time call you want to use.
running = true;
}
double getElapsed() {
double elapsed = getTime() - startTime;
return elapsed;
}
Este estilo le da un poco más de control al usuario del temporizador. La estructura en sí no se preocupa por qué hacer cuando el tiempo transcurrido alcanza un cierto punto; Ni siquiera está actualizando. El usuario simplemente puede consultar el tiempo transcurrido cuando sea necesario. Este patrón tiene el desafortunado efecto secundario de no ser amigable con el depurador. La hora del sistema continúa a medida que su programa se detiene en un depurador, por lo que los temporizadores como este se comportarán de manera diferente al recorrer los programas. Una posible solución para eso es mantener un valor de tiempo transcurrido específico del programa que se actualiza cada cuadro utilizando deltas de tiempo del sistema.
Sin embargo, creo que lo más importante son dos peculiaridades del tiempo en una computadora, especialmente cuando se trata del desarrollo de juegos. El primero es la precisión de coma flotante y el segundo es la resolución nativa del temporizador.
Notarás que en el segundo ejemplo, usé un double
tipo en lugar de un float
, como en el primer ejemplo (el nombre del tipo, por supuesto, depende del idioma que estés usando). La razón de esto es que el segundo ejemplo es almacenar el tiempo total transcurrido del juego . Si el juego se deja en funcionamiento durante mucho tiempo, los valores de formato de punto flotante de precisión simple tendrán una precisión insuficiente para medir con precisión el tiempo transcurrido , lo que provocará problemas de estabilidad. El primer ejemplo está bien usando el float
tipo siempre que no se esperen duraciones enormes.
En el otro extremo del espectro, si el tiempo de actualización que espera es lo suficientemente pequeño, es posible que no pueda lograrlo inicialmente, dependiendo de cómo obtenga la hora del sistema. Los temporizadores a menudo dependerán de la resolución del temporizador del sistema operativo en el que se está ejecutando. Por ejemplo, la resolución predeterminada del temporizador de Windows 7 e inferior es de 15,6 ms . Esto significa que la precisión de temporizador más baja que podría lograr utilizando funciones como timeGetTime
o GetTickCount
, es de 15.6 ms, a menos que cambie la resolución del temporizador (también hay peligros asociados con eso).
Bueno, eso resultó un poco largo, pero estas son cosas importantes a tener en cuenta al implementar temporizadores.