Author Topic: limited frame rate  (Read 8041 times)

Tanja

  • Clever
  • Fanatic
  • ***
  • Posts: 606
    • View Profile
limited frame rate
« on: 2008-01-22, 09:22:02 AM »
how can i limit the overall frame rate to a specific value?
when someone plays my game at a slower computer, i can do nothing. but if someone plays it on a faster computer (what is very likely), many animations will run too fast. i want to keep the frame rate at 60fps, not faster.

Richard Kain

  • Regular
  • **
  • Posts: 23
    • View Profile
Re: limited frame rate
« Reply #1 on: 2008-01-22, 02:22:55 PM »
I was under the impression that the base-line framerate already was capped at 60fps. At least, all of my trials have run at no higher than 60fps

Tanja

  • Clever
  • Fanatic
  • ***
  • Posts: 606
    • View Profile
Re: limited frame rate
« Reply #2 on: 2008-01-22, 02:29:58 PM »
no i've seen my game running at 85. and this was a older pc...

durnurd

  • Lead Lemming
  • Expert
  • Fanatic
  • *****
  • Posts: 1234
  • Games completed so far: 0
    • MSN Messenger - durnurd@hotmail.com
    • View Profile
    • Find My Ed
Re: limited frame rate
« Reply #3 on: 2008-01-22, 03:12:46 PM »
Well, I get games running at 200 FPS when running in Full-screen mode.  If you have that problem, turn on your video-card's V-sync (Vertical-refresh synchronization) so that it runs at a maximum speed of the refresh rate of your monitor.  There's currently no built-in way to limit the FPS, though.  It is possible, though I don't know where it would be, to change/add code in the drawing section of the game loop to slow down the loop.
Edward Dassmesser

Tanja

  • Clever
  • Fanatic
  • ***
  • Posts: 606
    • View Profile
Re: limited frame rate
« Reply #4 on: 2008-01-25, 09:28:45 AM »
maybe bluemonk knows the solution?

bluemonkmn

  • SGDK Author
  • Administrator
  • Fanatic
  • *****
  • Posts: 2761
    • ICQ Messenger - 2678251
    • MSN Messenger - BlueMonkMN@gmail.com
    • View Profile
    • http://sgdk2.sf.net/
    • Email
Re: limited frame rate
« Reply #5 on: 2008-01-26, 07:36:55 PM »
In version one, I have a frame rate limit built into the engine, but I haven'[t provided one for SGDK2 yet.  I think I used a high-frequency timer and after each frame I would wait until some time value was reached before proceeding.  You could develop and put similar code almost anywhere in your SGDK2 project because most code is within the game loop -- just make sure it only executes once per loop.  My suggestion would be to look at the end of the Run function in GameForm.cs.  Add a loop around the "Application.DoEvents()" call that repeats that line of code until the high-frequency timer reaches the appropriate value.

I think .NET does not expose a high-frequency timer (VB6 didn't either) so in order to access it, you would have to declare external function (Windows API) references to get the timer values.

I searched Google for:
QueryPerformanceCounter C#
and found this page: http://www.thescripts.com/forum/thread251697.html

That shows you at least how to access the function I was using, I think.  There's also QueryPerformanceFrequency that tells you how fast the counter runs, which you can use to calculate a value to set your frame rate as a fraction of a second.  I don't have time to go into the details now, but hopefully one of you clever folks or experts could take it from there :).

durnurd

  • Lead Lemming
  • Expert
  • Fanatic
  • *****
  • Posts: 1234
  • Games completed so far: 0
    • MSN Messenger - durnurd@hotmail.com
    • View Profile
    • Find My Ed
Re: limited frame rate
« Reply #6 on: 2008-01-26, 09:01:03 PM »
Here's a Frame Rate Limiter I hacked together just now as a Custom Object.

All you need to do is call CustomObjects.FPSLimiter.RegisterLimit with an argument of how many FPS to limit to.  This only needs to be called once, in an initialization loop, for example.  However, if you do call it every frame, it will have no adverse effects.

Call CustomObjects.FPSLimiter.UnregisterLimit to remove the limit.

To change the FPS limit, you can either re-register with a new FPS (no need to unregister first) or set CustomObjects.FPSLimiter.FPS to whatever value you want to limit to.

Code: (FPSLimiter.cs) [Select]
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace CustomObjects
{
   public class FPSLimiter
   {

      [DllImport("Kernel32.dll")]
      private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);

      [DllImport("kernel32.dll", SetLastError=true)]
      private static extern bool QueryPerformanceFrequency(out long frequency);

      private static long freq = -1;
      private static long pCount = -1;
      private static long delay = -1;
      private static uint framerate = 0;
      private static GameForm.SimpleNotification waiter = null;

      [Description("Call once to begin limiting the framerate to the specified value.")]
      public static void RegisterLimit(uint FPS)
      {
         if (null == waiter)
         {
            waiter = new GameForm.SimpleNotification(Wait);
            Project.GameWindow.OnBeforeBeginScene += waiter;
         }
         if (framerate != FPS || delay == -1)
            FPSLimiter.FPS = FPS;
      }
      [Description("Call once to remove all framerate limits.")]
      public static void UnregisterLimit()
      {
         Project.GameWindow.OnBeforeBeginScene -= waiter;
         waiter = null;
      }
      public static uint FPS
      {
         get
         {
            return (null == waiter ? 0 : framerate);
         }
         set
         {
            if (value == 0)
               throw new Exception ("Cannot limit framerate to 0 FPS");
            if (value != framerate)
            {
               framerate = value;
               init();
            }
         }
      }

      private static void init()
      {
         if (freq == -1)
         {
            if (!QueryPerformanceFrequency(out freq))
               throw new Exception("Couldn't get performance frequency for frame rate");
         }
         delay = (long)(1f/(float)FPS*(float)freq);
         if (pCount == -1)
            if (!QueryPerformanceCounter(out pCount))
               throw new Exception("Couldn't get performance count for frame rate");
            else
               return;
      }

      private static void Wait()
      {
         Project.GameWindow.debugText.Write(FPS.ToString());
         long newCount = 0;
         QueryPerformanceCounter(out newCount);
         while (newCount < pCount + delay)
         {
            System.Windows.Forms.Application.DoEvents();
            QueryPerformanceCounter(out newCount);
         }
         pCount = newCount;
      }
   }
}

--Edit--
I have submitted the file to sgdk2.enigmadream.com for distribution.  By the by, BlueMonk, I think there needs to be an area for Code objects specifically, and also an easy way to view details about and download files from that website within the SGDK2 IDE.
« Last Edit: 2008-01-26, 09:27:14 PM by durnurd »
Edward Dassmesser

Tanja

  • Clever
  • Fanatic
  • ***
  • Posts: 606
    • View Profile
Re: limited frame rate
« Reply #7 on: 2008-01-27, 05:57:25 AM »
your limiter works fine, but when i close the game window this error message appears:

durnurd

  • Lead Lemming
  • Expert
  • Fanatic
  • *****
  • Posts: 1234
  • Games completed so far: 0
    • MSN Messenger - durnurd@hotmail.com
    • View Profile
    • Find My Ed
Re: limited frame rate
« Reply #8 on: 2008-01-27, 09:25:58 AM »
1. How do you close the game window?  Is it with the close button or with the Exit item in the menu, or calling the QuitGame function?
2. What does line 274 of your GameForm.cs look like?  Mine looks like    if (OnBeforeDrawOverlay != null) which I don't think could cause a NullReferenceException
3. Do you have anything else that you know of that is registered as an event to run during the game loop (like an OnBeforeDrawOverlay event)?
Edward Dassmesser

Tanja

  • Clever
  • Fanatic
  • ***
  • Posts: 606
    • View Profile
Re: limited frame rate
« Reply #9 on: 2008-01-27, 10:43:43 AM »
1. i close the game with the X-button.
2. GameDisplay.Device.BeginScene();
3. i don't know exactly what you mean.... i have changed some things on the code, e.g. the opacity change for layers and for drawcounterassprite.

bluemonkmn

  • SGDK Author
  • Administrator
  • Fanatic
  • *****
  • Posts: 2761
    • ICQ Messenger - 2678251
    • MSN Messenger - BlueMonkMN@gmail.com
    • View Profile
    • http://sgdk2.sf.net/
    • Email
Re: limited frame rate
« Reply #10 on: 2008-01-27, 12:23:38 PM »
The quick/easy fix is to change all references to "OnBeforeBeginScene" in the FPS limiter code to "OnFrameStart".  The explanation of why the problem occurs is this:
The main game loop only checks if the window is closed after the one point where user events are allowed to be processed.
User events are processed during "Application.DoEvents" in the main loop in GameForm.cs.
OnBeforeBeginScene occurs after SGDK2 has performed this check.
The FPS limiter code executes "Application.DoEvents()" while it is waiting for the next frame, which allows more user events to be processed.
If this happens during OnBeforeBeginScene, that means more user events could be processed after SGDK2 has checked.  It didn't expect the window to be closed during OnBeforeBeginScene.

So the quick fix was to use a different event "OnFrameStart", which happens about the same time that the existing Application.DoEvents happens.  Then SGDK2 will check for the window being closed after the FPS Limiter code runs.

durnurd

  • Lead Lemming
  • Expert
  • Fanatic
  • *****
  • Posts: 1234
  • Games completed so far: 0
    • MSN Messenger - durnurd@hotmail.com
    • View Profile
    • Find My Ed
Re: limited frame rate
« Reply #11 on: 2008-01-27, 05:09:38 PM »
Huh... I tried it several times myself and never got the error, though.  Very le strange.
Edward Dassmesser