Question

J'essaie de créer une boucle de pas fixe dans mon programme, mais pour une raison quelconque, je ne parviens tout simplement pas à le faire fonctionner correctement. Fondamentalement, ce dont j'ai besoin, c'est une boucle qui fait:

while(!over) {
    Update(elapsedtime);
    Draw(elapsedtime);
}

ou quelque chose de similaire, avec a. J'ai essayé d'utiliser Thread.Sleep mais je ne suis pas sûr que cela me donne une véritable boucle de pas fixe, et lorsque j'ai essayé d'implémenter la solution sur sur ce site , j'ai eu des problèmes car je ne voyais pas comment enregistrer l'état des objets affectés par la boucle. Cela m'a obligé à exclure cette partie, ce qui a entraîné un ralentissement lorsqu'il y avait beaucoup d'objets dans la boucle.

Comment obtenir une boucle de pas fixe sans devoir constamment sauvegarder l'état de chaque objet de la boucle?

Était-ce utile?

La solution

Si vous travaillez sur un moteur de jeu, une minuterie ne fonctionnera probablement pas bien. Les timers n’ont pas assez de précision pour gérer une boucle à pas fixe et la maintenir régulière.

Vous devrez implémenter ceci à l'aide d'un minuteur haute précision. Dans ce cas, vous souhaiterez utiliser la la classe Stopwatch. Cela vous permettra d'avoir suffisamment de précision pour suivre votre temps écoulé avec précision.

Vous devez simplement savoir à quelle fréquence vous souhaitez mettre à jour (en ticks), puis utiliser un chronomètre pour mesurer le temps nécessaire à chacune de vos mises à jour. Après cela, vous pouvez potentiellement utiliser un appel Sleep () pour bloquer, mais sachez que la veille n'aura qu'une précision de 14-15 ms sur la plupart des systèmes, même si vous ne dormez que pendant 0 ou 1 ms. Cela peut ralentir trop votre boucle, vous devrez donc peut-être mettre en œuvre un verrou de verrouillage ou similaire (en attendant (faire quelque chose}). Sleep () est agréable car il permet d’économiser le processeur si vous le pouvez. Le verrouillage du spin prendra des cycles de processeur pendant que vous attendez, mais vous donne plus de précision.

Autres conseils

Demandez-vous une boucle qui s'exécutera pratiquement tous les n ticks? Cela ressemble à un minuterie . Il y a quelques minuteries dans la BCL. Un minuterie pour les serveurs ou un pour les formulaires Windows .

Vous pouvez les utiliser dans ce sens. Ce qui suit est du code psuedo et vise à montrer de manière générale comment cela est fait. En d’autres termes, il ne sera probablement pas compilé si vous ne faites que copier et coller.

public class RepeatingTask
{
    public MyObjectState _objectState;

    public RepeatingTask(Timespan interval)
    {
       Timer timer=new Timer(Timer_Tick); //This assumes we pass a delegate. Each timer is different. Refer to MSDN for proper usage
       timer.Interval=interval;
       timer.Start();

    }
    private DateTime _lastFire;
    private void Timer_Tick()
    {
       DateTime curTime=DateTime.Now();
       DateTime timeSinceLastFire = curTime-lastFireTime;
       _lastFire=DateTime.Now(); //Store when we last fired...

       accumulatedtime+=timeSinceLastFire
       while(accumulatedtime>=physicsInterval)
       {
          Update(physicsInterval);
          accumulated-=physicInterval;
       }

               }

}

Vous pouvez également utiliser une fermeture pour résumer votre état de la méthode dans laquelle le minuteur est défini.

Modifier

J'ai lu l'article et je comprends le problème. Cependant, vous pouvez toujours utiliser une minuterie, mais vous devez le faire, car il indique la configuration de votre fonction pour appeler les moteurs à chaque intervalle défini pour votre moteur physique.

Utilisez-vous WPF? Certains événements, je crois, sont déclenchés à des taux constants pour les animations de création.

Modifier

J'ai mis à jour mon exemple de code pour vous montrer mon interprétation, mais vous définissez essentiellement un intervalle pour votre moteur physique, puis ce que vous devez faire à chaque passage dans votre "boucle / minuteur, quel que soit". est de déterminer combien de temps réel s'est écoulé depuis la dernière itération. Vous stockez ensuite ce delta dans un accumulateur, que vous utiliserez pour compter jusqu'à ce que vous ayez appelé votre moteur physique pour tous les intervalles que vous avez manqués depuis votre dernier appel.

Ce qui me pose problème, c’est que si l’utilisation d’une minuterie ici est préférable, avoir un thread dédié à la veille, ou une autre implémentation.

Thread.Sleep ne vous donnera pas une boucle de pas fixe, il attendra simplement le temps imparti avant de laisser votre programme continuer. La fréquence réelle dépendra de la précision du sommeil et de la cohérence de votre programme pour exécuter la même durée à chaque étape. Toutefois, si vous pouvez tolérer certaines dérives, cela pourrait être suffisant et certainement le plus facile.

Pour obtenir une véritable boucle de pas fixe, vous avez besoin d'un minuterie d'intervalle qui exécute votre code via un rappel lorsque la minuterie expire. Notez que ce n'est plus vraiment une boucle, mais votre code est exécuté périodiquement, ce qui, je pense, est ce que vous voulez. Encore une fois, il peut y avoir une certaine dérive et vous devrez peut-être ajuster l'intervalle à chaque étape pour que l'événement suivant se déclenche au bon moment si vous avez besoin de plus de précision. Il n’est pas vraiment possible de le rendre parfaitement précis - même les minuteurs à intervalles matériels ont une précision, après tout - mais espérons que vous pourrez le rendre suffisamment précis pour vos besoins.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top