none
Choppy Shapes animation / Maintaining smooth frame rate? RRS feed

  • Question

  • In a little lunar lander style game we're moving a ship around with basic dynamics plus simple collision detection with a blocky world, defined via a very small 2D array of 30x18. The ship is a Shape, moved using Shapes.Move, no projectiles or other sprites to update. Yet, the movement of the ship is quite jerky. I've tried to get it locked at a consistent frame rate by placing the following code at the end of the main loop...

      'Lock framerate at ~60fps
      frameDelay = 16.66-(Clock.ElapsedMilliseconds-tStampFrame)
      If frameDelay > 0 Then
        Program.Delay(frameDelay)
      EndIf
      tStampFrame = Clock.ElapsedMilliseconds

    ...however, I'm finding that a few times each second the loop takes significantly longer than 16.66 ms, regardless of what's happening in the game, which I suspect is the reason for the jitter.  Any suggestions, or is this just the nature of .Net?

     

    Friday, February 4, 2011 6:31 AM

Answers

  • The best way to send an entire game with assets is to zip it all up and put it on SkyDrive and post a link here.  One possible problem is the auto repeat key delay if you are using keys to move the shapes, but it could be a number of other things.
    Friday, February 4, 2011 7:17 PM
    Moderator
  • Hello PeterDad,

    I know this is a few weeks old but none of the solutions proposed will provide you with a steady framerate.

    The problem is that the program.Delay() method is wildly inaccurate at low delay times. IIRC 10 millisecond delay is always 16 milliseconds or more. Its also a pain to have some frames busier than others as you always end up with the same delay at the end of each frame rather than varying accordingly. One possible solution is to use a cpu speed estimator as shown in the game STARGATES (really good game too!). It run a loop for a while and then sees how many times it ran in a given time lapse before modifying the program.delay time. But it still uses the program.delay method so is flawed and doesn't modify the delay if a frame is too long.

    So what I did in my game was create my own timer (example here FZB324) it kind of eats the CPU but then so does most SmallBasic games. You can add as many timer events as you want and it will easily run at a constant 30 frames per second (or 60 if you want) You can also split tasks across multiple timers to instead of using custom delays/counters.

     You also state that you are using a 2d array, try to avoid them as they are slow (obviously for some things its impractical). Also don't ever use the Shape.Getleft/GetTop methods instead store the positions yourself as constantly getting the position is slow. In my game i had multiple missiles (30+) with tons of obstructions (100~) to detect collision on along with 50 enemies even with all this going on in my game i am able to get a 60fps no problem.

    have fun!

     

    Thursday, February 17, 2011 8:18 PM

All replies

  • You can use Shapes.Animate(shape)

    Or, because the variable tStampFrame is use before declaring it, you are just doing Clock.Elapsed Milliseconds - 0! If you used code

      'Lock framerate at ~60fps
      tStampFrame = Clock.ElapsedMilliseconds
      frameDelay = 16.66-(Clock.ElapsedMilliseconds-tStampFrame)
      If frameDelay > 0 Then
        Program.Delay(frameDelay)
      EndIf

    Instead of

      'Lock framerate at ~60fps
      frameDelay = 16.66-(Clock.ElapsedMilliseconds-tStampFrame)
      If frameDelay > 0 Then
        Program.Delay(frameDelay)
      EndIf
      tStampFrame = Clock.ElapsedMilliseconds

     

    Maybe it could help. Because then it would be just 16.66 milliseconds, but then you could just use the framedelay as 16.66 For really smooth animations, use Program.Delay(5) or a delay similar, and then just move the image one pixel at a time.


    ~~AirWaves!!~~
    Friday, February 4, 2011 6:45 AM
  • Hi AirWaves..

    The tStampFrame is actually set at the beginning of the game loop, then the 60fps locking attempt occurs at the very end of the loop. So, more accurately like this:

    While ("True)
       'Record time stamp
       tStampFrame = Clock.ElapsedMilliseconds

       (... Game Code here ...)

      'Lock framerate at ~60 fps
      frameDelay = 16.66-(Clock.ElapsedMilliseconds-tStampFrame)
      If frameDelay > 0 Then
        Program.Delay(frameDelay)
      EndIf
    EndWhile

    This is supposed to even out the refresh rate, as well as assure the same performance on PCs of different specs, but it's obviously not working out too well :(

    Friday, February 4, 2011 7:00 AM
  • Did you try the Shapes.Animate(shape, frame delay)? This can help keep unwanted code out of your loops, and other good stuff.

    ~~AirWaves!!~~
    Friday, February 4, 2011 7:03 AM
  • Did you try the Shapes.Animate(shape, frame delay)? This can help keep unwanted code out of your loops, and other good stuff.

    ~~AirWaves!!~~

    Yes I did, but can't see too much improvement. When using Shapes.Animate, the program does not wait the duration specified in the command, correct?  (I may post the program once it's cleaned up a bit, but it requires a few bitmaps and level text files -- can one Publish with assets? The program probably needs to load them fro a URL?) Thanks for looking into it though!

     

    Friday, February 4, 2011 3:26 PM
  • The best way to send an entire game with assets is to zip it all up and put it on SkyDrive and post a link here.  One possible problem is the auto repeat key delay if you are using keys to move the shapes, but it could be a number of other things.
    Friday, February 4, 2011 7:17 PM
    Moderator
  • Hello PeterDad,

    I know this is a few weeks old but none of the solutions proposed will provide you with a steady framerate.

    The problem is that the program.Delay() method is wildly inaccurate at low delay times. IIRC 10 millisecond delay is always 16 milliseconds or more. Its also a pain to have some frames busier than others as you always end up with the same delay at the end of each frame rather than varying accordingly. One possible solution is to use a cpu speed estimator as shown in the game STARGATES (really good game too!). It run a loop for a while and then sees how many times it ran in a given time lapse before modifying the program.delay time. But it still uses the program.delay method so is flawed and doesn't modify the delay if a frame is too long.

    So what I did in my game was create my own timer (example here FZB324) it kind of eats the CPU but then so does most SmallBasic games. You can add as many timer events as you want and it will easily run at a constant 30 frames per second (or 60 if you want) You can also split tasks across multiple timers to instead of using custom delays/counters.

     You also state that you are using a 2d array, try to avoid them as they are slow (obviously for some things its impractical). Also don't ever use the Shape.Getleft/GetTop methods instead store the positions yourself as constantly getting the position is slow. In my game i had multiple missiles (30+) with tons of obstructions (100~) to detect collision on along with 50 enemies even with all this going on in my game i am able to get a 60fps no problem.

    have fun!

     

    Thursday, February 17, 2011 8:18 PM