Solucionado TimeStep & Rendering Game Loop -- ++ campo con game camp codereview Relacionados El problema

Fixed timestep & rendering game loop


1
vote

problema

Español

Entonces escribí este tiempo de tiempo fijo y amp; Representación de bucle de juego. Lo publico aquí para ver si hay formas de optimizarlo / hacerlo más preciso.

  else5  
Original en ingles

So I wrote this fixed timestep & rendering game loop. I am posting it here to see if there are ways to optimize it/make it more accurate.

     const float updatesRate = 1 / 60.0f;     const float framesRate = 1 / 308.0f;      double currentTime = hireTimeInSeconds( );     double accumulator = 0.0;     double accumulator2 = 0.0;     uint32_t frames = 0, updates = 0;     double timer = hireTimeInSeconds( );      while ( true ) {          double newTime = hireTimeInSeconds( );          if ( newTime - timer >= 1 ) {              //Printing fps and ups here              updates = 0;             frames = 0;             timer = newTime;         }          double frameTime = newTime - currentTime;         if ( frameTime > 0.25 ) frameTime = 0.25;         currentTime = newTime;         accumulator += frameTime;         accumulator2 += frameTime;          //Polling input here          while ( accumulator >= updatesRate ) {              //Updating here             accumulator -= updatesRate;             updates++;         }          const double alpha = accumulator / updatesRate;          while ( accumulator2 >= framesRate ) {             //Rendering             frames++;             accumulator2 -= framesRate;         }     }  ```  
     

Lista de respuestas

4
 
vote
vote
La mejor respuesta
 
  const float updatesRate = 1 / 60.0f; const float framesRate = 1 / 308.0f;   

Los otros valores de tiempo son todos double S, es un poco extraño usar float s aquí.


      if ( newTime - timer >= 1 ) {     ...     if ( frameTime > 0.25 ) frameTime = 0.25;   

Estos números mágicos deben ser nombrados constantes.


C ++ Ahora proporciona una variedad de utilidades relacionadas con el tiempo a través del encabezado <chrono> . Deberíamos usar los tipos de relojes, los tipos de duración de tipo seguro y las conversiones que proporciona.


  double accumulator = 0.0; double accumulator2 = 0.0; uint32_t frames = 0, updates = 0; double timer = hireTimeInSeconds( );   

La nombramiento de estas variables deja su propósito muy poco claro. Tal vez podríamos definir una clase 99887776665544336


hireTimeInSeconds Esto debería ser probablemente highResTimeInSeconds .


      while ( accumulator2 >= framesRate ) {         //Rendering         frames++;         accumulator2 -= framesRate;     }   

No creo que esto tenga sentido. Solo queremos hacer un marco, incluso si el tiempo ha pasado mucho tiempo. (No estamos realizando ninguna actualización entre los marcos de representación en este bucle, por lo que simplemente estamos haciendo la misma cosa exactamente una y otra vez).


Aplicando las sugerencias anteriores, podríamos obtener algo como el código a continuación. Es bastante más líneas de código, pero también es mucho más reutilizable (especialmente el 99887766555443310 99887766555443311 clases), y es espero que sea más claro en la intención:

  double2  

 
const float updatesRate = 1 / 60.0f; const float framesRate = 1 / 308.0f; 

The other time values are all doubles, it's a bit strange to use floats here.


    if ( newTime - timer >= 1 ) {     ...     if ( frameTime > 0.25 ) frameTime = 0.25; 

These magic numbers should be named constants.


C++ now provides a variety of time-related utilities through the <chrono> header. We should use the clock types, type-safe duration types, and conversions that it provides.


double accumulator = 0.0; double accumulator2 = 0.0; uint32_t frames = 0, updates = 0; double timer = hireTimeInSeconds( ); 

The naming of these variables leaves their purpose very unclear. Perhaps we could define an Accumulator class to group the variables for each accumulator and remove the duplication (see example code below).


hireTimeInSeconds This should probably be highResTimeInSeconds.


    while ( accumulator2 >= framesRate ) {         //Rendering         frames++;         accumulator2 -= framesRate;     } 

I don't think this makes sense. We only want to render one frame, even if lots of time has passed. (We're not doing any updates between rendering frames in this loop, so we'd just be rendering the exact same thing over and over).


Applying the above suggestions, we might get something like the code below. It is quite a few more lines of code, but is also much more reusable (especially the accumulator and frame_timer classes), and is hopefully clearer in intent:

#include <chrono> #include <iostream>  template<class c_t> class accumulator { public:      using clock_t = c_t;     using duration_t = typename clock_t::duration;      template<class d_t>     explicit accumulator(d_t tick_length):         m_tick_length(std::chrono::duration_cast<duration_t>(tick_length)) { }      std::size_t accumulate(duration_t delta_time) // note: returns the number of ticks of m_tick_length triggered by this call     {         m_accumulated_time += delta_time;          auto ticks = std::size_t{ 0 };          while (m_accumulated_time >= m_tick_length)         {             ++ticks;             m_accumulated_time -= m_tick_length;         }          return ticks;     }      duration_t get_tick_length() const     {         return m_tick_length;     }  private:      duration_t m_tick_length;     duration_t m_accumulated_time; };  template<class c_t> class frame_timer { public:      using clock_t = c_t;     using duration_t = typename clock_t::duration;     using time_point_t = typename clock_t::time_point;      template<class d_t>     explicit frame_timer(d_t initial_last_frame_time):         m_last_frame_time(std::chrono::duration_cast<duration_t>(initial_last_frame_time)),         m_last_tick(clock_t::now()) { }          void tick()     {         auto now = clock_t::now();         m_last_frame_time = now - m_last_tick;         m_last_tick = now;     }      duration_t get_last_frame_time() const     {         return m_last_frame_time;     }  private:      duration_t m_last_frame_time;     time_point_t m_last_tick; };  int main() {     using clock_t = std::chrono::high_resolution_clock;     using duration_t = clock_t::duration;     using time_point_t = clock_t::time_point;     using seconds_t = std::chrono::duration<float>;      auto const update_time = seconds_t(1.f / 60.f);     auto update_accumulator = accumulator<clock_t>(update_time);      auto const render_time = seconds_t(1.f / 308.f);     auto render_accumulator = accumulator<clock_t>(render_time);      auto const print_time = seconds_t(1.f);     auto print_accumulator = accumulator<clock_t>(print_time);      auto const initial_frame_time = update_time;     auto timer = frame_timer<clock_t>(initial_frame_time);      auto const max_frame_time = std::chrono::duration_cast<duration_t>(seconds_t(0.25f));      while (true)     {         auto const last_frame_time = (timer.get_last_frame_time() > max_frame_time) ? max_frame_time : timer.get_last_frame_time();          if (print_accumulator.accumulate(last_frame_time) != 0) // note: will skip update periods if frames are super long (> print_time)         {             // ... print frames             std::cout << "ping!" << std::endl;         }          auto const update_ticks = update_accumulator.accumulate(last_frame_time); // note: don't put this directly in the loop condition, we only want to call it once!          for (auto i = std::size_t{ 0 }; i != update_ticks; ++i)         {             // ... do update             std::cout << "update" << std::endl;         }          if (render_accumulator.accumulate(last_frame_time) != 0) // note: only ever render 1 frame, even if we should have rendered more         {             // ... render             std::cout << "render" << std::endl;         }          timer.tick();     } } 
 
 

Relacionados problema

8  IOS7 CHESSGAME UichessOarkView Design  ( Ios7 chessgame uichessboardview design ) 
He estado diseñando UichessboardView en la semejanza de UITYVIEW usando protocolos y delegados. uichessboardview.h @interface UIChessboardView : UIView...

5  Estructura de datos para entidades  ( Data structure for entities ) 
Estoy trabajando en un motor de componentes de la entidad-componente para juegos, que básicamente significa que una entidad es un objeto que apunta a los comp...

6  Sistema de eventos personalizado en C #  ( Custom event system in c ) 
Actualmente estoy escribiendo un juego y quiero codificar todo lo que sucede (GameObject se ha movido, HP cambió, fue creado / destruido, se ha creado / perdi...

7  Mecánica de índice para tijeras de papel de roca  ( Index mechanics for rock paper scissors ) 
Acabo de pasar por un ejemplo en línea muy fácil Creando un juego de tijeras de rock-papel, pero parecía que no era un gran uso del poder de la computación. ...

1  Piedra Papel tijeras  ( Rock paper scissors ) 
Gracias por su tiempo, soy nuevo en la programación y pasé algunos días haciendo este rock, papel y amp; Juego de tijera. ¿Qué otras mejoras posibles podrían ...

5  Mouselistener Lag en el juego de azulejos de piano  ( Mouselistener lag in piano tiles game ) 
Estaba intentando escribir mi propia versión simple de la aplicación de juegos de piano azulejos en Java, así como un ejercicio divertido. gamelogic.java ...

4  Atomas Clone en Python  ( Atomas clone in python ) 
Aquí está mi clon de mierda de atomas , un juego de rompecabezas donde combina pequeños átomos en otros más valiosos. 9988776655544337 ¿Hay algún códig...

4  Juego de Runas: Versión 3  ( Game of runes version 3 ) 
He escrito una versión muy revisada y desarrollada de la juego de runas . Los cambios principales se enumeran: Convertir runas para usar maldiciones. ag...

6  Prototipo de javascript blackjack  ( Javascript blackjack prototype ) 
¿Cuál sería la mejor manera de organizar Blackjack en JavaScript y tal vez comience con la pizarra en blanco? Áreas específicas: Actualizando la UI Inc...

5  Revisión de código para Hangman en C ++  ( Code review for hangman in c ) 
Tengo el siguiente programa C ++: autoConnect.py1 que se supone que replica visualmente el juego clásico de Hangman. ¿El código está totalmente optimiza...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos