Scrolling Game Development Kit Forum
Welcome, Guest. Please login or register.
2014-04-16, 02:44:51 AM

Login with username, password and session length
Search:     Advanced search
10356 Posts in 1148 Topics by 208 Members
Latest Member: Alan_776
* Home Help Search Login Register
+  Scrolling Game Development Kit Forum
|-+  SGDK Version 2
| |-+  Help, Errors, FAQ
| | |-+  Bug and improvement report
« previous next »
Pages: 1 2 [3] Print
Author Topic: Bug and improvement report  (Read 4007 times)
Vincent
SGDK2 Addict
Expert
Fanatic
*****
Posts: 590


Legacy of Kain: Revival is completed!!! (2 years)


View Profile Email
« Reply #30 on: 2011-01-28, 12:45:53 PM »

Beats me!  But it does.
Logged

Legacy of Kain: Revival completed!
http://lokrevival.webs.com
bluemonkmn
SGDK Author
Administrator
Fanatic
*****
Posts: 2696


2678251 BlueMonkMN@gmail.com
View Profile WWW Email
« Reply #31 on: 2011-01-28, 02:42:23 PM »

Wait, so how does it stay at 60 fps if you only call sleep(0)?

Because it does it over and over until the stopwatch says that it's time to go to the next frame.  The hope is that instead of simply looping and checking, adding a call to Sleep(0) inside the loop would give a little more time back to the CPU.
Logged

bluemonkmn
SGDK Author
Administrator
Fanatic
*****
Posts: 2696


2678251 BlueMonkMN@gmail.com
View Profile WWW Email
« Reply #32 on: 2011-01-29, 09:33:12 AM »

Vincent, can you test this fix for me and tell me if it limits the frame rate better?  I tried to make it use sleep to sleep for the correct time to average out correctly over 5 frames instead of just since the last frame.  Here are the changes in GeneralRules.cs:

Line 18 had a declaration for previousFrame.  Change it to this:

Code:
   protected static long[] previousFrames = new long[] { 0, 0, 0, 0, 0 };
   protected static int previousFrameIdx = 0;

Change the LimitFrameRate function to this:
Code:
   public virtual void LimitFrameRate(int fps)
   {
      long freq;
      long frame;
      freq = System.Diagnostics.Stopwatch.Frequency;
      frame = System.Diagnostics.Stopwatch.GetTimestamp();
      long oldFrameTime = previousFrames[previousFrameIdx];
      while ((frame - oldFrameTime) * fps < freq * previousFrames.Length)
      {
         int sleepTime = (int)((oldFrameTime * fps + freq * previousFrames.Length - frame * fps) * 1000 / (freq * fps));
         if (sleepTime > 0) System.Threading.Thread.Sleep(sleepTime);
         frame = System.Diagnostics.Stopwatch.GetTimestamp();
      }
      previousFrames[previousFrameIdx] = frame;
      previousFrameIdx = (previousFrameIdx + 1) % previousFrames.Length;
   }
Logged

Vincent
SGDK2 Addict
Expert
Fanatic
*****
Posts: 590


Legacy of Kain: Revival is completed!!! (2 years)


View Profile Email
« Reply #33 on: 2011-01-29, 10:54:32 AM »

Okay, I'll try this at work on monday. Smiley
Logged

Legacy of Kain: Revival completed!
http://lokrevival.webs.com
Vincent
SGDK2 Addict
Expert
Fanatic
*****
Posts: 590


Legacy of Kain: Revival is completed!!! (2 years)


View Profile Email
« Reply #34 on: 2011-01-31, 11:20:44 AM »

Okay, with your test code, in my FpsTester program I get a frame rate that shifts between 56 and 58 fps (still requesting 60 fps).

I tried it in my game also, to see if get the same result, and I've got the same results but when I play the game, it looks like the rate isn't very fluid.  It's kinda stroboscopic a little.  It's a little jumpy for the eyes.  With sleep(0) it runs better.

Does that help?

Thanks! Smiley
Logged

Legacy of Kain: Revival completed!
http://lokrevival.webs.com
bluemonkmn
SGDK Author
Administrator
Fanatic
*****
Posts: 2696


2678251 BlueMonkMN@gmail.com
View Profile WWW Email
« Reply #35 on: 2011-01-31, 02:59:05 PM »

After an experiment, I think sleep(0) is not really better than leaving sleep out completely.  It ends up taking all the CPU it can get on 1 thread.

My question now is this.  Is it better to have the original behavior where LimitFrameRate resulted in a frame rate lower than what you requested, or the new behavior where you get closer to the requested frame rate, but it's "kinda stroboscopic"?  Which behavior do you think SGDK2 should deliver by default?  Or should I have multiple LimitFrameRate functions:
1. LimitFrameRate (same behavior as now)
2. LimitFrameRateExact (same implementation without Sleep)
3. LimitFrameRateAvg (The new implementation from above that's "kinda stroboscopic")?

How does it behave if you change "protected static long[] previousFrames = new long[] { 0, 0, 0, 0, 0 };" to "protected static long[] previousFrames = new long[20]"?

Edit: Someone else from stackoverflow.com has been discussing the problem with me and has predicted this behavior.  Hopefully that person can also propose a better solution.  You can see the discussion at http://stackoverflow.com/questions/4837416/high-precision-sleep-or-how-to-yield-cpu-and-maintain-precise-frame-rate
« Last Edit: 2011-01-31, 03:20:17 PM by bluemonkmn » Logged

Vincent
SGDK2 Addict
Expert
Fanatic
*****
Posts: 590


Legacy of Kain: Revival is completed!!! (2 years)


View Profile Email
« Reply #36 on: 2011-02-01, 09:48:42 AM »

I tried with the new array.  The FPS is around 60 fps this time, it is more precise.  But it is still very jumpy.  I move my character around and it's very bad.  He walks fast, stops, walks fast, stops again, continuously like this.  Very annoying, it ruins the whole game I think.

When it comes to fps, I don't like to compromise.  When I play a game, I make sure the graphics are not high enough to slow the game.  So, in this case, of course I would say drop the sleep method altogether.  The stroboscopic version is the definitely the worst.  I prefer the game to be a little slower but constant and fluid.

I think the best version if the sleepless one.  Yeah, it does drain all the CPU, but unfocus the game window and you're okay.  You won't get problems by changing computers too.

With the actual version, if someone develop a game on a computer where the lower fps problem occurs, he might boost the fps parameter in the LimitFrameRate call and then the game will become much too fast for other computers.  It's okay if the game is meant to created and played on the same computer, but otherwise it's risky.


The "stroboscopic version" that I would call the "unstable version", is just painful.  I would avoid it at all costs.

I don't know if providing different versions of the behavior is a good idea.  It should be explained what each version of the method implies.  I would definitely go with the sleepless one.

But then again, you have to take my word for it, since it would seem I'm the only one with this issue...   Tongue
Logged

Legacy of Kain: Revival completed!
http://lokrevival.webs.com
bluemonkmn
SGDK Author
Administrator
Fanatic
*****
Posts: 2696


2678251 BlueMonkMN@gmail.com
View Profile WWW Email
« Reply #37 on: 2011-02-01, 02:22:34 PM »

I have another idea that will probably be better than the one above.  I think the stroboscopic effect happened because the first 5 frames were done instantly, then the next frame waits for 5 frames (or N frames) worth of time, and the following 4 frames run instantly again.  I was worried about this problem and tried to think about it without anything to write on, so I thought about it wrong, but now I see the problem.  Now I think it might work better to keep track of 2 things:
1. What was the timer on the first frame?
2. How many frames have passed since the first frame?

From that we can calculate whether we are ahead or behind the target FPS.  Now that I think about it, I think that's what the person from stackoverflow was suggesting.  But the word "decaying" threw me.  I think it makes sense now, though, to reset the "first frame" every once in a while in case something like a message box or switching to another window (pausing the game) causes one of these values to get out of sync.

I will try coming up with the code for that when I get home.
Logged

bluemonkmn
SGDK Author
Administrator
Fanatic
*****
Posts: 2696


2678251 BlueMonkMN@gmail.com
View Profile WWW Email
« Reply #38 on: 2011-02-01, 05:50:18 PM »

OK, try this.

Replace the first block with:
Code:
  protected static long fpsStartTime;
   protected static long fpsFrameCount;

and the second block with:
Code:
  public virtual void LimitFrameRate(int fps)
   {
      long freq;
      long frame;
      freq = System.Diagnostics.Stopwatch.Frequency;
      frame = System.Diagnostics.Stopwatch.GetTimestamp();
      while ((frame - fpsStartTime) * fps < freq * fpsFrameCount)
      {
         int sleepTime = (int)((fpsStartTime * fps + freq * fpsFrameCount - frame * fps) * 1000 / (freq * fps));
         if (sleepTime > 0) System.Threading.Thread.Sleep(sleepTime);
         frame = System.Diagnostics.Stopwatch.GetTimestamp();
      }
      if ((++fpsFrameCount > fps) || (fpsStartTime == 0))
      {
         fpsFrameCount = 1;
         fpsStartTime = frame;
      }
   }

Edit: I just tried this one on my laptop where even sleep(0) didn't work (if I recall), and this was really solid.  The frame rate was almost always exactly what I requested.  Hopefully it works as well for you.
« Last Edit: 2011-02-01, 05:57:52 PM by bluemonkmn » Logged

Vincent
SGDK2 Addict
Expert
Fanatic
*****
Posts: 590


Legacy of Kain: Revival is completed!!! (2 years)


View Profile Email
« Reply #39 on: 2011-02-02, 11:47:24 AM »

Wow, this one is very good!  Yup, you have a winner. Smiley
Logged

Legacy of Kain: Revival completed!
http://lokrevival.webs.com
Pages: 1 2 [3] Print 
« previous next »
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2013, Simple Machines Valid XHTML 1.0! Valid CSS!