Je veux que quelque chose se passe toutes les N secondes, comment dois-je faire? Peut-être utiliser une minuterie mais comment?
Je veux que quelque chose se passe toutes les N secondes, comment dois-je faire? Peut-être utiliser une minuterie mais comment?
Réponses:
Une approche courante consiste à utiliser la boucle de mise à jour et l'heure delta.
float timerCurrent = 0f;
float timerTotal = 5f;
Update() {
timerCurrent += deltaTime;
if(timerCurrent >= timerTotal) {
//do timer action
timerCurrent -= timerTotal;
}
}
Cela suppose que vous ayez accès à une deltaTime
variable. Le temps delta est simplement le temps qui s'est écoulé depuis la dernière image. De nombreux moteurs auront cela à votre disposition, ou vous pouvez en savoir plus sur la configuration de votre propre ici .
Dans la plupart des langues, vous devez démarrer l'horloge avec une sorte d'appel de fonction dans le sens de clock.startTimer()
avant d'entrer dans la boucle principale. Ensuite, vous devez stocker la valeur de l'heure avant d'entrer dans la boucle principale dans une variable avec une fonction comme time = clock.getTime()
. Stockez votre temps de pas dans une variable n
.
Dans votre boucle principale, la vérification que vous voulez faire est quelque chose comme
if(time + n <= clock.getTime())
//do stuff
time = clock.getTime() //important to assign new time value here
Remarque: je ne suis pas sûr de la langue / bibliothèque que vous regardez, donc ce n'est qu'un algorithme générique auquel j'ai pensé du haut de ma tête. Il peut ne pas répondre exactement à vos besoins. Certaines langues / bibliothèques nécessitent que vous créiez un objet horloge tandis que d'autres vous permettent simplement de faire un appel de fonction directement.
Selon les commentaires ci-dessous, vous devez faire attention aux problèmes de threading en fonction de la langue que vous utilisez. Vous devez également utiliser un flotteur double pour stocker time
.
time
va stocker le temps de jeu écoulé, il doit utiliser un format à virgule flottante double précision.
Comme d'autres réponses l'ont déjà souligné, la mise en œuvre d'un temporisateur peut être effectuée en incrémentant une valeur stockée par chaque trame deltaTime
et en la comparant à la durée attendue. Pour être complet, je vais inclure du code qui est très similaire aux autres réponses:
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 façon dont vous voulez gérer la // Run code.
portion dépend de vous. Peut-être que vous avez une Timer
classe, dont une instance prend un delegate
(C #) ou un callback
(C ++) et l'appelle lorsque le temporisateur expire. En outre, la pause du minuteur consiste à le supprimer de la boucle de mise à jour.
Une autre approche consiste à marquer l'heure de début de la minuterie et à la place faire un calcul à la demande du temps écoulé:
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;
}
Ce style donne un peu plus de contrôle à l'utilisateur de la minuterie. La structure elle-même n'est pas concernée par ce qu'il faut faire lorsque le temps écoulé atteint un certain point; ce n'est même pas une mise à jour. L'utilisateur peut simplement interroger le temps écoulé lorsque cela est nécessaire. Ce modèle a pour effet secondaire malheureux de ne pas être compatible avec le débogueur. L'heure du système continue pendant que votre programme est arrêté sur un débogueur, donc les temporisateurs comme celui-ci se comporteront différemment lors de la navigation dans les programmes. Une solution potentielle à cela est de maintenir une valeur de temps écoulé spécifique au programme qui est mise à jour à chaque trame à l'aide de deltas de temps système.
Je pense que le plus important est cependant deux bizarreries de synchronisation sur un ordinateur, surtout en ce qui concerne le développement de jeux. La première est la précision en virgule flottante et la seconde est la résolution de la minuterie native.
Vous remarquerez que dans le deuxième exemple, j'ai utilisé un double
type au lieu d'un float
, comme dans le premier exemple (le nom du type dépend bien sûr de la langue que vous utilisez). La raison en est que le deuxième exemple est le stockage du temps de jeu total écoulé . Si le jeu est exécuté pendant très longtemps, les valeurs de format à virgule flottante simple précision auront une précision insuffisante pour mesurer avec précision le temps écoulé , ce qui entraînera des problèmes de stabilité. Le premier exemple est très bien en utilisant le float
type tant que des durées énormes ne sont pas attendues.
À l'autre extrémité du spectre, si le temps de mise à jour que vous attendez est suffisamment petit, vous ne pourrez peut-être pas le réaliser initialement, selon la façon dont vous obtenez l'heure du système. Les minuteries dépendent souvent de la résolution de la minuterie du système d'exploitation sur lequel vous exécutez. Par exemple, la résolution du minuteur par défaut de Windows 7 et inférieur est de 15,6 ms . Cela signifie que la précision de temporisation la plus faible que vous pourriez obtenir en utilisant des fonctions telles que timeGetTime
ou GetTickCount
, est de 15,6 ms, sauf si vous modifiez la résolution de la temporisation (cela comporte également des dangers ).
Eh bien, cela s'est avéré un peu long, mais ce sont des choses importantes à prendre en compte lors de l'implémentation des temporisateurs.