Pregunta

Estoy intentando crear un bucle de paso fijo en mi programa, pero por alguna razón parece que no puedo hacer que funcione correctamente. Básicamente, lo que necesito es un bucle que hace:

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

o algo similar, con a. Intenté usar Thread.Sleep pero no estoy tan seguro de que me haya dado un bucle de pasos fijo real, y cuando intenté implementar la solución en este sitio web Tuve problemas debido al hecho de que no podía ver una manera de guardar el estado de los objetos afectados por el bucle. Esto me obligó a excluir esa parte, lo que condujo a una desaceleración cuando había muchos objetos en el bucle.

¿Cómo puedo obtener un bucle de paso fijo sin tener que guardar constantemente el estado de cada objeto en el bucle?

¿Fue útil?

Solución

Si está trabajando en un motor de juego, un temporizador probablemente no funcionará bien. Los temporizadores no tienen suficiente precisión para manejar un bucle de paso fijo y mantenerlo regular.

Deberá implementar esto utilizando un temporizador de alta precisión. En este caso, querrá usar la clase Stopwatch. Esto le permitirá tener la precisión suficiente para realizar un seguimiento preciso de su tiempo transcurrido.

Solo necesitará hacer un seguimiento de la frecuencia con la que desea actualizar (en Ticks), luego usar un cronómetro para medir el tiempo que toma cada una de sus actualizaciones. Después de eso, puede usar una llamada Sleep () para bloquear, pero tenga en cuenta que el sueño solo tendrá una precisión de 14-15 ms en la mayoría de los sistemas, incluso si solo duerme durante 0 o 1 ms. Esto puede ralentizar demasiado su ciclo, por lo que es posible que deba implementar un bloqueo de giro o similar (mientras (espera) {hacer algo}). Sleep () es bueno porque ahorra CPU si puedes, el bloqueo de giro consumirá ciclos de CPU mientras esperas, pero te da más precisión.

Otros consejos

¿Está pidiendo un bucle que se ejecutará básicamente cada n ticks? Esto suena como un Temporizador . Hay un par de temporizadores en el BCL. Un temporizador para servidores o uno para formularios de ventana .

Puede usarlos a lo largo de estas líneas. El siguiente es el código psuedo y está destinado a mostrar en general cómo se hace esto. En otras palabras, probablemente no se compilará si solo copia y pega.

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;
       }

               }

}

También puede usar un cierre para ajustar su estado del método en el que se define el temporizador.

Editar

Leí el artículo y entiendo el problema; sin embargo, aún podría usar un temporizador, pero necesita, como él indica, configurar su función para llamar a los motores para cada intervalo en el que configure su motor de física.

¿Está utilizando WPF? Tienen algunos eventos que creo que se disparan a velocidades constantes para animaciones de diseño.

Editar

Actualicé mi ejemplo de código para mostrarle mi interpretación, pero básicamente lo que hace es definir un intervalo para su motor de física, y luego lo que debe hacer en cada pasada a través de su "Loop / Timer" lo que sea " es determinar cuánto tiempo real pasó desde la última iteración. Luego almacena ese delta en un Accumalator, que usará para contar hasta que haya llamado a su motor de física para todos los intervalos que perdió desde la última vez que llamó.

Con lo que lucho es si usar un temporizador aquí es mejor, entonces tener un hilo dedicado durmiendo, o alguna otra implementación.

Thread.Sleep no le dará un bucle de paso fijo, simplemente esperará la cantidad de tiempo dada antes de permitir que su programa continúe. La frecuencia real dependerá de cuán preciso sea el sueño y cuán consistente sea su programa al ejecutar la misma cantidad de tiempo de reloj de pared en cada paso. Sin embargo, si puede adaptarse a alguna deriva, esto podría ser adecuado y sin duda es el más fácil.

Para obtener un bucle de paso fijo real, lo que necesita es un temporizador de intervalo que ejecuta su código a través de una devolución de llamada cuando expira el temporizador. Tenga en cuenta que ya no es realmente un bucle, pero su código se ejecuta periódicamente, que es, creo, lo que quiere. Nuevamente, puede haber alguna deriva y, por lo tanto, es posible que deba ajustar el intervalo en cada paso para que el próximo evento se active en el momento correcto si necesita más precisión. No es realmente posible hacerlo perfectamente preciso, incluso los temporizadores de intervalos basados ??en hardware tienen una precisión, después de todo, pero es de esperar que pueda hacerlo lo suficientemente preciso para sus propósitos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top