Quero que algo aconteça a cada N segundos, como eu faria isso? Talvez use um temporizador, mas como?
Quero que algo aconteça a cada N segundos, como eu faria isso? Talvez use um temporizador, mas como?
Respostas:
Uma abordagem comum para isso é usar o loop de atualização e o tempo delta.
float timerCurrent = 0f;
float timerTotal = 5f;
Update() {
timerCurrent += deltaTime;
if(timerCurrent >= timerTotal) {
//do timer action
timerCurrent -= timerTotal;
}
}
Isso supõe que você tenha acesso a uma deltaTime
variável. O tempo delta é simplesmente o tempo decorrido desde o último quadro. Muitos mecanismos terão isso disponível para você, ou você pode aprender mais sobre como configurar seu próprio aqui .
Na maioria dos idiomas, você precisa iniciar o relógio com algum tipo de chamada de função ao longo das linhas clock.startTimer()
antes de inserir o loop principal. Então, você deve armazenar o valor da hora do relógio antes de inserir o loop principal em uma variável com uma função como time = clock.getTime()
. Armazene seu tempo de etapa em variável n
.
No loop principal, a verificação que você deseja fazer é algo parecido com o
if(time + n <= clock.getTime())
//do stuff
time = clock.getTime() //important to assign new time value here
Nota: Não sei ao certo qual idioma / biblioteca você está procurando, então esse é apenas um algoritmo genérico que eu pensei em cima da minha cabeça. Pode não atender exatamente às suas necessidades. Alguns idiomas / bibliotecas exigem que você crie um objeto de relógio, enquanto outros podem simplesmente fazer uma chamada de função diretamente.
Conforme os comentários abaixo, você deve ter cuidado com os problemas de segmentação, dependendo do idioma que está usando. Você também deve usar um flutuador duplo para armazenar time
.
time
tempo decorrido do jogo for armazenado, ele deverá usar um formato de ponto flutuante de precisão dupla.
Como outras respostas já apontadas, a implementação de um cronômetro pode ser feita incrementando um valor armazenado por cada quadro deltaTime
e comparando-o com a duração esperada. Para garantir a integridade, incluirei código muito semelhante às outras respostas:
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?
}
}
A decisão de como você deseja lidar com a // Run code.
parte é sua. Talvez você tenha uma Timer
classe, cuja instância usa um delegate
(C #) ou um callback
(C ++) e a chama quando o cronômetro expira. Além disso, pausar o timer é uma questão de removê-lo do loop de atualização.
Uma abordagem alternativa é marcar o horário de início do cronômetro e, em vez disso, fazer um cálculo sob demanda do tempo decorrido:
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;
}
Esse estilo dá um pouco mais de controle ao usuário do timer. A estrutura em si não está preocupada com o que fazer quando o tempo decorrido atingir um determinado ponto; nem está atualizando. O usuário pode simplesmente consultar o tempo decorrido quando necessário. Esse padrão tem o efeito colateral lamentável de não ser amigável ao depurador. A hora do sistema continua quando seu programa é interrompido em um depurador, portanto, temporizadores como esse se comportam de maneira diferente ao percorrer os programas. Uma solução potencial para isso é manter um valor de tempo decorrido específico do programa que é atualizado a cada quadro usando deltas de hora do sistema.
Eu acho que o mais importante são duas peculiaridades do tempo em um computador, especialmente quando se trata de desenvolvimento de jogos. O primeiro é a precisão do ponto flutuante e o segundo é a resolução nativa do timer.
Você notará que no segundo exemplo, usei um double
tipo em vez de a float
, como no primeiro exemplo (o nome do tipo de curso depende do idioma que você está usando). A razão para isso é o segundo exemplo: o tempo total decorrido do jogo . Se o jogo permanecer em execução por muito tempo, os valores no formato de ponto flutuante de precisão única terão precisão insuficiente para medir com precisão o tempo decorrido , causando problemas de estabilidade. O primeiro exemplo é bom usando o float
tipo, desde que não sejam esperadas durações enormes.
No outro extremo do espectro, se o tempo de atualização esperado for pequeno o suficiente, talvez você não consiga alcançá-lo inicialmente, dependendo de como você obtém o tempo do sistema. Os temporizadores geralmente dependem da resolução do temporizador do sistema operacional em que você está executando. Por exemplo, a resolução padrão do timer do Windows 7 e abaixo é de 15,6 ms . Isso significa que a menor precisão do timer que você pode obter usando funções como timeGetTime
ou GetTickCount
é 15,6 ms, a menos que você altere a resolução do timer (também existem perigos associados a isso).
Bem, isso ficou um pouco longo, mas essas são coisas importantes a serem observadas ao implementar temporizadores.