Author Topic: Math wizards, I need help  (Read 4244 times)

0 Members and 1 Guest are viewing this topic.

Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
    • View Profile
Math wizards, I need help
« on: September 21, 2018, 06:34:40 pm »
I've got a bad cold today and can't think. I have a math problem here that needs solved but I just can't seem to get my mind wrapped around it.

I'm setting up independent frames rates for the sprite library's animation routines. The main loop will be the main frame rate, then each sprite will have it's own frame rate it can be drawn at.

Consider the following:

Main Frame Rate = 30
Sprite Frame Rate = 20
Frames To Skip = 10 (30 - 20) main frame rate - sprite frame rate
SKIP every 3rd frame (30 / 10) main frame rate / frames to skip

Main Frame Rate = 30
Sprite Frame Rate = 15
Frames To Skip = 15 (30 - 15) main frame rate - sprite frame rate
SKIP every 2nd frame (30 / 15) main frame rate / frames to skip


everything above this line we need to SKIP frames
-------------------------- (main frame rate / 2)
everything below this line we need to DRAW frames

Main Frame Rate = 30
Sprite Frame Rate = 10
DRAW every 3rd frame (30 / 10) main frame rate / sprite frame rate

Main Frame Rate = 30
Sprite Frame Rate = 5
DRAW every 6th frame (30 / 5) main frame rate / sprite frame rate

As you can see sprites would either need to be drawn or skipped at certain intervals to achieve their frame rate within the main frame rate. Any sprite frame rate that is equal to or greater than the main frame rate divided by two will require having a frame drawing SKIPPED now and then.

Any sprite frame rate that is less than the main frame rate divided by two will require having a frame drawing DRAWN now and then.

Is there an algorithm that sums this all up or will I need to manually code for two separate instances? It feels like there is a really simple solution here but I'll be darned if I can see it.
In order to understand recursion, one must first understand recursion.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Math wizards, I need help
« Reply #1 on: September 21, 2018, 09:10:33 pm »
I am unfamiliar with frame rates but to me it looks like you want to do one sprite every loop, another every other loop, a 3rd every 3rd loop and a 4th every 4th loop

If that is so then a loopcounter lc = lc + 1 every loop*
draw or move  sprite 1 every loop
                      sprite 2 every lc mod 2 = 0 loop
                      sprite 3 every lc mod 3 = 0 loop
                      sprite 4 every lc mod 4 = 0 loop

*if you want to reset lc so it stays periodic  lc = (lc + 1) mod 12


Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
    • View Profile
Re: Math wizards, I need help
« Reply #2 on: September 21, 2018, 11:21:10 pm »
Yep, I tried something like your suggestion but it would only work half the time, either for rates smaller than half the global rate, or rates larger than half the global rate.

I ended up figuring something out that works pretty well. Here is where I seed the skip number:

Code: QB64: [Select]
  1.     IF SL_framerate = framerate THEN '                                                                  animation and global frame rates the same?
  2.         SL_sprite(handle).anim.skip = 0 '                                                               yes, nothing needs to be done with frames
  3.     ELSEIF framerate >= SL_framerate \ 2 THEN '                                                         no, sprite frame rate 1/2 or less of master frame rate?
  4.         SL_sprite(handle).anim.skip = SL_framerate \ (SL_framerate - framerate) '                       yes, calculate every frame to skip
  5.     ELSE '                                                                                              no, sprite frame rate is greater than 1/2 of master frame rate
  6.         SL_sprite(handle).anim.skip = SL_framerate \ framerate '                                        calculate every frame to draw
  7.     END IF
  8.  

And here is where the code decides whether to skip or draw a frame cell:

Code: QB64: [Select]
  1.             ' auto animation
  2.  
  3.             IF SL_sprite(handle).anim.auto THEN '                                                       is auto animation enabled?
  4.                 IF SL_sprite(handle).anim.skip = 0 THEN '                                               always go to next cell?
  5.                     nextcell = -1 '                                                             (TRUE)  yes, draw next cell
  6.                 ELSE '                                                                                  no
  7.  
  8.                     ' draw or skip next cell
  9.  
  10.                     SL_sprite(handle).anim.frame = SL_sprite(handle).anim.frame + 1 '                   increment frame counter
  11.                     IF SL_sprite(handle).anim.skip = SL_sprite(handle).anim.frame THEN '                time to skip or go to next cell?
  12.                         SL_sprite(handle).anim.frame = 0 '                                              yes, reset the frame counter
  13.                         IF SL_sprite(handle).anim.framerate >= SL_framerate \ 2 THEN '                  should this cell be skipped?
  14.                             nextcell = 0 '                                                     (FALSE)  yes, skip next cell
  15.                         ELSE '                                                                          no
  16.                             nextcell = -1 '                                                     (TRUE)  go to next cell
  17.                         END IF
  18.                     ELSEIF SL_sprite(handle).anim.framerate >= SL_framerate \ 2 THEN '                  no, is sprite frame rate equal or greater than half global frame rate?
  19.                         nextcell = -1 '                                                                 yes, go to next cell
  20.                     END IF
  21.                 END IF
  22.  

It works exactly like it should but I'm sure there has to be an algorithmic way to do this.
« Last Edit: September 21, 2018, 11:55:00 pm by TerryRitchie »
In order to understand recursion, one must first understand recursion.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Math wizards, I need help
« Reply #3 on: September 22, 2018, 08:58:44 pm »
A rate needs to be defined as a number of units per (divided by) some other unit.

I can not figure what units you are working with so I experimented with Number of Loops per Second which is used with setting the _LIMIT in the the main display loop. In this system, frameRate for changing frames is some fractional multiplier of Number of Loops per Second.

This system seems to work OK here in attached where the man walking uphill (frame changing 1/8 the loops per second) is going at a rate 1/4 the men coming downhill (frame changing 1/2 the number of loops per second).
Code: QB64: [Select]
  1. _TITLE "Walking Man #2 B+ 2018-09-22"
  2.  
  3. CONST xmax = 800
  4. CONST ymax = 600
  5. SCREEN _NEWIMAGE(xmax, ymax, 32)
  6. _SCREENMOVE 360, 60
  7.  
  8. walk& = _LOADIMAGE("walking720x146.png") ' 8 positions at 90 x 146   walk& is same as slot number
  9. manW = 90 'width of man image
  10. manH = 146 'height of man image
  11.  
  12. TYPE manType
  13.     x AS SINGLE
  14.     y AS SINGLE
  15.     dx AS SINGLE
  16.     dy AS SINGLE
  17.     frame AS INTEGER
  18.     frameRate AS SINGLE
  19.  
  20. DIM man1 AS manType
  21. man1.x = 0
  22. man1.y = ymax - manH
  23. man1.dx = 1
  24. man1.dy = -.625
  25. man1.frame = 0
  26. man1.frameRate = 1 / 8 'of loops per sec
  27.  
  28.  
  29. DIM man2 AS manType
  30. man2.x = xmax + manW
  31. man2.y = 0
  32. man2.dx = -4
  33. man2.dy = 2.5
  34. man2.frame = 0
  35. man2.frameRate = 1 / 2 'of loops per sec
  36.  
  37.  
  38. manN = 0 'man number 0 to 7 as walks ie, manN = (manN + 1) mod 8
  39. GLS = 30 ' Global Loops per Second
  40.     CLS
  41.     lc = (lc + 1) MOD GLS
  42.  
  43.     _PUTIMAGE (man1.x, man1.y)-STEP(manW, manH), walk&, 0, (man1.frame * 90, 0)-STEP(manW, manH)
  44.     _PUTIMAGE (man2.x, man2.y)-STEP(-manW, manH), walk&, 0, (man2.frame * 90, 0)-STEP(manW, manH)
  45.     man1.x = (man1.x + man1.dx)
  46.     man1.y = (man1.y + man1.dy)
  47.     IF man1.x > xmax THEN man1.x = -manW: man1.y = ymax - manH
  48.     man1.frame = INT(man1.frameRate * lc) MOD 8
  49.  
  50.     man2.x = (man2.x + man2.dx)
  51.     man2.y = (man2.y + man2.dy)
  52.     IF man2.x < -manW THEN man2.x = xmax: man2.y = 0
  53.     man2.frame = INT(man2.frameRate * lc) MOD 8
  54.  
  55.     _DISPLAY
  56.     _LIMIT GLS
  57.  
« Last Edit: September 22, 2018, 09:48:01 pm by bplus »

Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
    • View Profile
Re: Math wizards, I need help
« Reply #4 on: September 22, 2018, 11:42:25 pm »
I downloaded your code and looking at it now for ideas. Thank you :)

Yeah, this code works like expected. I can put any ratio I want for manx.frameRate and that frame rate is achieved.

Thank you for this!
« Last Edit: September 22, 2018, 11:50:24 pm by TerryRitchie »
In order to understand recursion, one must first understand recursion.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Math wizards, I need help
« Reply #5 on: September 23, 2018, 02:36:40 pm »
Terry, I have to warn. I am getting a little back and forth dance when I use a rate of 1/3 instead of 1/2 for man going downstairs. So this method needs more testing. Since 8 not dividable by 3 might be a rounding issue when choosing correct frame.

I change GLS to 24 divisible by both 8 and 3 and all is smooth for both 1/2 and 1/3.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Math wizards, I need help
« Reply #6 on: September 23, 2018, 03:37:54 pm »
Fixed and I can't imagine at moment what could go wrong next?

Now the images are not tied to the _LIMIT. The only rule is to use whole numbers for dFrame (delta Frame) = number of loops to pass for each frame change. There is now loop counter for each object = fCount.

Break this:
Code: QB64: [Select]
  1. _TITLE "Walking Man #2 B+ 2018-09-23 fixed?"
  2.  
  3. CONST xmax = 800
  4. CONST ymax = 600
  5. SCREEN _NEWIMAGE(xmax, ymax, 32)
  6. _SCREENMOVE 360, 60
  7.  
  8. walk& = _LOADIMAGE("walking720x146.png") ' 8 positions at 90 x 146   walk& is same as slot number
  9. manW = 90 'width of man image
  10. manH = 146 'height of man image
  11.  
  12. TYPE manType
  13.     x AS SINGLE
  14.     y AS SINGLE
  15.     dx AS SINGLE
  16.     dy AS SINGLE
  17.     frame AS INTEGER 'delta frame change frame when fc = df
  18.     dFrame AS INTEGER
  19.     fCount AS INTEGER
  20.  
  21. DIM man1 AS manType
  22. man1.x = 0
  23. man1.y = ymax - manH
  24. man1.dx = 1
  25. man1.dy = -.625
  26. man1.frame = 0
  27. man1.dFrame = 6 'loops for each frame change
  28. man1.fCount = 0
  29.  
  30. DIM man2 AS manType
  31. man2.x = xmax + manW
  32. man2.y = 0
  33. man2.dx = -4
  34. man2.dy = 2.5
  35. man2.frame = 0
  36. man2.dFrame = 4 'of loops for each frame change
  37. man2.fCount = 0
  38.  
  39. manN = 0 'man number 0 to 7 as walks ie, manN = (manN + 1) mod 8
  40. GLS = 30 ' Global Loops per Second
  41.     CLS
  42.  
  43.     _PUTIMAGE (man1.x, man1.y)-STEP(manW, manH), walk&, 0, (man1.frame * 90, 0)-STEP(manW, manH)
  44.     _PUTIMAGE (man2.x, man2.y)-STEP(-manW, manH), walk&, 0, (man2.frame * 90, 0)-STEP(manW, manH)
  45.     man1.x = (man1.x + man1.dx)
  46.     man1.y = (man1.y + man1.dy)
  47.     IF man1.x > xmax THEN man1.x = -manW: man1.y = ymax - manH
  48.     man1.fCount = man1.fCount + 1
  49.     IF man1.fCount = man1.dFrame THEN man1.fCount = 0: man1.frame = (man1.frame + 1) MOD 8
  50.  
  51.     man2.x = (man2.x + man2.dx)
  52.     man2.y = (man2.y + man2.dy)
  53.     IF man2.x < -manW THEN man2.x = xmax: man2.y = 0
  54.     man2.fCount = man2.fCount + 1
  55.     IF man2.fCount = man2.dFrame THEN man2.fCount = 0: man2.frame = (man2.frame + 1) MOD 8
  56.  
  57.     _DISPLAY
  58.     _LIMIT GLS
  59.  
  60.  

I think this is easier to understand and use.
« Last Edit: September 23, 2018, 03:52:55 pm by bplus »

Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
    • View Profile
Re: Math wizards, I need help
« Reply #7 on: September 23, 2018, 03:51:52 pm »
Excellent, I planned on implementing your changes tonight to my code. Thank you finding this issue and offering a fix.

I'm working on collision routines at the moment. Should be done with those soon then I can revisit independent frame rate code.

Thanks again!
In order to understand recursion, one must first understand recursion.

Offline johnno56

  • Forum Resident
  • Posts: 1270
  • Live long and prosper.
    • View Profile
Re: Math wizards, I need help
« Reply #8 on: September 23, 2018, 07:06:04 pm »
... now where have I seen THIS animation before?  Don't tell me... It will eventually come to me... I know I've seen it before... Oh. The woes of getting old... lol
Logic is the beginning of wisdom.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Math wizards, I need help
« Reply #9 on: September 23, 2018, 07:13:25 pm »
LOL That's right, graphics provided by Johnno, thanks once again.