RPGDXThe center of Indie-RPG gaming
Not logged in. [log in] [register]
 
 
Post new topic Reply to topic  
View previous topic - View next topic  
Author Message
tcaudilllg
Dragonmaster


Joined: 20 Jun 2002
Posts: 1731
Location: Cedar Bluff, VA

PostPosted: Wed Sep 02, 2009 4:39 am    Post subject: Frame skipping [quote]

How is it done?
Back to top  
Hajo
Demon Hunter


Joined: 30 Sep 2003
Posts: 779
Location: Between chair and keyboard.

PostPosted: Wed Sep 02, 2009 9:55 am    Post subject: [quote]

I only know this in the area of games that run at a fixed frame rate, e.g. 25 fps.

If the game notices that the computer is too slow to reach 25 fps, it starts skipping, every n-th frame. Starting with n=25 and lowering n till it can maintain a constant frame rate with enough CPU time left for the rest of the game.

It just means not to calculate/draw every n-th frame.
Back to top  
Ninkazu
Demon Hunter


Joined: 08 Aug 2002
Posts: 945
Location: Location:

PostPosted: Wed Sep 02, 2009 12:38 pm    Post subject: [quote]

Hajo, I disagree. I've implemented my own frame skipping algorithm, and have had it critiqued by a couple former professional game developers (while at NVIDIA) - they said that mine was the standard technique.

The idea is to completely separate the three: game logic, sound and graphics rendering. Say I have a counter that ticks for every expected frame draw - this is accomplished, say, in Allegro by doing this
Code:
// in defines
#define TARGET_FPS 30
volatile int t;
void tick() { ++t; }
// in init
install_int_ex(tick, BPS_TO_TIMER(TARGET_FPS));


Whenever we get to starting another frame, we decrement t until it's 0, performing a frame's game logic each time. The reason for this is if the previous rendering took too long, we would have t > 1 and thus must skip frames to catch up.

In the main loop you can imagine that t == 0 is a common occurrence on fast computers, so you want to only perform game logic updates and rendering when t > 0. Otherwise you should yield the process so you don't take 100% CPU.
Back to top  
Hajo
Demon Hunter


Joined: 30 Sep 2003
Posts: 779
Location: Between chair and keyboard.

PostPosted: Wed Sep 02, 2009 3:58 pm    Post subject: [quote]

Sounds better than my simple approach :)
Back to top  
DeveloperX
202192397


Joined: 04 May 2003
Posts: 1626
Location: Decatur, IL, USA

PostPosted: Thu Sep 03, 2009 1:26 am    Post subject: [quote]

Code:

// main.cpp
// Project: Allegro Game Template v6.1
// Author: Richard Marks <ccpsceo@gmail.com>
/*
  ****************************************************************************
  * Copyright (c) 2009, Richard Marks, CCPS Solutions,                       *
  * Undefined Aeon Software.                                                 *
  *                                                                          *
  * Permission is hereby granted, free of charge, to any person obtaining a  *
  * copy of this software and associated documentation files (the            *
  * "Software"), to deal in the Software without restriction, including      *
  * without limitation the rights to use, copy, modify, merge, publish,      *
  * distribute, distribute with modifications, sub-license, and/or sell      *
  * copies of the Software, and to permit persons to whom the Software is    *
  * furnished to do so, subject to the following conditions:                 *
  *                                                                          *
  * The above copyright notice and this permission notice shall be included  *
  * in all copies or substantial portions of the Software.                   *
  *                                                                          *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  *
  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
  *                                                                          *
  * Except as contained in this notice, the name(s) of the above copyright   *
  * holders shall not be used in advertising or otherwise to promote the     *
  * sale, use or other dealings in this Software without prior written       *
  * authorization.                                                           *
  ****************************************************************************
*/
#include <cstdio>
#include <cstdlib>
#include <cstring>

#include <allegro.h>

// we need this for handling timing
static volatile int allegrotimerspeedcounter = 0;
static void my_allegro_timer_speed_controller()
{
   allegrotimerspeedcounter++;
}
END_OF_FUNCTION(my_allegro_timer_speed_controller)

// we need this to handle closing the window via the [X] button (you NEED this)
static volatile bool mainthreadisrunning = true;
static void my_allegro_close_button_handler()
{
   mainthreadisrunning = false;
}
END_OF_FUNCTION(my_allegro_close_button_handler)

bool setup_game();
void shutdown_game();

// constants for the screen resolution
const int WINDOW_WIDTH = 800;
const int WINDOW_HEIGHT = 600;

// bitmap for drawing on
BITMAP* backbuffer = 0;

int main(int argc, char* argv[])
{
   // init allegro and add keyboard and mouse support
   allegro_init();
   install_timer();
   install_keyboard();
   install_mouse();

   // set the video mode to 800x600 @ 16bpp
   set_color_depth(16);
   set_gfx_mode(GFX_AUTODETECT_WINDOWED, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0);
   set_window_title("Allegro Game Template v6.1 -- Richard Marks <ccpsceo@gmail.com>");

   // create the back buffer bitmap
   backbuffer = create_bitmap(SCREEN_W, SCREEN_H);

   // seed the random number generator
   srand(time(0));

   // lock the static functions and variables we need for handling timing and closing the window via the [X] button
   LOCK_FUNCTION(my_allegro_close_button_handler);
   LOCK_FUNCTION(my_allegro_timer_speed_controller);
   LOCK_VARIABLE(allegrotimerspeedcounter);

   // set the callback function for the close-button to our global handler function
   set_close_button_callback(my_allegro_close_button_handler);

   // set our FPS lock timing global function
   install_int_ex(my_allegro_timer_speed_controller, BPS_TO_TIMER(30));

   // setup the game
   if (!setup_game())
   {
      fprintf(stderr, "The game initialization has failed. Cannot continue!\n");
      exit(1);
   }

   // main loop
   bool gameover = false;
   while(!gameover)
   {
      // if our global is ever false
      if (!mainthreadisrunning)
      {
         gameover = true;
      }

      // we only update during our FPS lock time
      while (allegrotimerspeedcounter > 0)
      {
         if (keyboard_needs_poll())
         {
            poll_keyboard();
         }

         if (key[KEY_ESC])
         {
            gameover = true;
         }

         // TODO: *** update stuff here

         // decrement the global timing var so that we can leave the update loop!
         allegrotimerspeedcounter--;
      }

      // start rendering the scene

      clear_bitmap(backbuffer);


      // TODO: *** draw stuff here

      // make it all visible
      blit(backbuffer, screen, 0, 0, 0, 0, backbuffer->w, backbuffer->h);

      // a little rest to keep CPU usage down ^-^
      rest(10);
   }

   // shutdown the game
   shutdown_game();

   // clean up the back buffer
   if (backbuffer)
   {
      destroy_bitmap(backbuffer);
   }

   return 0;
}
END_OF_MAIN();

bool setup_game()
{
   // load game resources and stuff here
   // return false if something failed to load or init

   // return true to let the main() function know that we're good to go
   return true;
}

void shutdown_game()
{
   // unallocate anything you allocated for your game here
}



Is what I usually use in my stuff.
_________________
Principal Software Architect
Rambling Indie Games, LLC

See my professional portfolio
Back to top  
Ninkazu
Demon Hunter


Joined: 08 Aug 2002
Posts: 945
Location: Location:

PostPosted: Thu Sep 03, 2009 12:53 pm    Post subject: [quote]

Yes, that would be what I suggested, however you draw too often. I suggest this modification
Code:

if (allegrotimerspeedcounter > 0)
{
      // we only update during our FPS lock time
      while (allegrotimerspeedcounter > 0)
      {
         if (keyboard_needs_poll())
         {
            poll_keyboard();
         }

         if (key[KEY_ESC])
         {
            gameover = true;
         }

         // TODO: *** update stuff here

         // decrement the global timing var so that we can leave the update loop!
         allegrotimerspeedcounter--;
      }

      // start rendering the scene

      clear_bitmap(backbuffer);


      // TODO: *** draw stuff here

      // make it all visible
      blit(backbuffer, screen, 0, 0, 0, 0, backbuffer->w, backbuffer->h);
}
else
      rest(1);


The reason for this is that you want to make sure you only draw when it is appropriate. Your code could possibly render a frame more than once, since allegrotimerspeedcounter == 0 is a possibility, updating no logic, but drawing the screen again. Next I changed rest(10) to rest(1) since rest(1) is the same as yield(), and is best for releasing the process. rest(10) could possibly rest too long and skip the possibility for an update. This is especially true on slower computers.
Back to top  
Mattias Gustavsson
Mage


Joined: 10 Nov 2007
Posts: 457
Location: Royal Leamington Spa, UK

PostPosted: Thu Sep 03, 2009 12:57 pm    Post subject: [quote]

Ninkazu wrote:
since rest(1) is the same as yield()


you mean rest(0), surely?
_________________
www.mattiasgustavsson.com - My blog
www.rivtind.com - My Fantasy world and isometric RPG engine
www.pixieuniversity.com - Software 2D Game Engine
Back to top  
DeveloperX
202192397


Joined: 04 May 2003
Posts: 1626
Location: Decatur, IL, USA

PostPosted: Thu Sep 03, 2009 2:17 pm    Post subject: [quote]

@ Ninkazu: Thanks man. I typically use rest(10) to save my CPU, rest(1) doesn't do much for being nice to my computer for some reason...

@ Mattias: rest(0) effectively does nothing whatsoever from what I've seen.
_________________
Principal Software Architect
Rambling Indie Games, LLC

See my professional portfolio
Back to top  
DeveloperX
202192397


Joined: 04 May 2003
Posts: 1626
Location: Decatur, IL, USA

PostPosted: Thu Sep 03, 2009 2:36 pm    Post subject: [quote]

Taking the above into consideration, I have put together a new template.

Code:

// main.cpp
// Project: Allegro Game Template v6.2
// Author: Richard Marks <ccpsceo@gmail.com>
/*
  ****************************************************************************
  * Copyright (c) 2009, Richard Marks, CCPS Solutions,                       *
  * Undefined Aeon Software.                                                 *
  *                                                                          *
  * Permission is hereby granted, free of charge, to any person obtaining a  *
  * copy of this software and associated documentation files (the            *
  * "Software"), to deal in the Software without restriction, including      *
  * without limitation the rights to use, copy, modify, merge, publish,      *
  * distribute, distribute with modifications, sub-license, and/or sell      *
  * copies of the Software, and to permit persons to whom the Software is    *
  * furnished to do so, subject to the following conditions:                 *
  *                                                                          *
  * The above copyright notice and this permission notice shall be included  *
  * in all copies or substantial portions of the Software.                   *
  *                                                                          *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  *
  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
  *                                                                          *
  * Except as contained in this notice, the name(s) of the above copyright   *
  * holders shall not be used in advertising or otherwise to promote the     *
  * sale, use or other dealings in this Software without prior written       *
  * authorization.                                                           *
  ****************************************************************************
*/

#include <cstdio>
#include <cstdlib>
#include <cstring>

#include <allegro.h>

////////////////////////////////////////////////////////////////////////////////

// we need this for handling timing
static volatile int allegrotimerspeedcounter = 0;
static void my_allegro_timer_speed_controller()
{
   allegrotimerspeedcounter++;
}
END_OF_FUNCTION(my_allegro_timer_speed_controller)

// we need this to handle closing the window via the [X] button (you NEED this)
static volatile bool mainthreadisrunning = true;
static void my_allegro_close_button_handler()
{
   mainthreadisrunning = false;
}
END_OF_FUNCTION(my_allegro_close_button_handler)

////////////////////////////////////////////////////////////////////////////////

bool setup_game();
void update_game();
void render_game();
void shutdown_game();

////////////////////////////////////////////////////////////////////////////////

// constants for the screen resolution
const int WINDOW_WIDTH = 800;
const int WINDOW_HEIGHT = 600;
const int WINDOW_COLOR_DEPTH = 16;
const bool WINDOW_USE_FULLSCREEN = false;

// the text in the window caption bar
const char* WINDOW_CAPTION = "Allegro Game Template v6.2 -- Richard Marks <ccpsceo@gmail.com>";

// if we want to enable the mouse
const bool ENABLE_MOUSE_SUPPORT = true;

// the FPS (frames per second) we should lock to
#define FRAME_LOCK_RATE 30

// bitmap for drawing on
BITMAP* backbuffer = 0;

////////////////////////////////////////////////////////////////////////////////

int main(int argc, char* argv[])
{
   // init allegro and add keyboard and optional mouse support
   allegro_init();
   install_timer();
   install_keyboard();
   if (ENABLE_MOUSE_SUPPORT)
   {
      install_mouse();
   }

   // set the video mode
   set_color_depth(WINDOW_COLOR_DEPTH);
   set_gfx_mode(
      (WINDOW_USE_FULLSCREEN) ?
         GFX_AUTODETECT_FULLSCREEN :
         GFX_AUTODETECT_WINDOWED,
      WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0);
   // set the window caption text
   set_window_title(WINDOW_CAPTION);

   // create the back buffer bitmap
   backbuffer = create_bitmap(SCREEN_W, SCREEN_H);

   // seed the random number generator
   srand(time(0));

   // lock the static functions and variables we need for handling timing and closing the window via the [X] button
   LOCK_FUNCTION(my_allegro_close_button_handler);
   LOCK_FUNCTION(my_allegro_timer_speed_controller);
   LOCK_VARIABLE(allegrotimerspeedcounter);

   // set the callback function for the close-button to our global handler function
   set_close_button_callback(my_allegro_close_button_handler);

   // set our FPS lock timing global function
   install_int_ex(my_allegro_timer_speed_controller, BPS_TO_TIMER(FRAME_LOCK_RATE));

   // setup the game
   if (!setup_game())
   {
      fprintf(stderr, "The game initialization has failed. Cannot continue!\n");
      exit(1);
   }

   // main loop
   bool gameover = false;
   while(!gameover)
   {
      // if our global is ever false
      if (!mainthreadisrunning)
      {
         gameover = true;
      }

      // we only draw when the FPS should be locked
      if (allegrotimerspeedcounter > 0)
      {
         // we only update during our FPS lock time
         while (allegrotimerspeedcounter > 0)
         {
            // ensure the keyboard data is current
            if (keyboard_needs_poll())
            {
               poll_keyboard();
            }

            // ensure the mosue data is current
            if (ENABLE_MOUSE_SUPPORT)
            {
               if (mouse_needs_poll())
               {
                  poll_mouse();
               }
            }

            // update
            update_game();

            // decrement the global timing var so that we can leave the update loop!
            allegrotimerspeedcounter--;
         }

         // start rendering the scene
         render_game();

         if (ENABLE_MOUSE_SUPPORT)
         {
            show_mouse(backbuffer);
         }

         // make it all visible
         blit(backbuffer, screen, 0, 0, 0, 0, backbuffer->w, backbuffer->h);
      }
      else
      {
         // a little rest to keep CPU usage down ^-^
         rest(1);
      }
   }

   // shutdown the game
   shutdown_game();

   // clean up the back buffer
   if (backbuffer)
   {
      if (ENABLE_MOUSE_SUPPORT)
      {
         show_mouse(0);
      }
      destroy_bitmap(backbuffer);
   }

   return 0;
}
END_OF_MAIN();

////////////////////////////////////////////////////////////////////////////////

bool setup_game()
{
   // load game resources and stuff here
   // return false if something failed to load or init

   // return true to let the main() function know that we're good to go
   return true;
}

////////////////////////////////////////////////////////////////////////////////

void update_game()
{
   // TODO: *** update stuff here

   // pressing ESC will end the main loop
   if (key[KEY_ESC])
   {
      mainthreadisrunning = false;
   }
}

////////////////////////////////////////////////////////////////////////////////

void render_game()
{
   clear_bitmap(backbuffer);

   // TODO: *** draw stuff here
}

////////////////////////////////////////////////////////////////////////////////

void shutdown_game()
{
   // deallocate anything you allocated for your game here
}



Thanks again Ninkazu. rest(1) worked for me in this use. :)
_________________
Principal Software Architect
Rambling Indie Games, LLC

See my professional portfolio
Back to top  
Mattias Gustavsson
Mage


Joined: 10 Nov 2007
Posts: 457
Location: Royal Leamington Spa, UK

PostPosted: Thu Sep 03, 2009 6:40 pm    Post subject: [quote]

From: http://alleg.sourceforge.net/stabledocs/en/alleg005.html
Quote:


void rest(unsigned int time);

This function waits for the specified number of milliseconds.
Passing 0 as parameter will not wait, but just yield. This can be useful in order to "play nice" with other processes. Other values will cause CPU time to be dropped on most platforms. This will look better to users, and also does things like saving battery power and making fans less noisy.

Note that calling this inside your active game loop is a bad idea, as you never know when the OS will give you the CPU back, so you could end up missing the vertical retrace and skipping frames. On the other hand, on multitasking operating systems it is good form to give up the CPU for a while if you will not be using it.


But hey, I don't use it myself, so I don't know. Just thought that if "rest" works anything like "Sleep", it would mean that it waits for the specified number of milliseconds, or if 0 is specified yields the remainder of the slice.
_________________
www.mattiasgustavsson.com - My blog
www.rivtind.com - My Fantasy world and isometric RPG engine
www.pixieuniversity.com - Software 2D Game Engine
Back to top  
Ninkazu
Demon Hunter


Joined: 08 Aug 2002
Posts: 945
Location: Location:

PostPosted: Fri Sep 04, 2009 1:03 pm    Post subject: [quote]

You're right. Thanks.
Back to top  
Post new topic Reply to topic Page 1 of 1 All times are GMT
 



Display posts from previous:   
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum