Author Topic: Best practices for a consistent framerate  (Read 2860 times)

0 Members and 1 Guest are viewing this topic.

Offline 40wattstudio

  • Newbie
  • Posts: 82
    • 40wattstudio
Best practices for a consistent framerate
« on: March 14, 2020, 08:09:19 am »
Currently developing a QB64 game (see signature link) and while I have a lot of my desired features added, I've noticed that sometimes the game slows down to a crawl.

My question is: Are there some general tips or best practices for making a QB64 program run with a consistent framerate?

In particular, I'm using a lot of _LOADIMAGE, _PUTIMAGE, and various loops.
Is there much of a performance difference between using a DO LOOP vs a FOR NEXT?
Is there a rough limit to how many loops one should have running at any one time?
Would it be better to load all images outside of the main loop, or only call them as needed?
What would you do to make a game run as fast as possible? I'd rather have a game run too fast than too slow because I can always slow it down with _LIMIT.

Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
Re: Best practices for a consistent framerate
« Reply #1 on: March 14, 2020, 11:27:41 am »
"My question is: Are there some general tips or best practices for making a QB64 program run with a consistent framerate?"

I've found that _LIMIT works very nice for smooth frame rates. I typically write all my games to run in the 30 to 60 FPS range ( _LIMIT 30  or  _LIMIT 60)

"Is there much of a performance difference between using a DO LOOP vs a FOR NEXT?"

Years ago there was talk of DO...LOOP being much more efficient so I adopted a policy of never using FOR...NEXT statements in the main body of my code. I'm not sure if that speed difference is the case today, some speed comparison code would need to be executed to find out.

"Is there a rough limit to how many loops one should have running at any one time?"

Nope, not that I'm aware of. Many of my games have multiple nested loops with no side effects.

"Would it be better to load all images outside of the main loop, or only call them as needed?"

In my opinion loading all assets before the main game play loop would be better. If you loaded as needed you would notice an ever slight performance hit for each disk access. These may add up over time to a very noticeable difference in game performance. I normally create a subroutine called INITIALIZE() where all game settings get loaded and/or set as well as loading all sounds, graphics, and fonts. Furthermore, any pre-game graphics work that can be done on images I do here as well.

"What would you do to make a game run as fast as possible?"

Practice, practice, and more practice. The more you code the more efficient ways you find to do things. Also, don't hesitate to look at the code of other games posted here. My game called Widescreen Asteroids would be a good example for you to look through. I optimized the heck out of that thing because of all the particle effects I wished to achieve during game play. I've learned many tricks and techniques over the years from looking at other programmer's code. I comment my code very well for two reasons; my understanding when looking at the code a year later and for others to learn from it.
« Last Edit: March 14, 2020, 11:39:50 am by TerryRitchie »
In order to understand recursion, one must first understand recursion.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Re: Best practices for a consistent framerate
« Reply #2 on: March 14, 2020, 11:34:46 am »
Well Terry, posted just before me here is my 2 cents:

A FOR loop is slower than a DO loop or a WHILE loop.

Yes have all your stuff loaded before main loop.
I try to run everything through main loop. But big games might have different phases = different main loops exclusive of any other main loop.

For speed, check out Steve McNeill's MEM tutorials.


Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • Steve’s QB64 Archive Forum
Re: Best practices for a consistent framerate
« Reply #3 on: March 14, 2020, 11:58:21 am »
Another trick: Use layers and only redraw those layers if changes are necessary.

For example, let's say I'm making Pacman.  (A simple game to use as an example, as everyone knows it, generally.)

We could draw every line, dot, ghost, sprite, and player separately before displaying them on the screen...

OR...

We could decide which parts are permanent (the walls and "ghost house"), which parts seldom change (the dots which Pac-Man eats), and which parts change constantly (Pac-Man and the ghosts). 

By making these 3 parts different layers, we only draw the background once and then use it with _PUTIMAGE to clear the screen, instead of relying on CLS first.  Then we only need to change the second layer by removing any dots that got eaten -- and if none got ate (as Pac-Man was just running from the ghosts), we don't have to alter that layer at all before we put it in place.  And finally, we draw Pac-Man and the ghosts...

1 background.  1 possible dot change and then the dot layer.  1 hero and 4 villains...  this is all we draw and render to the screen...

Compared to:

Clearing the screen.  Drawing every wall independently.  Drawing the ghost house.  Drawing every dot. Drawing the hero and 4 villains...

By separating into layers, you can reduce the amount of calculations and redrawing your program has to do before rendering the final product on the screen -- and that's often where the biggest changes in framerate will occur at.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline 40wattstudio

  • Newbie
  • Posts: 82
    • 40wattstudio
Re: Best practices for a consistent framerate
« Reply #4 on: March 14, 2020, 12:07:21 pm »
Thanks for suggesting your Widescreen Asteroids game Terry, that is probably the tidiest QBasic code I've ever seen!
Bplus, I'll check into those MEM tutorials. Thanks for the tip!
SMcNeill - what you says makes a lot of sense regarding the layers, I think that could be a big contributing factor as well to my problems.

I've been using _LIMIT quite religiously, but that only seems to help when trying to slow things down. Still it's a good tool to have.

Okay, I'll definitely make a point of loading the graphics/etc before the main loop. Currently I'm loading some assets within loops so that might be my issue right there.

In regards to loading pictures, are there certain file formats that QB64 loads faster than others (.png vs .jpeg, etc)? Does picture size become an issue at some point? I have images all the way from 15x15 pixels to 2000 x 2000 pixels.

So one thing I've noticed from looking at other people's programs is that they usually use these .bi files. Is that simply to prevent having all your code in the .bas or is there another reason for that?





Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • Steve’s QB64 Archive Forum
Re: Best practices for a consistent framerate
« Reply #5 on: March 14, 2020, 12:29:34 pm »
.BI and.BM files are usually recyclable library code.

Let's say I write a routine to save my screen to the drive as a BMP file...   Now, that's something I might pop into a dozen different programs so I can do screen captures, Right? 

So what am I going to do?  Rewrite that code every time I need it?  Find an old program that has it, open that, and then copy and paste it into my new program?

Or....

Am I going to make a folder called "LIBRARY FILES" and then save it there as a "SaveBMP.BM" file, so all I need to do in the future is $INCLUDE:'./LIBRARY FILES/SAVEBMP.BM' in any program that needs it?
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline 40wattstudio

  • Newbie
  • Posts: 82
    • 40wattstudio
Re: Best practices for a consistent framerate
« Reply #6 on: March 14, 2020, 12:39:57 pm »
So basically .bi / .bm files keep you from reinventing the wheel every time. Does that sound about right?

Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
Re: Best practices for a consistent framerate
« Reply #7 on: March 14, 2020, 01:01:53 pm »
Thanks for suggesting your Widescreen Asteroids game Terry, that is probably the tidiest QBasic code I've ever seen!

In regards to loading pictures, are there certain file formats that QB64 loads faster than others (.png vs .jpeg, etc)? Does picture size become an issue at some point? I have images all the way from 15x15 pixels to 2000 x 2000 pixels.

Well thank you :-)

I like to work with .PNG files exclusively for two reasons. First, they are lossless, meaning you wont get any of the artifacting around boundaries in images like you do with JPEGs. Secondly, they support a transparent (alpha) layer, meaning I can create a .PNG in my favorite graphics program, designate a color as transparent, and QB64 will see and use the transparent layer.

Large image sizes only become an issue if you need to move them around in real time. The only time I use large images in real-time is for layering as Steve pointed out. Another common reason I use large image files is to load something like a sprite sheet into memory containing all of the game's graphics. I can then use _PUTIMAGE to pluck out the images I need from the "master" sprite sheet I have loaded in memory.

Oh, also, if you designate large images as hardware types (vs software) then they speed up dramatically when drawing them.
« Last Edit: March 14, 2020, 01:04:43 pm by TerryRitchie »
In order to understand recursion, one must first understand recursion.

Offline OldMoses

  • Seasoned Forum Regular
  • Posts: 469
Re: Best practices for a consistent framerate
« Reply #8 on: March 14, 2020, 01:08:19 pm »
I was recently beating my head against the wall working with an old star field simulator that I wrote a few months back. I had a routine that allowed the user to turn left/right/up/down in it using the arrow keys. It would speed up and slow down simply running with no keyboard input. I couldn't make it stop its "stick/slip" action until I used a logical operator that skipped the salient computations when no key input was found. Those computations use trig functions which are expensive in processor time and it was doing them when it wasn't necessary. This is related to what Steve was saying about not drawing things that are unnecessary, the same thing will go for computations. Do as much as possible outside the loop and skip them when inside the loop but not used.


Here's the code, the SIN functions on lines 63 & 64 caused most of the issues. Using the IF ... THEN to skip them smoothed it out to a great degree. When you're actually using them, it isn't as noticeable.
Code: QB64: [Select]
  1. _TITLE "OldMoses' 3D StarField V.2 (h to toggle help menu)"
  2.  
  3. TYPE star '                                                     define the star data type
  4.     x AS INTEGER '                                              star x coordinate
  5.     y AS INTEGER '                                              star y coordinate
  6.     z AS INTEGER '                                              star z coordinate
  7.     r AS INTEGER '                                              red component
  8.     g AS INTEGER '                                              green component
  9.     b AS INTEGER '                                              blue component
  10.     xa AS INTEGER '                                             apparent x position on screen
  11.     ya AS INTEGER '                                             apparent y position on screen
  12.  
  13. DIM SHARED scrw AS INTEGER '                                    screen width
  14. DIM SHARED scrh AS INTEGER '                                    screen height
  15. DIM SHARED starcount AS INTEGER: starcount = 4000 '             set number of stars to begin with
  16. DIM SHARED vwport AS INTEGER: vwport = 1200 '                   set the viewport setback from viewer's eye
  17. DIM SHARED p(starcount) AS star '                               dimension the star data array
  18. DIM SHARED speed AS INTEGER: speed = 4 '                        warp factor
  19. DIM SHARED xch AS _BYTE '                                       x turn state
  20. DIM SHARED ych AS _BYTE '                                       y turn state
  21. DIM SHARED hlptog AS _BYTE: hlptog = -1 '                       help menu display toggle
  22. DIM SHARED dattog AS _BYTE: dattog = -1 '                       data bar display toggle
  23. DIM SHARED bsrad AS _BYTE: bsrad = 1 '                          star swell radius
  24.  
  25. 'lets try a fullscreen version.
  26. scrw = _DESKTOPWIDTH: scrh = _DESKTOPHEIGHT - 40
  27. a& = _NEWIMAGE(scrw, scrh, 32)
  28.  
  29. PopVoid '                                                       OldMoses said "Let there be light" and the universe was, is and ever shall be
  30. WINDOW (-scrw / 2, scrh / 2)-(scrw / 2, -scrh / 2) '            create viewport window, Cap'n Kirk spends his days staring at this
  31. _PRINTMODE _KEEPBACKGROUND '                                    stars show through help menu
  32. DO '                                                            draw the stars
  33.     x& = _KEYHIT
  34.     IF x& <> 0 THEN
  35.         IF x& = 104 THEN hlptog = NOT hlptog '                  toggle help menu
  36.         IF x& = 100 THEN dattog = NOT dattog '                  toggle data bar
  37.         IF x& = 43 THEN speed = speed + 1 '                     increase speed
  38.         IF x& = 45 THEN speed = speed - 1 '                     decrease speed
  39.         IF x& = 19200 THEN xch = 1 '                            turn left
  40.         IF x& = 19712 THEN xch = -1 '                           turn right
  41.         IF x& = 18432 THEN ych = -1 '                           turn up
  42.         IF x& = 20480 THEN ych = 1 '                            turn down
  43.         IF x& = 122 THEN vwport = vwport * 2 '                  zoom x 2
  44.         IF x& = 120 THEN vwport = 1200 '                        zoom normal
  45.         IF x& = 97 OR x& = 115 THEN '
  46.             IF x& = 97 THEN '                                   add stars
  47.                 starcount = starcount + 1 '
  48.                 AddStar starcount '
  49.             ELSE '
  50.                 starcount = starcount - 1 '                     subtract stars
  51.                 REDIM _PRESERVE p(starcount) AS star '
  52.             END IF
  53.         END IF '
  54.     END IF '
  55.     CLS '
  56.     FOR x = 1 TO starcount '                                    iterate through all stars
  57.  
  58.         IF xch <> 0 OR ych <> 0 THEN '                          not actually a proper transformation
  59.             p(x).x = p(x).x + p(x).z * SIN(_D2R(xch * 0.3)) '   slew stars for left/right turns
  60.             p(x).y = p(x).y + p(x).z * SIN(_D2R(ych * 0.3)) '   slew stars for up/down pitch
  61.         END IF
  62.  
  63.         IF p(x).z > 0 THEN 'ignore those behind, change to a dot product test if a facing vector is later added
  64.             p(x).xa = p(x).x / p(x).z * vwport '                get relative screen position from absolute position for x & y
  65.             p(x).ya = p(x).y / p(x).z * vwport
  66.  
  67.             IF ABS(p(x).xa) < ABS(scrw / 2) AND ABS(p(x).ya) < ABS(scrh / 2) THEN 'place the star if within the viewport
  68.                 dst& = (_HYPOT(_HYPOT(ABS(p(x).x), ABS(p(x).y)), ABS(p(x).z))) / (vwport / 1200) 'distance to star / zoom
  69.                 fdf& = (dst& - 25904) / 16 '                    far fade in factor;
  70.                 IF fdf& < 0 THEN fdf& = 0
  71.                 fdn& = (dst& - 6806) / 32 '                     near fade in factor; mid-field swell
  72.                 IF fdn& < 0 THEN fdn& = 0
  73.                 fdp& = (dst& - 938) / 12 '                      proximity swell
  74.                 IF fdp& < 0 THEN fdp& = 0
  75.                 SELECT CASE dst&
  76.                     CASE 0 TO 3999
  77.                         FCirc p(x).xa, p(x).ya, bsrad + 1, _RGBA32(p(x).r, p(x).g, p(x).b, 255 - fdp&) 'proximity star plot
  78.                         FCirc p(x).xa, p(x).ya, bsrad, _RGBA32(p(x).r, p(x).g, p(x).b, 255)
  79.                     CASE 4000 TO 14999
  80.                         FCirc p(x).xa, p(x).ya, bsrad, _RGBA32(p(x).r, p(x).g, p(x).b, 255 - fdn&) 'near star plot
  81.                         PSET (p(x).xa, p(x).ya), _RGBA32(p(x).r, p(x).g, p(x).b, 255)
  82.                     CASE IS > 15000
  83.                         PSET (p(x).xa, p(x).ya), _RGBA32(p(x).r, p(x).g, p(x).b, 255 - fdf&) 'far star plot
  84.                 END SELECT
  85.             END IF
  86.  
  87.         END IF
  88.  
  89.         p(x).z = p(x).z - speed '                               move the star closer to the viewer
  90.         IF speed < 0 THEN
  91.             IF p(x).z > 30000 THEN
  92.                 ReplaceStar x, p(x).z - 30000 '                 add new stars as existing ones fade to black (reverse)
  93.             END IF
  94.         ELSE
  95.             IF p(x).z < -30000 THEN
  96.                 ReplaceStar x, p(x).z + 30000 '                 add new stars as existing ones go behind the viewer (forward)
  97.             END IF
  98.         END IF
  99.     NEXT x
  100.     xch = 0: ych = 0
  101.     IF hlptog THEN HelpScreen
  102.     IF dattog THEN Footer
  103.     _DISPLAY '                                                  eliminate screen flicker
  104.     _LIMIT 500 '                                                smooth out the action
  105.  
  106.  
  107. SUB PopVoid '                                                   Do an initial population of stars
  108.  
  109.     FOR x = 1 TO starcount '                                    place a 'starcount' # of stars randomly in a 3D space
  110.         RANDOMIZE TIMER
  111.         p(x).x = INT(RND * 60000) - 30000
  112.         p(x).y = INT(RND * 60000) - 30000
  113.         p(x).z = INT(RND * 60000) - 30000
  114.         t% = INT(RND * 110) - 55 '                              star spectrum/color
  115.         ch = INT(RND * 6)
  116.         IF ch < 5 THEN
  117.             p(x).r = 200 + t%: p(x).b = 200 - t%
  118.         ELSE
  119.             p(x).r = 200 - t%: p(x).b = 200 + t%
  120.         END IF
  121.         g% = INT(RND * 6)
  122.         IF g% = 0 THEN
  123.             g1% = INT(RND * 7) + 1
  124.             p(x).g = 200 + gi% ^ 2
  125.         ELSE
  126.             p(x).g = 200
  127.         END IF
  128.     NEXT x
  129.  
  130. END SUB 'PopVoid
  131.  
  132.  
  133. SUB ReplaceStar (var AS INTEGER, insert AS INTEGER) '           This replaces any star that goes beyond z limits
  134.  
  135.     p(var).x = INT(RND * 60000) - 30000 '                       New x,y,z but keep old color for simplicity sake
  136.     p(var).y = INT(RND * 60000) - 30000
  137.     p(var).z = p(var).z + insert
  138.  
  139. END SUB 'ReplaceStar
  140.  
  141.  
  142. SUB FCirc (CX AS INTEGER, CY AS INTEGER, RR AS INTEGER, C AS _UNSIGNED LONG)
  143.     DIM R AS INTEGER, RError AS INTEGER
  144.     DIM X AS INTEGER, Y AS INTEGER
  145.  
  146.     R = ABS(RR)
  147.     RError = -R
  148.     X = R
  149.     Y = 0
  150.     IF R = 0 THEN PSET (CX, CY), C: EXIT SUB
  151.     LINE (CX - X, CY)-(CX + X, CY), C, BF
  152.     WHILE X > Y
  153.         RError = RError + Y * 2 + 1
  154.         IF RError >= 0 THEN
  155.             IF X <> Y + 1 THEN
  156.                 LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  157.                 LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  158.             END IF
  159.             X = X - 1
  160.             RError = RError - X * 2
  161.         END IF
  162.         Y = Y + 1
  163.         LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  164.         LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  165.     WEND
  166. END SUB 'FCirc
  167.  
  168.  
  169. SUB AddStar (x AS INTEGER)
  170.  
  171.     REDIM _PRESERVE p(x) AS star
  172.     p(x).x = INT(RND * 60000) - 30000
  173.     p(x).y = INT(RND * 60000) - 30000
  174.     IF speed > 0 THEN
  175.         p(x).z = 30000
  176.     ELSE
  177.         p(x).z = -30000
  178.     END IF
  179.     t% = INT(RND * 110) - 55
  180.     ch = INT(RND * 6)
  181.     IF ch < 5 THEN
  182.         p(x).r = 200 + t%: p(x).b = 200 - t%
  183.     ELSE
  184.         p(x).r = 200 - t%: p(x).b = 200 + t%
  185.     END IF
  186.     g% = INT(RND * 6)
  187.     IF g% = 0 THEN
  188.         g1% = INT(RND * 7) + 1
  189.         p(x).g = 200 + gi% ^ 2
  190.     ELSE
  191.         p(x).g = 200
  192.     END IF
  193.  
  194. END SUB 'AddStar
  195.  
  196. SUB HelpScreen
  197.  
  198.     mi = (scrh / 2) - (13 * 16 / 2) '                           change ...(x * 16 / 2) to x= number of items in menu
  199.     _PRINTSTRING (scrw / 2 - 150, mi), "<+> increase speed", 0
  200.     _PRINTSTRING (scrw / 2 - 150, mi + 16), "<-> decrease speed", 0
  201.     _PRINTSTRING (scrw / 2 - 150, mi + 32), "<left arrow> turn left", 0
  202.     _PRINTSTRING (scrw / 2 - 150, mi + 48), "<right arrow> turn right", 0
  203.     _PRINTSTRING (scrw / 2 - 150, mi + 64), "<up arrow> pitch up", 0
  204.     _PRINTSTRING (scrw / 2 - 150, mi + 80), "<down arrow> pitch down", 0
  205.     _PRINTSTRING (scrw / 2 - 150, mi + 96), "<z> zoom x 2", 0
  206.     _PRINTSTRING (scrw / 2 - 150, mi + 112), "<x> zoom original", 0
  207.     _PRINTSTRING (scrw / 2 - 150, mi + 128), "<a> add stars", 0
  208.     _PRINTSTRING (scrw / 2 - 150, mi + 144), "<s> subtract stars", 0
  209.     _PRINTSTRING (scrw / 2 - 150, mi + 160), "<h> toggle this list on/off", 0
  210.     _PRINTSTRING (scrw / 2 - 150, mi + 176), "<d> toggle data bar", 0
  211.     _PRINTSTRING (scrw / 2 - 150, mi + 192), "<ESC> quit", 0
  212.  
  213. END SUB 'HelpScreen
  214.  
  215. SUB Footer
  216.  
  217.     _PRINTSTRING (5, scrh - 60), "Warp " + STR$(speed), 0 '     speed indicator
  218.     _PRINTSTRING (scrw / 2 - 50, scrh - 60), "Stars = " + STR$(starcount), 0
  219.     _PRINTSTRING (scrw - 100, scrh - 60), "Mag. x" + STR$(vwport / 1200), 0 '   magnification factor
  220.  
  221. END SUB 'Footer
  222.  
« Last Edit: March 14, 2020, 01:20:49 pm by OldMoses »

Offline 40wattstudio

  • Newbie
  • Posts: 82
    • 40wattstudio
Re: Best practices for a consistent framerate
« Reply #9 on: March 14, 2020, 01:27:35 pm »

I like to work with .PNG files exclusively for two reasons. First, they are lossless, meaning you wont get any of the artifacting around boundaries in images like you do with JPEGs. Secondly, they support a transparent (alpha) layer, meaning I can create a .PNG in my favorite graphics program, designate a color as transparent, and QB64 will see and use the transparent layer.

Oh, also, if you designate large images as hardware types (vs software) then they speed up dramatically when drawing them.

I've been preferring .png as well since I use a lot of alpha/transparent layers. Makes the game look a whole lot better and allows for some pretty cool effects!

Not sure what you mean by designating the images as hardware types. Is there a special statement for that?

Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
Re: Best practices for a consistent framerate
« Reply #10 on: March 14, 2020, 02:34:26 pm »
Not sure what you mean by designating the images as hardware types. Is there a special statement for that?

Here is the Wiki information on hardware images:

http://www.qb64.org/wiki/Hardware_images
In order to understand recursion, one must first understand recursion.

Offline 40wattstudio

  • Newbie
  • Posts: 82
    • 40wattstudio
Re: Best practices for a consistent framerate
« Reply #11 on: March 14, 2020, 10:54:50 pm »

A FOR loop is slower than a DO loop or a WHILE loop.


I can definitely see the difference now!
So I made a quick little program to compare how long it would take to load 361 .png files (2000x2000 pixels, 2.89MB each)

Using the FOR NEXT loop . . .
Code: QB64: [Select]
  1.     FOR i = 0 TO maxrotation
  2.         winpath$ = "SCRAPSHIP\gfx\eevee\" + LTRIM$(STR$(i)) + ".png"
  3.         LOCATE 1, 1
  4.         PRINT winpath$
  5.         planetrotation(i) = _LOADIMAGE(winpath$)
  6.         _PUTIMAGE (win.X, win.Y), planetrotation(i)
  7.     NEXT
  8.  
. .  it took 4 minutes and 4 seconds for all the pictures to load.

So then I tried a DO WHILE LOOP . . .
Code: QB64: [Select]
  1.     i = 0
  2.     DO WHILE i < maxrotation
  3.         winpath$ = "SCRAPSHIP\gfx\eevee\" + LTRIM$(STR$(i)) + ".png"
  4.         LOCATE 1, 1
  5.         PRINT winpath$
  6.         planetrotation(i) = _LOADIMAGE(winpath$)
  7.         _PUTIMAGE (win.X, win.Y), planetrotation(i)
  8.         i = i + 1
  9.     LOOP
  10.  
. . . and that took 3 minutes and 44 seconds. So 20 seconds faster, but still too painfully slow in the context of a video game.

I definitely need to use .png files for the transparency (which is a bummer because from what I've read, .jpg is faster to load).
Maybe I can trim the size of the pictures down or display only every second or third rotation frame.

@OldMoses, thanks for sharing the Starfield program. Reminded me a little of games like Star Voyager on the NES. :)

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • Steve’s QB64 Archive Forum
Re: Best practices for a consistent framerate
« Reply #12 on: March 14, 2020, 11:40:53 pm »
Not a very accurate time comparison run there...

LOCATE and PRINT are both very slow processes and will often bottleneck any sort of performance for you. _PRINTSTRING is a little bit better, but not by much.  You can honestly -- and I'm not kidding here -- use PSET to plot every pixel of a font to the screen, faster than PRINT will print to the screen!

Since your concern is currently load times, just compare load times...

FOR I = 0 TO maxcount
.   Planetrotation(I) =_LOADIMAGE
NEXT

Compared the load time to the same as a DO...LOOP

********

At this point, every screen is in loaded in memory and all your program needs is to_PUTIMAGE them to display, and timing performance of it is a completely different can of worms...
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline 40wattstudio

  • Newbie
  • Posts: 82
    • 40wattstudio
Re: Best practices for a consistent framerate
« Reply #13 on: March 15, 2020, 07:58:18 am »
Not a very accurate time comparison run there...

LOCATE and PRINT are both very slow processes and will often bottleneck any sort of performance for you. _PRINTSTRING is a little bit better, but not by much.  You can honestly -- and I'm not kidding here -- use PSET to plot every pixel of a font to the screen, faster than PRINT will print to the screen!

My bad, I forgot to mention that some of those lines I commented out when I ran them. I just had them all together for convenience.
Anyways, I resized all of my pictures to 1500x1500 pixels. These are the results only running _LOADIMAGE:
FOR ... NEXT = 1 minute 28 seconds
DO LOOP = 1 minute 19 seconds

That's pretty crazy about the PRINT statement! But it's good you mention that because I do have a couple PRINT statements in my program (mostly for debugging purposes).


Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Re: Best practices for a consistent framerate
« Reply #14 on: March 15, 2020, 11:32:23 am »
I have timed DO versus FOR versus WHILE versus GOTO just doing millions of calculations like adding 10 million numbers. FOR is clearly the slowest.