Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Topics - TerryRitchie

Pages: 1 2 [3] 4
31
QB64 Discussion / _CLEARCOLOR() Usage
« on: September 08, 2018, 05:05:45 pm »
I swear years ago I could load a 32bit PNG file in that already had an alpha channel defined and then use _CLEARCOLOR to identify the alpha channel color.

_CLEARCOLOR is always returning 0 for me when polling a loaded 32bit PNG image.

Am I correct, or is my age showing again?

There's got to be another way than scanning each pixel in the image and comparing it to _ALPHA32() for a value of zero to find the transparent layer.

32
QB64 Discussion / Hardware vs Software Images
« on: September 07, 2018, 12:58:25 am »
It's been a Loooong time since I have played around with hardware image capability in QB64, and even then it was in the experimental stage.

Just so I have this straight, once I have committed an image as hardware (mode 33) I can do nothing with that image except for displaying it (_PUTIMAGE, _MAPTRIANGLE), or copying it (_COPYIMAGE).

Even trying to set a hardware image as a source, to say read a POINT() from it will not work, correct?

If I need to make a change to a hardware image, I'll need to have a software image copy of it, make the changes on the software image, then once again convert the image to hardware with _COPYIMAGE to another handle. Is that correct?

33
Programs / Sprite Library Revisited
« on: September 06, 2018, 01:44:41 am »
[UPDATE:] This now contains the new sprite library work in progress.

Original post below

I'm currently in the process of updating my sprite library to take advantage of new features available in QB64 that were not present in 2012 when I wrote the library. I also want to enhance the collision detection routines (and finally get a fully working pixel perfect detection routine as well). One problem when working with sprite sheets is that every sprite needs to be the same size. As an example look below at the sprite sheet I created of a TR3B UFO a few days ago. Each sprite is 266x266 in size, however there is a lot of wasted space on many of them, especially the sprites in the middle. This not only takes up RAM but does not play well with collision detection as two dead spaces can trigger a collision when the images contained within did not actually touch. I purposely designed this sprite sheet to see if I could overcome these issues.

Below is some proof of concept code I wrote that detects the image within each sprite, cuts each individual sprite down to its minimum size, then saves an x,y offset value so the sprites can be successfully lined up later even though they are wildly different in size. This should allow rectangular collision detection to be much more accurate and the memory used by the sprites much less.

Keep in mind, the code is sloppy and will need to be cleaned up but I wanted to get other's opinion on this. Do you think I am on the right track or is there a better way of achieving this that I need to know about? Could my image detection routine be done simpler or in a better manner?

Code: QB64: [Select]
  1. '*
  2. '* constants used with SL_FLIP_SPRITE subroutine
  3. '*
  4.  
  5. CONST SL_NOFLIP = 0
  6. CONST SL_HORIZONTAL = 1
  7. CONST SL_VERTICAL = 2
  8. CONST SL_FLIPBOTH = 3
  9.  
  10. '*
  11. '* constants used with SL_NEW_SPRITE_SHEET function
  12. '*
  13.  
  14. CONST SL_SHEETTRANSPARENCY = -1 '       use sheet's transparency info (.PNG)
  15. CONST SL_SETTRANSPARENCY = 0 '          manually set transparency
  16. CONST SL_NOTRANSPARENCY = 1 '           don't use transparency with sheet
  17.  
  18. '*
  19. '* constants used with SL_NEW_SPRITE function
  20. '*
  21.  
  22. CONST SL_NOSAVE = 0 '                   sprite will not save background
  23. CONST SL_SAVE = -1 '                    sprite will save background
  24.  
  25.  
  26. '*
  27. '* type declarations
  28. '*
  29.  
  30. TYPE SL_SHEET ' *********************** sprite sheet database ***************************************
  31.     image AS LONG '                     software sprite image
  32.     mask AS LONG '                      software mask image
  33.     spritewidth AS INTEGER '            width of sprite
  34.     spriteheight AS INTEGER '           height of sprite
  35.     collx1 AS INTEGER '                 collision box top left x
  36.     colly1 AS INTEGER '                 collision box top left y
  37.     collx2 AS INTEGER '                 collision box bottom right x
  38.     colly2 AS INTEGER '                 collision box bottom right y
  39.     transparency AS INTEGER '           -1 (TRUE) if sheet uses transparency
  40.  
  41. TYPE SL_SPRITE ' ********************** sprite database *********************************************
  42.     inuse AS INTEGER '                  this array index in use
  43.     sheet AS INTEGER '                  sheet sprite belongs to
  44.     column AS INTEGER '                 the column on the sheet the sprite resides
  45.     row AS INTEGER '                    the row on the sheet the sprite resides
  46.     sprite AS LONG '                    hardware image
  47.     image AS LONG '                     software image
  48.     mask AS LONG '                      software mask image
  49.     spritewidth AS INTEGER '            width of sprite
  50.     spriteheight AS INTEGER '           height of sprite
  51.     rsprite AS LONG '                   rotated sprite hardware image
  52.     rimage AS LONG '                    rotated sprite software image
  53.     rmask AS LONG '                     rotated sprite mask software image
  54.     rspritewidth AS INTEGER '           rotated sprite image width
  55.     rspriteheight AS INTEGER '          rotated sprite image height
  56.     background AS LONG '                background image behind sprite
  57.     xreal AS SINGLE '                   x location of sprite (center point)
  58.     yreal AS SINGLE '                   y location of sprite (center point)
  59.     xint AS INTEGER '                   x location of sprite on screen INT(xreal) (center point)
  60.     yint AS INTEGER '                   y location of sprite on screen INT(yreal) (center point)
  61.     xactual AS INTEGER '                x location of sprite on screen (upper left x)
  62.     yactual AS INTEGER '                y location of sprite on screen (upper left y)
  63.     restore AS INTEGER '                -1 (true) if sprite restores background
  64.     collx1 AS INTEGER '                 collision box top left x
  65.     colly1 AS INTEGER '                 collision box top left y
  66.     collx2 AS INTEGER '                 collision box bottom right x
  67.     colly2 AS INTEGER '                 collision box bottom right y
  68.     flip AS INTEGER '                   flip horizontally, vertically, or both
  69.     rotation AS SINGLE '                rotation angle of sprite (0 - 359.999)
  70.     transparency AS INTEGER '           -1 (TRUE) if sprite uses transparency
  71.  
  72. TYPE SL_ROTATE '*********************** precalculated rotation table ********************************
  73.     rwidth AS INTEGER '                 width of rotated sprite
  74.     rheight AS INTEGER '                height of rotated sprite
  75.     px0 AS INTEGER '                    rectangular rotation coordinates
  76.     px1 AS INTEGER
  77.     px2 AS INTEGER
  78.     px3 AS INTEGER
  79.     py0 AS INTEGER
  80.     py1 AS INTEGER
  81.     py2 AS INTEGER
  82.     py3 AS INTEGER
  83.  
  84. '*
  85. '* defined arrays
  86. '*
  87.  
  88. REDIM SL_sheet(1, 1, 1) AS SL_SHEET '   master sprite sheet array
  89. REDIM SL_sprite(1) AS SL_SPRITE '       master working sprite array
  90. REDIM SL_rotate(1, 359) AS SL_ROTATE '  precalculated rotation values
  91.  
  92. '*
  93. '* main code (for testing)
  94. '*
  95.  
  96. kongsheet = SL_NEW_SPRITE_SHEET("dkong.png", 64, 64, SL_SETTRANSPARENCY, _RGB32(255, 0, 255))
  97. mysprite% = SL_NEW_SPRITE(kongsheet, 1, 1, SL_NOSAVE)
  98. mysprite2% = SL_NEW_SPRITE(kongsheet, 1, 1, SL_NOSAVE)
  99.  
  100. 'SL_FLIP_SPRITE mysprite%, SL_NOFLIP
  101.  
  102. SCREEN _NEWIMAGE(640, 480, 32)
  103.  
  104.     _LIMIT 120
  105.     SL_PUT_SPRITE 128, 128, mysprite2%
  106.     angle = angle + 1: IF angle = 360 THEN angle = 0
  107.     SL_ROTATE_SPRITE mysprite%, angle
  108.     CIRCLE (128, 128), 64, _RGB32(255, 255, 255)
  109.     SL_PUT_SPRITE 128, 128, mysprite%
  110.     _DISPLAY
  111.  
  112.  
  113.  
  114.  
  115. '    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  116. SUB SL_ROTATE_SPRITE (handle AS INTEGER, degrees AS INTEGER) '                                                                                                                         SL_ROTATE_SPRITE
  117.     'ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
  118.     '³                    °°°±±±²²²ÛÛÛ COMMAND DESCRIPTION AND USAGE ÛÛÛ²²²±±±°°°                     ³                                °°°±±±²²²ÛÛÛ NOTES ÛÛÛ²²²±±±°°°                                ³
  119.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  120.     '³                                                                                                ³                                                                                               ³
  121.     '³                                                                                                ³                                                                                               ³
  122.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  123.     '³                            °°°±±±²²²ÛÛÛ KNOWN ISSUES ÛÛÛ²²²±±±°°°                              ³                               °°°±±±²²²ÛÛÛ CREDITS ÛÛÛ²²²±±±°°°                               ³
  124.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  125.     '³                                                                                                ³ Portions of this subroutine have code based off of Galleon's RotoZoom subroutine in the QB64  ³
  126.     '³                                                                                                ³ documentation at http://[abandoned, outdated and now likely malicious qb64 dot net website - don’t go there]/wiki/index.php?title=MAPTRIANGLE (link no longer works)      ³
  127.     '³                                                                                                ³                                                                                               ³
  128.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  129.     '³                                                                          °°°±±±²²²ÛÛÛ THEORY OF OPERATION ÛÛÛ²²²±±±°°°                                                                         ³
  130.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  131.     '³                                                                                                                                                                                                ³
  132.     '³                                                                                                                                                                                                ³
  133.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  134.     '³                                                                                °°°±±±²²²ÛÛÛ HISTORY ÛÛÛ²²²±±±°°°                                                                               ³
  135.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  136.     '³ Date: 09/11/18 by Terry Ritchie                                                                                                                                                                ³
  137.     '³     : Initial writing of code.                                                                                                                                                                 ³
  138.     '³                                                                                                                                                                                                ³
  139.     'ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
  140.  
  141.     ' declare global variables
  142.  
  143.     SHARED SL_sprite() AS SL_SPRITE '   master working sprite array
  144.     SHARED SL_rotate() AS SL_ROTATE '   precalculated rotation table
  145.  
  146.     'declare local variables
  147.  
  148.     DIM px0 AS INTEGER '                precalculated polar coordinates
  149.     DIM px1 AS INTEGER
  150.     DIM px2 AS INTEGER
  151.     DIM px3 AS INTEGER
  152.     DIM py0 AS INTEGER
  153.     DIM py1 AS INTEGER
  154.     DIM py2 AS INTEGER
  155.     DIM py3 AS INTEGER
  156.     DIM sw AS INTEGER '                 sprite width
  157.     DIM sh AS INTEGER '                 sprite height
  158.     DIM rw AS INTEGER '                 precalculated rotated sprite width
  159.     DIM rh AS INTEGER '                 precalculated rotated sprite height
  160.  
  161.     ' perform error checks
  162.  
  163.     IF NOT SL_VALID_SPRITE(handle) THEN '                                                               is this a valid sprite?
  164.         SL_ERROR "SL_ROTATE_SPRITE", 500, "" '                                                          no, report error to programmer
  165.     END IF
  166.  
  167.     ' correct degree angle if needed (needs to be 0 - 359)
  168.  
  169.     IF degrees = 360 THEN '                                                                             is it 360?
  170.         degrees = 0 '                                                                                   yes, that's the same as 0
  171.     ELSEIF degrees < 0 THEN '                                                                           is it less than 360?
  172.         DO '                                                                                            yes
  173.             degrees = dgrees + 360 '                                                                    increase by 360
  174.         LOOP UNTIL degrees > 0 '                                                                        until it's in a valid range
  175.     ELSEIF degrees > 360 THEN '                                                                         is it greater than 360?
  176.         DO '                                                                                            yes
  177.             degrees = degrees - 360 '                                                                   decrease by 360
  178.         LOOP UNTIL degrees < 360 '                                                                      until it's in a valid range
  179.     END IF
  180.     SL_sprite(handle).rotation = degrees '                                                              remember degree of rotation
  181.     IF degrees = 0 THEN EXIT SUB '                                                                      no rotation needed, leave
  182.     SL_sprite(handle).rspritewidth = SL_rotate(SL_sprite(handle).sheet, degrees).rwidth '               get precalculated rotated sprite width
  183.     SL_sprite(handle).rspriteheight = SL_rotate(SL_sprite(handle).sheet, degrees).rheight '             get precalculated rotated sprite height
  184.     px0 = SL_rotate(SL_sprite(handle).sheet, degrees).px0 '                                             get precalculated polar coordinates
  185.     px1 = SL_rotate(SL_sprite(handle).sheet, degrees).px1
  186.     px2 = SL_rotate(SL_sprite(handle).sheet, degrees).px2
  187.     px3 = SL_rotate(SL_sprite(handle).sheet, degrees).px3
  188.     py0 = SL_rotate(SL_sprite(handle).sheet, degrees).py0
  189.     py1 = SL_rotate(SL_sprite(handle).sheet, degrees).py1
  190.     py2 = SL_rotate(SL_sprite(handle).sheet, degrees).py2
  191.     py3 = SL_rotate(SL_sprite(handle).sheet, degrees).py3
  192.     rw = SL_rotate(SL_sprite(handle).sheet, degrees).rwidth '                                           get precalculated rotated sprite width
  193.     rh = SL_rotate(SL_sprite(handle).sheet, degrees).rheight '                                          get precalculated rotated sprite height
  194.     sw = SL_sprite(handle).spritewidth - 1 '                                                            get sprite width
  195.     sh = SL_sprite(handle).spriteheight - 1 '                                                           get sprite height
  196.     IF SL_sprite(handle).rimage THEN _FREEIMAGE SL_sprite(handle).rimage '                              free rotated image if it already exists
  197.     SL_sprite(handle).rimage = _NEWIMAGE(rw, rh, 32) '                                                  create rotated image
  198.     _MAPTRIANGLE (0, 0)-(0, sh)-(sw, sh), SL_sprite(handle).image TO _
  199.                  (px0, py0)-(px1, py1)-(px2, py2), SL_sprite(handle).rimage '                           map rotated sprite onto image
  200.     _MAPTRIANGLE (0, 0)-(sw, 0)-(sw, sh), SL_sprite(handle).image TO _
  201.                  (px0, py0)-(px3, py3)-(px2, py2), SL_sprite(handle).rimage
  202.     IF SL_sprite(handle).rsprite THEN _FREEIMAGE SL_sprite(handle).rsprite '                            free rotated hardware sprite if it alreadt exists
  203.     SL_sprite(handle).rsprite = _COPYIMAGE(SL_sprite(handle).rimage, 33) '                              create hardware sprite of rotated image
  204.     IF SL_sprite(handle).transparency THEN '                                                            does this sprite have a mask?
  205.         IF SL_sprite(handle).rmask THEN _FREEIMAGE SL_sprite(handle).rmask '                            yes, free mask image if it already exists
  206.         SL_sprite(handle).rmask = _NEWIMAGE(rw, rh, 32) '                                               created rotated mask image
  207.         _MAPTRIANGLE (0, 0)-(0, sh)-(sw, sh), SL_sprite(handle).mask TO _
  208.                      (px0, py0)-(px1, py1)-(px2, py2), SL_sprite(handle).rmask '                        map rotated mask onto image
  209.         _MAPTRIANGLE (0, 0)-(sw, 0)-(sw, sh), SL_sprite(handle).mask TO _
  210.                      (px0, py0)-(px3, py3)-(px2, py2), SL_sprite(handle).rmask
  211.     END IF
  212.  
  213.  
  214. '    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  215. SUB SL_FLIP_SPRITE (handle AS INTEGER, flip AS INTEGER) '                                                                                                                                SL_FLIP_SPRITE
  216.     'ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
  217.     '³                    °°°±±±²²²ÛÛÛ COMMAND DESCRIPTION AND USAGE ÛÛÛ²²²±±±°°°                     ³                                °°°±±±²²²ÛÛÛ NOTES ÛÛÛ²²²±±±°°°                                ³
  218.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  219.     '³ Sets a sprite's flipping behavior when drawn to the screen.                                    ³ - Four constants have been created for this subroutine:                                       ³
  220.     '³                                                                                                ³   : SL_NOFLIP     (0) no flipping desired (or reset flip behavior)                            ³
  221.     '³ SL_FLIP_SPRITE mysprite, SL_NOFLIP                                                             ³   : SL_HORIZONTAL (1) flip sprite horizontally                                                ³
  222.     '³                                                                                                ³   : SL_VERTICAL   (2) flip sprite vertically                                                  ³
  223.     '³ input : handle - the sprite to flip.                                                           ³   : SL_FLIPBOTH   (3) flip sprite both horizontally and vertically                            ³
  224.     '³         flip   - the type of flip desired:                                                     ³ - Once a flip behavior has been set it will remain in effect until the behavior is changed.   ³
  225.     '³                  : 0 - no flipping desired (or reset flip behavior)                            ³ - This subroutine will report an error on the following conditions:                           ³
  226.     '³                  : 1 - flip sprite horizontally                                                ³   : An invalid sprite has been requested.                                                     ³
  227.     '³                  : 2 - flip sprite vertically                                                  ³   : An invalid flip behavior.                                                                 ³
  228.     '³                  : 3 - flip sprite both horizontally and vertically                            ³                                                                                               ³
  229.     '³                                                                                                ³                                                                                               ³
  230.     '³ Sets  : SL_sprite(handle).flip = flip  (sets the flip behavior for later use)                  ³                                                                                               ³
  231.     '³                                                                                                ³                                                                                               ³
  232.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  233.     '³                            °°°±±±²²²ÛÛÛ KNOWN ISSUES ÛÛÛ²²²±±±°°°                              ³                               °°°±±±²²²ÛÛÛ CREDITS ÛÛÛ²²²±±±°°°                               ³
  234.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  235.     '³ None                                                                                           ³ None                                                                                          ³
  236.     '³                                                                                                ³                                                                                               ³
  237.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  238.     '³                                                                          °°°±±±²²²ÛÛÛ THEORY OF OPERATION ÛÛÛ²²²±±±°°°                                                                         ³
  239.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  240.     '³ A sprite array setting will be made for use by other library routines.                                                                                                                         ³
  241.     '³                                                                                                                                                                                                ³
  242.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  243.     '³                                                                                °°°±±±²²²ÛÛÛ HISTORY ÛÛÛ²²²±±±°°°                                                                               ³
  244.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  245.     '³ Date: 09/11/18 by Terry Ritchie                                                                                                                                                                ³
  246.     '³     : Initial writing of code.                                                                                                                                                                 ³
  247.     '³                                                                                                                                                                                                ³
  248.     'ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
  249.  
  250.     ' declare global variables
  251.  
  252.     SHARED SL_sprite() AS SL_SPRITE '   master working sprite array
  253.  
  254.     ' perform error checks
  255.  
  256.     IF NOT SL_VALID_SPRITE(handle) THEN '                                                               is this a valid sprite?
  257.         SL_ERROR "SL_FLIP_SPRITE", 400, "" '                                                            no, report error to programmer
  258.     END IF
  259.     IF flip < 0 OR flip > 3 THEN '                                                                      valid flip behavior requested?
  260.         SL_ERROR "SL_FLIP_SPRITE", 401, "" '                                                            no, report error to programmer
  261.     END IF
  262.     SL_sprite(handle).flip = flip '                                                                     set flipping behavior
  263.  
  264.  
  265. '    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  266. SUB SL_PUT_SPRITE (x AS SINGLE, y AS SINGLE, handle AS INTEGER) '                                                                                                                         SL_PUT_SPRITE
  267.     'ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
  268.     '³                    °°°±±±²²²ÛÛÛ COMMAND DESCRIPTION AND USAGE ÛÛÛ²²²±±±°°°                     ³                                °°°±±±²²²ÛÛÛ NOTES ÛÛÛ²²²±±±°°°                                ³
  269.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  270.     '³ Places a sprite on the current _DEST (normally screen) at the coordinates provided.            ³ - The x and y values supplied by the programmer can be sent in as single precision to allow   ³
  271.     '³                                                                                                ³   for fine x and y increments. Internally the final x and y values needed for image placement ³
  272.     '³ SL_PUT_SPRITE 100, 100, mysprite%                                                              ³   are converted to integer values.                                                            ³
  273.     '³                                                                                                ³                                                                                               ³
  274.     '³ Input : x      - x location (column) to place sprite.                                          ³                                                                                               ³
  275.     '³         y      - y location (row) to place sprite.                                             ³                                                                                               ³
  276.     '³         handle - the sprite to place on the screen.                                            ³                                                                                               ³
  277.     '³                                                                                                ³                                                                                               ³
  278.     '³ Sets  :                                                                                        ³                                                                                               ³
  279.     '³                                                                                                ³                                                                                               ³
  280.     '³                                                                                                ³                                                                                               ³
  281.     '³                                                                                                ³                                                                                               ³
  282.     '³                                                                                                ³                                                                                               ³
  283.     '³                                                                                                ³                                                                                               ³
  284.     '³ Errors: All reported errors will be in the 300 - 399 range for this function.                  ³                                                                                               ³
  285.     '³                                                                                                ³                                                                                               ³
  286.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  287.     '³                            °°°±±±²²²ÛÛÛ KNOWN ISSUES ÛÛÛ²²²±±±°°°                              ³                               °°°±±±²²²ÛÛÛ CREDITS ÛÛÛ²²²±±±°°°                               ³
  288.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  289.     '³                                                                                                ³                                                                                               ³
  290.     '³                                                                                                ³                                                                                               ³
  291.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  292.     '³                                                                          °°°±±±²²²ÛÛÛ THEORY OF OPERATION ÛÛÛ²²²±±±°°°                                                                         ³
  293.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  294.     '³                                                                                                                                                                                                ³
  295.     '³                                                                                                                                                                                                ³
  296.     '³                                                                                                                                                                                                ³
  297.     '³                                                                                                                                                                                                ³
  298.     '³                                                                                                                                                                                                ³
  299.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  300.     '³                                                                                °°°±±±²²²ÛÛÛ HISTORY ÛÛÛ²²²±±±°°°                                                                               ³
  301.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  302.     '³ Date: 09/10/18 by Terry Ritchie                                                                                                                                                                ³
  303.     '³     : Initial writing of code.                                                                                                                                                                 ³
  304.     '³                                                                                                                                                                                                ³
  305.     'ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
  306.  
  307.     ' declare global variables
  308.  
  309.     SHARED SL_sprite() AS SL_SPRITE '   master working sprite array
  310.  
  311.     ' declare local variables
  312.  
  313.     DIM xa AS INTEGER '                 actual x location of sprite on screen
  314.     DIM ya AS INTEGER '                 actual y location of sprite on screen
  315.     DIM sw AS INTEGER '                 width of sprite to be drawn
  316.     DIM sh AS INTEGER '                 height of sprite to be drawn
  317.     DIM sprite AS LONG '                the sprite to be drawn
  318.  
  319.     ' perform error checks
  320.  
  321.     IF NOT SL_VALID_SPRITE(handle) THEN '                                                               is this a valid sprite?
  322.         SL_ERROR "SL_PUT_SPRITE", 300, "" '                                                             no, report error to programmer
  323.     END IF
  324.  
  325.     'local variable setup
  326.  
  327.     SL_sprite(handle).xreal = x '                                                             (SINGLE)  save requested x center location
  328.     SL_sprite(handle).yreal = y '                                                             (SINGLE)  save requested y center location
  329.     SL_sprite(handle).xint = INT(x) '                                                        (INTEGER)  save screen x center location
  330.     SL_sprite(handle).yint = INT(y) '                                                        (INTEGER)  save screen y center location
  331.     IF SL_sprite(handle).rotation THEN '                                                                is sprite rotated?
  332.         sprite = SL_sprite(handle).rsprite '                                                            yes, get rotated sprite image
  333.         sw = SL_sprite(handle).rspritewidth '                                                           get rotated sprite width
  334.         sh = SL_sprite(handle).rspriteheight '                                                          get rotated sprite height
  335.     ELSE '                                                                                              sprite is not rotated
  336.         sprite = SL_sprite(handle).sprite '                                                             get standard sprite image
  337.         sw = SL_sprite(handle).spritewidth '                                                            get standard sprite width
  338.         sh = SL_sprite(handle).spriteheight '                                                           get standard sprite height
  339.     END IF
  340.     xa = SL_sprite(handle).xint - sw \ 2 '                                                              calculate actual screen x location from center
  341.     ya = SL_sprite(handle).yint - sh \ 2 '                                                              calculate actual screen y location from center
  342.     SL_sprite(handle).xactual = xa '                                                         (INTEGER)  save actual screen x location
  343.     SL_sprite(handle).yactual = ya '                                                         (INTEGER)  save actual screen y location
  344.  
  345.     ' place sprite on the current destination
  346.  
  347.     SELECT CASE SL_sprite(handle).flip '                                                                which flipping style is selected?
  348.         CASE 0 '                                                                  (constant SL_NOFLIP)  normal, no flipping
  349.             _PUTIMAGE (xa, ya), sprite '                                                                draw normal sprite
  350.         CASE 1 '                                                              (constant SL_HORIZONTAL)  flip horizontally
  351.             _PUTIMAGE (xa + sw - 1, ya)-(xa, ya + sh - 1), sprite '                                     draw horizontally flipped sprite
  352.         CASE 2 '                                                                (constant SL_VERTICAL)  flip vertically
  353.             _PUTIMAGE (xa, ya + sh - 1)-(xa + sw - 1, ya), sprite '                                     draw vertically flipped sprite
  354.         CASE 3 '                                                                (constant SL_FLIPBOTH)  flip vertically and horizontally
  355.             _PUTIMAGE (xa + sw - 1, ya + sh - 1)-(xa, ya), sprite '                                     draw horizontally and vertically flipped sprite
  356.     END SELECT
  357.  
  358.  
  359. '    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  360. FUNCTION SL_NEW_SPRITE (sheet AS INTEGER, column AS INTEGER, row AS INTEGER, restores AS INTEGER) '                                                                                       SL_NEW_SPRITE
  361.     'ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
  362.     '³                    °°°±±±²²²ÛÛÛ COMMAND DESCRIPTION AND USAGE ÛÛÛ²²²±±±°°°                     ³                                °°°±±±²²²ÛÛÛ NOTES ÛÛÛ²²²±±±°°°                                ³
  363.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  364.     '³ Creates a pointer to a sprite contained in the SL_sprite database array.                       ³ - Two constants have been created for use with this function:                                 ³
  365.     '³                                                                                                ³   : SL_NOSAVE ( 0) do not save the background image behind sprite between calls.              ³
  366.     '³ mysprite% = SL_NEW_SPRITE(mysheet%, 2, 3, SL_NOSAVE)                                           ³   : SL_SAVE   (-1) save the background image behind sprite between calls.                     ³
  367.     '³                                                                                                ³ - The function will report an error on the following conditions:                              ³
  368.     '³ Input : sheet    - the sprite sheet the sprite resides on.                                     ³   : An invalid sprite sheet has been selected.                                                ³
  369.     '³         column   - the column in the sprite sheet the sprite resides in.                       ³   : An invalid row or column value within a sprite sheet has been requested.                  ³
  370.     '³         row      - the row in the sprite sheet the sprite resides in.                          ³   : An invalid background image restoration method has been requested.                        ³
  371.     '³         restores - background saving behavior                                                  ³                                                                                               ³
  372.     '³                    :  0 - don't restore background between calls.                              ³                                                                                               ³
  373.     '³                    : -1 - restore the background between calls.                                ³                                                                                               ³
  374.     '³                                                                                                ³                                                                                               ³
  375.     '³ Output: an integer value greater than zero (0) that acts as a handle pointing to the sheet and ³                                                                                               ³
  376.     '³         location on the sheet where a sprite resides.                                          ³                                                                                               ³
  377.     '³                                                                                                ³                                                                                               ³
  378.     '³ Sets  : SL_sprite(x).inuse        = -1       (TRUE, this sprite index is in use)               ³                                                                                               ³
  379.     '³         SL_sprite(x).sheet        = sheet    (the sprite sheet where this sprite resides)      ³                                                                                               ³
  380.     '³         SL_sprite(x).column       = column   (column within sprite sheet where sprite resides) ³                                                                                               ³
  381.     '³         SL_sprite(x).row          = row      (row within sprite sheet where sprite resides)    ³                                                                                               ³
  382.     '³         SL_sprite(x).restore      = restores (background save behavior of sprite)              ³                                                                                               ³
  383.     '³         SL_sprite(x).spritewidth             (sprite width copied from sprite sheet)           ³                                                                                               ³
  384.     '³         SL_sprite(x).spriteheight            (sprite height copied from sprite sheet)          ³                                                                                               ³
  385.     '³         SL_sprite(x).collx1                  (upper left collision box x copied from sheet)    ³                                                                                               ³
  386.     '³         SL_sprite(x).colly1                  (upper left collision box y copied from sheet)    ³                                                                                               ³
  387.     '³         SL_sprite(x).collx2                  (lower right collision box x copied from sheet)   ³                                                                                               ³
  388.     '³         SL_sprite(x).colly2                  (lower right collision box y copied from sheet)   ³                                                                                               ³
  389.     '³         SL_sprite(x).sprite                  (hardware sprite image created from sheet image)  ³                                                                                               ³
  390.     '³         SL_sprite(x).image                   (software sprite image copied from sheet image)   ³                                                                                               ³
  391.     '³         SL_sprite(x).mask                    (software mask image copied from sheet image)     ³                                                                                               ³
  392.     '³                                                                                                ³                                                                                               ³
  393.     '³         all other SL_sprite(x).* subvariables reset to their initial value                     ³                                                                                               ³
  394.     '³                                                                                                ³                                                                                               ³
  395.     '³ Errors: All reported errors will be in the 200 - 299 range for this function.                  ³                                                                                               ³
  396.     '³                                                                                                ³                                                                                               ³
  397.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  398.     '³                            °°°±±±²²²ÛÛÛ KNOWN ISSUES ÛÛÛ²²²±±±°°°                              ³                               °°°±±±²²²ÛÛÛ CREDITS ÛÛÛ²²²±±±°°°                               ³
  399.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  400.     '³ None                                                                                           ³ None                                                                                          ³
  401.     '³                                                                                                ³                                                                                               ³
  402.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  403.     '³                                                                          °°°±±±²²²ÛÛÛ THEORY OF OPERATION ÛÛÛ²²²±±±°°°                                                                         ³
  404.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  405.     '³ The sprite array database is scanned for a free index and once found that index number becomes the handle (pointer) the the sprite being created. The new index contains further pointers to   ³
  406.     '³ where the requested sprite is located in the sprite sheet array database; the sheet number, the row, and the column the sprite resides in within the sheet. Information from the sprite sheet  ³
  407.     '³ is then copied over (see Sets: above) from the sheet array to the sprite array. A hardware image of the sprite is then created from the software image contained in the sprite sheet.          ³
  408.     '³                                                                                                                                                                                                ³
  409.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  410.     '³                                                                                °°°±±±²²²ÛÛÛ HISTORY ÛÛÛ²²²±±±°°°                                                                               ³
  411.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  412.     '³ Date: 09/10/18 by Terry Ritchie                                                                                                                                                                ³
  413.     '³     : Initial writing of code.                                                                                                                                                                 ³
  414.     '³                                                                                                                                                                                                ³
  415.     'ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
  416.  
  417.     ' declare global variables
  418.  
  419.     SHARED SL_sheet() AS SL_SHEET '     master sprite sheet array
  420.     SHARED SL_sprite() AS SL_SPRITE '   master working sprite array
  421.  
  422.     ' declare local variables
  423.  
  424.     DIM handle AS INTEGER '             handle (pointer) number of new sprite
  425.  
  426.     ' perform error checks
  427.  
  428.     IF sheet > UBOUND(SL_sheet) OR SL_sheet(sheet, 0, 0).image <> -1 THEN '                             valid sprite sheet requested?
  429.         SL_ERROR "SL_NEW_SPRITE", 200, "" '                                                             no, report error to programmer
  430.     END IF
  431.     IF column > UBOUND(SL_sheet, 2) OR row > UBOUND(SL_sheet, 3) OR row < 1 OR column < 1 THEN '        valid row and column requested?
  432.         SL_ERROR "SL_NEW_SPRITE", 201, "" '                                                             no, report error to programmer
  433.     END IF
  434.     IF ABS(restores) > 1 THEN '                                                                         valid background restoration behavior requested?
  435.         SL_ERROR "SL_NEW_SPRITE", 202, "" '                                                             no, report error to programmer
  436.     END IF
  437.  
  438.     ' local variable setup
  439.  
  440.     handle = 0 '                                                                                        initialize handle value
  441.  
  442.     ' increase sprite array's size if needed
  443.  
  444.     DO '                                                                                                look for next available handle
  445.         handle = handle + 1 '                                                                           increment to next handle value
  446.     LOOP UNTIL (NOT SL_sprite(handle).inuse) OR handle = UBOUND(SL_sprite) '                            stop looking when valid handle found
  447.     IF SL_sprite(handle).inuse THEN '                                                                   is the last array element in use?
  448.         handle = handle + 1 '                                                                           yes, increment to next handle value
  449.         REDIM _PRESERVE SL_sprite(handle) AS SL_SPRITE '                                                increase the size of the sprite array
  450.     END IF
  451.  
  452.     ' populate sprite array
  453.  
  454.     SL_sprite(handle).inuse = -1 '                                                              (TRUE)  mark array index as in use
  455.     SL_sprite(handle).sheet = sheet '                                                                   point to sheet where sprite resides              *
  456.     SL_sprite(handle).column = column '                                                                 point to column on sheet where sprite located    * these still needed?
  457.     SL_sprite(handle).row = row '                                                                       point to row on sheet where sprite located       *
  458.     SL_sprite(handle).restore = restores '                             (constants SL_SAVE & SL_NOSAVE)  background restore behavior of sprite
  459.     SL_sprite(handle).rsprite = 0 '                                                                     no rotated hardware image yet
  460.     SL_sprite(handle).rimage = 0 '                                                                      no rotated software image yet
  461.     SL_sprite(handle).rmask = 0 '                                                                       no rotated software mask image yet
  462.     SL_sprite(handle).background = 0 '                                                                  no background image saved yet
  463.     SL_sprite(handle).xreal = 0 '                                                                       reset x location of sprite (center x)
  464.     SL_sprite(handle).yreal = 0 '                                                                       reset y location of sprite (center y)
  465.     SL_sprite(handle).xint = 0 '                                                                        reset x location of sprite on screen INT(xreal) (center x)
  466.     SL_sprite(handle).yint = 0 '                                                                        reset y location of sprite on screen INT(yreal) (center y)
  467.     SL_sprite(handle).xactual = 0 '                                                                     reset x location of sprite on screen (upper left x)
  468.     SL_sprite(handle).yactual = 0 '                                                                     reset y location of sprite on screen (upper left y)
  469.     SL_sprite(handle).collx1 = SL_sheet(sheet, column, row).collx1 '                                    get sprite's collision box boundaries
  470.     SL_sprite(handle).colly1 = SL_sheet(sheet, column, row).colly1
  471.     SL_sprite(handle).collx2 = SL_sheet(sheet, column, row).collx2
  472.     SL_sprite(handle).colly2 = SL_sheet(sheet, column, row).colly2
  473.     SL_sprite(handle).spritewidth = SL_sheet(sheet, column, row).spritewidth '                          get width of sprite
  474.     SL_sprite(handle).spriteheight = SL_sheet(sheet, column, row).spriteheight '                        get height of sprite
  475.     SL_sprite(handle).sprite = _COPYIMAGE(SL_sheet(sheet, column, row).image, 33) '                     create hardware sprite image
  476.     SL_sprite(handle).image = _COPYIMAGE(SL_sheet(sheet, column, row).image, 32) '                      copy software sprite image from sheet
  477.     IF SL_sheet(sheet, column, row).transparency THEN '                                                 does this sprite use transparency?
  478.         SL_sprite(handle).mask = _COPYIMAGE(SL_sheet(sheet, column, row).mask, 32) '                    yes, copy software sprite mask image from sheet
  479.         SL_sprite(handle).transparency = -1 '                                                   (TRUE)  remember this sprite has a transparency layer
  480.     ELSE '                                                                                              no transparency
  481.         SL_sprite(handle).mask = 0 '                                                                    no mask will be brought in
  482.         SL_sprite(handle).transparency = 0 '                                                   (FALSE)  remember this sprite has no transparency layer
  483.     END IF
  484.     SL_sprite(handle).flip = 0 '                                                                        no sprite flipping
  485.     SL_sprite(handle).rotation = 0 '                                                                    no sprite rotation angle
  486.  
  487.     SL_NEW_SPRITE = handle
  488.  
  489.  
  490. '    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  491. FUNCTION SL_NEW_SPRITE_SHEET (filename AS STRING, spritewidth AS INTEGER, spriteheight AS INTEGER, transparency AS INTEGER, transcolor AS _UNSIGNED LONG) '                         SL_NEW_SPRITE_SHEET
  492.     'ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
  493.     '³                    °°°±±±²²²ÛÛÛ COMMAND DESCRIPTION AND USAGE ÛÛÛ²²²±±±°°°                     ³                                °°°±±±²²²ÛÛÛ NOTES ÛÛÛ²²²±±±°°°                                ³
  494.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  495.     '³ Loads a sprite sheet's sprites into memory and stores them in the sprite sheet array. Three    ³ - The software image mask will only be created if the sprite sheet contains a transparency    ³
  496.     '³ sprite images are created for each sprite; a hardware image for displaying, a software image   ³   layer (alpha channel) either built-in or user defined.                                      ³
  497.     '³ for manipulating, and a software mask image for pixel collision detection.                     ³ - Three constants have been created for use with this function:                               ³
  498.     '³                                                                                                ³   : SL_SHEETTRANSPARENCY (-1) to have the function use built-in sprite sheet's alpha layer.   ³
  499.     '³ mysheet% = SL_NEW_SPRITE_SHEET("sprites.png", 64, 96, SL_SETTRANSPARENCY, _RGB32(255, 0, 255)) ³   : SL_SETTRANSPARENCY   ( 0) to have the function use the programmer supplied alpha value.   ³
  500.     '³                                                                                                ³   : SL_NOTRANSPARENCY    ( 1) to have the function ignore alpha channel completely.           ³
  501.     '³ Input : filename     - the name of the sprite sheet image file to load in.                     ³ - The function will report an error on the following conditions:                              ³
  502.     '³         spritewidth  - the width of every sprite contained on the sprite sheet.                ³   : A filename is supplied that does not exist.                                               ³
  503.     '³         spriteheight - the height of every sprite contained on the sprite sheet.               ³   : A sprite width or height that is less than one (1).                                       ³
  504.     '³         transparency - the type of transparency to apply to the sprite sheet and sprites:      ³   : An invalid transparency type value. Valid types are from negative one (-1) to one (1).    ³
  505.     '³                         : -1 - use the sprite sheet's built-in alpha channel (PNG files).      ³   : The sprite sheet does not contain at least one row and column of sprites.                 ³
  506.     '³                         :  0 - use the programmer assigned alpha channel value.                ³ - The programmer supplied alpha channel value will be ignored if transparency is set to a     ³
  507.     '³                         :  1 - this sheet does not have any transparency included.             ³   value of negative one (-1).                                                                 ³
  508.     '³         transcolor   - programmer assigned alpha channel value for the sprite sheet.           ³ - When transparency is set to one (1) the programmer supplied transcolor is used to identify  ³
  509.     '³                                                                                                ³   the background color used in the sprite sheet. This is still needed to find the collision   ³
  510.     '³ Output: An integer value greater than zero (0) that acts as a handle pointing to the sheet     ³   box boundaries for collision detection.                                                     ³
  511.     '³         that contains the sprites.                                                             ³                                                                                               ³
  512.     '³                                                                                                ³                                                                                               ³
  513.     '³ Sets  : SL_sheet(x, 0, 0).image        = -1      (TRUE, this sheet index is in use)            ³                                                                                               ³
  514.     '³         SL_sheet(x, 0, 0).spritewidth  = columns (the number indexes in the 2nd dimension of   ³                                                                                               ³
  515.     '³                                                   sheet array)                                 ³                                                                                               ³
  516.     '³         SL_sheet(x, 0, 0).spriteheight = rows    (the number of indexes in the 3rd dimension   ³                                                                                               ³
  517.     '³                                                   of sheet array)                              ³                                                                                               ³
  518.     '³         SL_sheet(x, c, r).image                  software image copied from sprite sheet       ³                                                                                               ³
  519.     '³         SL_sheet(x, c, r).spritewidth            width of sprite in pixels                     ³                                                                                               ³
  520.     '³         SL_sheet(x, c, r).spriteheight           height of sprite in pixels                    ³                                                                                               ³
  521.     '³         SL_sheet(x, c, r).mask                   sprite mask (image black, background white)   ³                                                                                               ³
  522.     '³         SL_sheet(x, c, r).collx1                 collision box upper left x                    ³                                                                                               ³
  523.     '³         SL_sheet(x, c, r).colly1                 collision box upper left y                    ³                                                                                               ³
  524.     '³         SL_sheet(x, c, r).collx2                 collision box lower right x                   ³                                                                                               ³
  525.     '³         SL_sheet(x, c, r).colly2                 collision box lower right y                   ³                                                                                               ³
  526.     '³           * c = column  r = row                                                                ³                                                                                               ³
  527.     '³                                                                                                ³                                                                                               ³
  528.     '³ Errors: All reported errors will be in the 100 - 199 range for this function.                  ³                                                                                               ³
  529.     '³                                                                                                ³                                                                                               ³
  530.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  531.     '³                            °°°±±±²²²ÛÛÛ KNOWN ISSUES ÛÛÛ²²²±±±°°°                              ³                               °°°±±±²²²ÛÛÛ CREDITS ÛÛÛ²²²±±±°°°                               ³
  532.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  533.     '³ Need to incorporate Steve's PNG transparency layer identifier instead of mine.                 ³ Portions of this subroutine have code based off of Galleon's RotoZoom subroutine in the QB64  ³
  534.     '³                                                                                                ³ documentation at http://[abandoned, outdated and now likely malicious qb64 dot net website - don’t go there]/wiki/index.php?title=MAPTRIANGLE (link no longer works)      ³
  535.     '³                                                                                                ³                                                                                               ³
  536.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  537.     '³                                                                          °°°±±±²²²ÛÛÛ THEORY OF OPERATION ÛÛÛ²²²±±±°°°                                                                         ³
  538.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  539.     '³ Once the sprite sheet is loaded it is scanned for an alpha channel if the programmer requests to use the sheet's transparency layer. The width and height of the sheet are retrieved and then  ³
  540.     '³ divided by the sprite dimensions provided by the programmer to determine how many columns and rows of sprites exist. A three dimensional sheet array is created where the first dimension is   ³
  541.     '³ the sheet number (handle/pointer), the second and thirs dimensions are then related to the sprite column and row locations on the sheet. Each sprite is copied from the sprite sheet into the  ³
  542.     '³ sprite sheet array. Each sprite is scanned to determine the absolute image size within the sprite (background/transparency areas are ignored) to determine the smallest possible collision box ³
  543.     '³ needed for collision detection. Finally, the sprite is scanned again to create an image mask for pixel perfect detection.                                                                      ³
  544.     '³                                                                                                                                                                                                ³
  545.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  546.     '³                                                                                °°°±±±²²²ÛÛÛ HISTORY ÛÛÛ²²²±±±°°°                                                                               ³
  547.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  548.     '³ Date: 09/09/18 by Terry Ritchie                                                                                                                                                                ³
  549.     '³     : Initial writing of code.                                                                                                                                                                 ³
  550.     '³                                                                                                                                                                                                ³
  551.     'ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
  552.  
  553.     ' declare global variables
  554.  
  555.     SHARED SL_sheet() AS SL_SHEET '    master sprite sheet array
  556.     SHARED SL_rotate() AS SL_ROTATE '  precalculated rotation table
  557.  
  558.     ' declare local variables
  559.  
  560.     DIM handle AS INTEGER '             handle (pointer) number of new sprite sheet
  561.     DIM x AS INTEGER '                  generic counter to cycle through sheet sprite columns
  562.     DIM y AS INTEGER '                  generic counter to cycle through sheet sprite rows
  563.     DIM x1 AS INTEGER '                 generic counter to cycle though sprite for collision boundaries and mask creation
  564.     DIM y1 AS INTEGER '                 generic ocunter to cycle though sprite for collision boundaries and mask creation
  565.     DIM osource AS LONG '               original source image before this function was called
  566.     DIM odest AS LONG '                 original destination image before this function was called
  567.     DIM pixel AS _UNSIGNED LONG '       pixel color at each coordinate in sprite sheet
  568.     DIM alpha AS _UNSIGNED LONG '       alpha level of current pixel
  569.     DIM top AS INTEGER '                upper boundary of sprite image
  570.     DIM bottom AS INTEGER '             lower boundary of sprite image
  571.     DIM left AS INTEGER '               left boundary of sprite image
  572.     DIM right AS INTEGER '              right boundary of sprite image
  573.     DIM sheetimage AS LONG '            sprite sheet image
  574.     DIM sheetwidth AS INTEGER '         width of sprite sheet in pixels
  575.     DIM sheetheight AS INTEGER '        height of sprite sheet in pixels
  576.     DIM rows AS INTEGER '               number of sprite rows contained on sheet
  577.     DIM columns AS INTEGER '            number of sprite columns contained on sheet
  578.     DIM clearcolor AS _UNSIGNED LONG '  transcolor passed in will be modified
  579.     DIM tempsprite AS LONG '            temporary sprite for _CLEARCOLOR detection
  580.  
  581.     DIM px(3) AS SINGLE '               polar x coordinates of maptriangle
  582.     DIM py(3) AS SINGLE '               polar y coordinates of maptriangle
  583.     DIM sinr AS SINGLE
  584.     DIM cosr AS SINGLE
  585.     DIM bx1 AS INTEGER
  586.     DIM bx2 AS INTEGER
  587.     DIM by1 AS INTEGER
  588.     DIM by2 AS INTEGER
  589.  
  590.     ' perform error checks
  591.  
  592.     IF NOT _FILEEXISTS(filename) THEN '                                                                 does the sprite sheet exist?
  593.         SL_ERROR "SL_NEW_SPRITE_SHEET", 100, filename '                                                 no, report error to programmer
  594.     END IF
  595.     IF ABS(transparency) > 1 THEN '                                                                     valid transparency setting?
  596.         SL_ERROR "SL_NEW_SPRITE_SHEET", 101, "" '                                                       no, report error to programmer
  597.     END IF
  598.     IF spritewidth < 1 OR spriteheight < 1 THEN '                                                       valid sprite width/height supplied?
  599.         SL_ERROR "SL_NEW_SPRITE_SHEET", 102, "" '                                                       no, report error to programmer
  600.     END IF
  601.     IF transparency = -1 AND UCASE$(RIGHT$(filename, 4)) <> ".PNG" THEN '                               wrong file type for transparency?
  602.         SL_ERROR "SL_NEW_SPRITE_SHEET", 103, UCASE$(RIGHT$(filename, 4)) '                              yes, report error to programmer
  603.     END IF
  604.  
  605.     ' local variable setup
  606.  
  607.     sheetimage = _LOADIMAGE(filename, 32) '                                                             load sprite sheet file
  608.     sheetwidth = _WIDTH(sheetimage) '                                                                   get width of sheet
  609.     sheetheight = _HEIGHT(sheetimage) '                                                                 get height of sheet
  610.     columns = sheetwidth \ spritewidth '                                                                get number of whole columns of sprites
  611.     rows = sheetheight \ spriteheight '                                                                 get number of whole rows of sprites
  612.     IF columns < 1 OR rows < 1 THEN '                                                                   at least one sprite column and row on sheet?
  613.         SL_ERROR "SL_NEW_SPRITE_SHEET", 104, "" '                                                       no, report error to programmer
  614.     END IF
  615.     osource = _SOURCE '                                                                                 remember current source image
  616.     odest = _DEST '                                                                                     remember current destination image
  617.     handle = 0 '                                                                                        initialize handle value
  618.     clearcolor = transcolor '                                                                           get background/transparent color passed in
  619.  
  620.     ' increase sheet array's 1st dimension if needed to create a new sprite sheet
  621.  
  622.     DO '                                                                                                look for the next available handle
  623.         handle = handle + 1 '                                                                           increment the handle value
  624.     LOOP UNTIL (NOT SL_sheet(handle, 0, 0).image) OR handle = UBOUND(SL_sheet) '                       stop looking when valid handle value found
  625.     IF SL_sheet(handle, 0, 0).image = -1 THEN '                                                        is the last array element in use?
  626.         handle = handle + 1 '                                                                           yes, increment the handle value
  627.         REDIM _PRESERVE SL_sheet(handle, UBOUND(SL_sheet, 2), UBOUND(SL_sheet, 3)) AS SL_SHEET '        create new sheet in sprite array
  628.         REDIM _PRESERVE SL_rotate(handle, UBOUND(SL_rotate, 2)) AS SL_ROTATE
  629.     END IF
  630.  
  631.     ' increase sheet array's 2nd and 3rd dimensions if needed to match number of rows and columns
  632.  
  633.     IF columns > UBOUND(SL_sheet, 2) THEN '                                                             more columns in this sheet than others?
  634.         REDIM _PRESERVE SL_sheet(handle, columns, UBOUND(SL_sheet, 3)) AS SL_SHEET '                    yes, increase the array's 2nd dimension to match
  635.     END IF
  636.     IF rows > UBOUND(SL_sheet, 3) THEN '                                                                more rows in this sheet than others?
  637.         REDIM _PRESERVE SL_sheet(handle, UBOUND(SL_sheet, 2), rows) AS SL_SHEET '                       yes, increase the array's 3rd dimension to match
  638.     END IF
  639.  
  640.     ' the variables in SL_sheet(x, 0, 0) will serve a dual purpose
  641.     ' SL_sheet(x, 0, 0).image will contain either -1 (true) or 0 (false) to indicate the first dimension of the array is in use.
  642.     ' SL_sheet(x, 0, 0).spritewidth will contain the number of columns contained in the sheet (the array's 2nd dimension)
  643.     ' SL_sheet(x, 0, 0).spriteheight will contain the number of rows contained in the sheet (the array's 3rd dimension)
  644.  
  645.     SL_sheet(handle, 0, 0).image = -1 '                                                         (TRUE)  mark as in use
  646.     SL_sheet(handle, 0, 0).spritewidth = columns '                                                      remember number of columns in sheet
  647.     SL_sheet(handle, 0, 0).spriteheight = rows '                                                        remember number of rows in sheet
  648.  
  649.     ' identify transparency of sprite sheet if requested
  650.  
  651.     IF transparency = -1 THEN '                                        (constant SL_SHEETTRANSPARENCY)  sheet have alpha channel?
  652.         x = 0 '                                                                                         yes, start at upper left x of sheet
  653.         y = 0 '                                                                                         start at upper left y of sheet
  654.         alpha = 255 '                                                                                   assume no alpha channel
  655.         _SOURCE sheetimage '                                                                            set sprite sheet image as source image
  656.         DO '                                                                                            start looping through the sheet's pixels
  657.             pixel = POINT(x, y) '                                                                       get the pixel's color attributes
  658.             alpha = _ALPHA32(pixel) '                                                                   get the alpha level (0 - 255)
  659.             IF alpha = 0 THEN EXIT DO '                                                                 if it is transparent then leave the loop
  660.             x = x + 1 '                                                                                 move right one pixel
  661.             IF x > sheetwidth THEN '                                                                    have we gone off the sheet?
  662.                 x = 0 '                                                                                 yes, reset back to the left beginning
  663.                 y = y + 1 '                                                                             move down one pixel
  664.             END IF
  665.         LOOP UNTIL y > sheetheight '                                                                    don't stop until the entire sheet has been checked
  666.         IF alpha = 0 THEN '                                                                             did we find a transparent pixel?
  667.             tempsprite = _NEWIMAGE(1, 1, 32) '                                                          yes, create a temporary image         * why did I have to do
  668.             _CLEARCOLOR pixel, tempsprite '                                                             set pixel found as transparent        * this hack to get
  669.             clearcolor = _CLEARCOLOR(tempsprite) '                                                      get the transparent color from image  * clearcolor to come out
  670.             _FREEIMAGE tempsprite '                                                                     temporary image no longer needed      * to the right value?
  671.         ELSE '                                                                                          no transparency found within sheet
  672.             transparency = 1 '                                                                          set sheet to having no alpha channel
  673.         END IF
  674.     ELSEIF transparency = 0 THEN '                                       (constant SL_SETTRANSPARENCY)  manually set alpha channel?
  675.         _CLEARCOLOR clearcolor, sheetimage '                                                            yes, set color as transparent
  676.         clearcolor = _CLEARCOLOR(sheetimage) '                                                          get the transparent color ************* again, why this hack?
  677.     END IF
  678.  
  679.     ' load sprites from sheet and place into sprite array
  680.  
  681.     FOR x = 1 TO columns '                                                                              cycle through the sheet's columns
  682.         FOR y = 1 TO rows '                                                                             cycle through the sheet's rows
  683.             SL_sheet(handle, x, y).image = _NEWIMAGE(spritewidth, spriteheight, 32) '                   create software sprite image
  684.             IF transparency < 1 THEN '                                                                  should a mask be created?
  685.                 SL_sheet(handle, x, y).mask = _NEWIMAGE(spritewidth, spriteheight, 32) '                yes, create software sprite mask image
  686.                 _DEST SL_sheet(handle, x, y).mask '                                                     write to the mask image
  687.             ELSE
  688.                 SL_sheet(handle, x, y).transparency = 0 '                                      (FALSE)  set sprite as having no transparency
  689.             END IF
  690.             _PUTIMAGE , sheetimage, SL_sheet(handle, x, y).image,_
  691.                  ((x - 1) * spritewidth, (y - 1) * spriteheight)-_
  692.                  ((x - 1) * spritewidth + spritewidth - 1, (y - 1) * spriteheight + spriteheight - 1) ' copy sprite from sheet and place in sprite image
  693.  
  694.             ' precalculate collision boundaries and update sprite mask if needed
  695.  
  696.             _SOURCE SL_sheet(handle, x, y).image '                                                      work from the software sprite image
  697.             top = spriteheight '                                                                        set initial collision boundary markers
  698.             left = spritewidth
  699.             bottom = 0
  700.             right = 0
  701.             FOR x1 = 0 TO spritewidth - 1 '                                                             cycle through the width of sprite
  702.                 FOR y1 = 0 TO spriteheight - 1 '                                                        cycle through the height of sprite
  703.                     IF POINT(x1, y1) <> clearcolor THEN '                                               is this pixel a transparent/background color?
  704.                         IF x1 < left THEN left = x1 '                                                   no, save position if left-most pixel
  705.                         IF y1 < top THEN top = y1 '                                                     save position if top-most pixel
  706.                         IF x1 > right THEN right = x1 '                                                 save position if right-most pixel
  707.                         IF y1 > bottom THEN bottom = y1 '                                               save position if bbottom-most pixel
  708.                     END IF
  709.                     IF transparency < 1 THEN '                                                          update software sprite mask?
  710.                         IF POINT(x1, y1) = clearcolor THEN '                                            yes, is this pixel a transparent/background color?
  711.                             PSET (x1, y1), _RGB32(255, 255, 255) '                                      yes, set as white on the mask image
  712.                         END IF
  713.                     END IF
  714.                 NEXT y1
  715.             NEXT x1
  716.             SL_sheet(handle, x, y).collx1 = left '                                                      collision box top left x
  717.             SL_sheet(handle, x, y).colly1 = top '                                                       collision box top left y
  718.             SL_sheet(handle, x, y).collx2 = right '                                                     collision box bottom right x
  719.             SL_sheet(handle, x, y).colly2 = bottom '                                                    collision box bottom right y
  720.             SL_sheet(handle, x, y).spritewidth = spritewidth '                                          remember sprite width
  721.             SL_sheet(handle, x, y).spriteheight = spriteheight '                                        remember sprite height
  722.         NEXT y
  723.     NEXT x
  724.     _FREEIMAGE sheetimage '                                                                             sprite sheet image no longer needed
  725.  
  726.     ' create precalculated rotation table for the sprite sheet (0 to 359 degrees)
  727.  
  728.     FOR x = 1 TO 359
  729.         px(0) = -spritewidth / 2 '                                                                      upper left  x polar coordinate of sprite
  730.         py(0) = -spriteheight / 2 '                                                                     upper left  y polar coordinate of sprite
  731.         px(1) = px(0) '                                                                                 lower left  x polar coordinate of sprite
  732.         py(1) = spriteheight / 2 '                                                                      lower left  y polar coordinate of sprite
  733.         px(2) = spritewidth / 2 '                                                                       lower right x polar coordinate of sprite
  734.         py(2) = py(1) '                                                                                 lower right y polar coordinate of sprite
  735.         px(3) = px(2) '                                                                                 upper right x polar coordinate of sprite
  736.         py(3) = py(0) '                                                                                 upper right y polar coordinate of sprite
  737.         sinr = SIN(-x / 57.2957795131) '                                                                calculate the sin of rotation
  738.         cosr = COS(-x / 57.2957795131) '                                                                calculate the cosine of rotation
  739.         bx1 = 0 '                                                                                       upper left x boundary of sprite
  740.         by1 = 0 '                                                                                       upper left y boundary of sprite
  741.         bx2 = 0 '                                                                                       lower right x boundary of sprite
  742.         by2 = 0 '                                                                                       lower right y boundary of sprite
  743.         FOR y = 0 TO 3 '                                                                                cycle through all four polar coordinates
  744.             x2 = (px(y) * cosr + sinr * py(y)) '                                                        compute new polar coordinate location
  745.             y2 = (py(y) * cosr - px(y) * sinr) '                                                        compute new polar coordinate location
  746.             px(y) = x2 '                                                                                save the new polar coordinate
  747.             py(y) = y2 '                                                                                save the new polar coordinate
  748.             IF px(y) < bx1 THEN bx1 = px(y) '                                                           save lowest  x value seen \  NOTE: use for
  749.             IF px(y) > bx2 THEN bx2 = px(y) '                                                           save highest x value seen  \ background image         <--------------------- LOOK
  750.             IF py(y) < by1 THEN by1 = py(y) '                                                           save lowest  y value seen  / rectangle coordinates
  751.             IF py(y) > by2 THEN by2 = py(y) '                                                           save highest y value seen /
  752.         NEXT y
  753.         SL_rotate(handle, x).rwidth = bx2 - bx1 + 1 '                                                   calculate width of rotated sprite
  754.         SL_rotate(handle, x).rheight = by2 - by1 + 1 '                                                  calculate height of rotated sprite
  755.         SL_rotate(handle, x).px0 = px(0) + ((bx2 - bx1 + 1) / 2) '                                      calculate triangular coordinates
  756.         SL_rotate(handle, x).px1 = px(1) + ((bx2 - bx1 + 1) / 2)
  757.         SL_rotate(handle, x).px2 = px(2) + ((bx2 - bx1 + 1) / 2)
  758.         SL_rotate(handle, x).px3 = px(3) + ((bx2 - bx1 + 1) / 2)
  759.         SL_rotate(handle, x).py0 = py(0) + ((by2 - by1 + 1) / 2)
  760.         SL_rotate(handle, x).py1 = py(1) + ((by2 - by1 + 1) / 2)
  761.         SL_rotate(handle, x).py2 = py(2) + ((by2 - by1 + 1) / 2)
  762.         SL_rotate(handle, x).py3 = py(3) + ((by2 - by1 + 1) / 2)
  763.     NEXT x
  764.     _SOURCE osource '                                                                                   return source to current
  765.     _DEST odest '                                                                                       return destination to current
  766.     SL_NEW_SPRITE_SHEET = handle '                                                                      return the handle number pointing to this sheet
  767.  
  768.  
  769. '    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  770. SUB SL_ERROR (routine AS STRING, errno AS INTEGER, info AS STRING) '                                                                                                                           SL_ERROR
  771.     'ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
  772.     '³                    °°°±±±²²²ÛÛÛ COMMAND DESCRIPTION AND USAGE ÛÛÛ²²²±±±°°°                     ³                                °°°±±±²²²ÛÛÛ NOTES ÛÛÛ²²²±±±°°°                                ³
  773.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  774.     '³ Reports a Sprite Library error to the programmer. Used internally only.                        ³ - A copy of this library has been provided that has all of the error checks removed. Once     ³
  775.     '³                                                                                                ³   you are sure no errors exist you would then include that library for your final             ³
  776.     '³ Input : routine - the function/subroutine the error occurred in                                ³   compilation. The error checking routines do take some processing away from your code so     ³
  777.     '³                                                                                                ³   performance will improve by removing them.                                                  ³
  778.     '³         errno   - the error number associated with the error                                   ³                                                                                               ³
  779.     '³                   100 - sprite does not exist                                                  ³                                                                                               ³
  780.     '³                   101 - sprite is not in use                                                   ³                                                                                               ³
  781.     '³                   102 - sprite can't be hidden                                                 ³                                                                                               ³
  782.     '³                   103 - invalid zoom value                                                     ³                                                                                               ³
  783.     '³                   104 - invalid rotation angle                                                 ³                                                                                               ³
  784.     '³                   105 - invalid flipping behavior                                              ³                                                                                               ³
  785.     '³                   106 - sheet does not exist                                                   ³                                                                                               ³
  786.     '³                   107 - sheet is not in use                                                    ³                                                                                               ³
  787.     '³                   108 - invalid transparency setting                                           ³                                                                                               ³
  788.     '³                   109 - invalid sprite width/height                                            ³                                                                                               ³
  789.     '³                                                                                                ³                                                                                               ³
  790.     '³         info    - any information that need to be conveyed with the error                      ³                                                                                               ³
  791.     '³                   such as a file name                                                          ³                                                                                               ³
  792.     '³                                                                                                ³                                                                                               ³
  793.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  794.     '³                            °°°±±±²²²ÛÛÛ KNOWN ISSUES ÛÛÛ²²²±±±°°°                              ³                               °°°±±±²²²ÛÛÛ CREDITS ÛÛÛ²²²±±±°°°                               ³
  795.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  796.     '³ none                                                                                           ³ This routine was created in response to a request from QB64 member pitt                       ³
  797.     '³                                                                                                ³ http://www.[abandoned, outdated and now likely malicious qb64 dot net website - don’t go there]/forum/index.php?topic=7281.0 (link no longer works)                       ³
  798.     '³                                                                                                ³                                                                                               ³
  799.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  800.     '³                                                                          °°°±±±²²²ÛÛÛ THEORY OF OPERATION ÛÛÛ²²²±±±°°°                                                                         ³
  801.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  802.     '³ A pure text screen is shown, the font reset to default, and _AUTODISPLAY enabled. This forces the code out of any graphics screen it may currently be in. The error is then displayed to the   ³
  803.     '³ programmer based on the values passed in. The program is then forced to terminate.                                                                                                             ³
  804.     '³                                                                                                                                                                                                ³
  805.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  806.     '³                                                                                °°°±±±²²²ÛÛÛ HISTORY ÛÛÛ²²²±±±°°°                                                                               ³
  807.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  808.     '³ Date: 09/09/18 by Terry Ritchie                                                                                                                                                                ³
  809.     '³     : Initial writing of code.                                                                                                                                                                 ³
  810.     '³                                                                                                                                                                                                ³
  811.     'ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
  812.  
  813.     SCREEN 0, 0, 0, 0 '                                                             go to a pure text screen
  814.     _FONT 16 '                                                                      set the standard screen 0 font
  815.     IF _FULLSCREEN THEN _FULLSCREEN _OFF '                                          turn off full screen if on
  816.     _AUTODISPLAY '                                                                  auto update the display
  817.     CLS '                                                                           clear the screen
  818.     COLOR 10, 0
  819.     PRINT "                   **************************************" '             print error header
  820.     PRINT "                   ** Sprite Library Error Encountered **"
  821.     PRINT "                   **************************************"
  822.     PRINT
  823.     COLOR 15, 0
  824.     PRINT " "; routine;
  825.     COLOR 7, 0
  826.     PRINT " has reported error";
  827.     COLOR 30, 0
  828.     PRINT STR$(errno)
  829.     COLOR 7, 0
  830.     PRINT
  831.     SELECT CASE errno '                                                             which error number is being reported?
  832.         CASE 100
  833.             PRINT "- "; CHR$(34); info; CHR$(34); " sprite sheet does not exist"
  834.             PRINT "- check path or spelling"
  835.         CASE 101
  836.             PRINT "- invalid transparency setting supplied - valid settings are"
  837.             PRINT "- : -1 (constant SL_SHEETTRANSPARENCY)"
  838.             PRINT "- :  0 (constant SL_SETTRANSPARENCY)"
  839.             PRINT "- :  1 (constant SL_NOTRANSPARENCY)"
  840.         CASE 102
  841.             PRINT "- sprite width and height must be greater than zero"
  842.         CASE 103
  843.             PRINT "- selecting to use a sheet's transparency only works with .PNG files"
  844.             PRINT "- the function was passed a "; info; " file."
  845.         CASE 104
  846.             PRINT "- there must be at least one column and one row of sprites on sheet"
  847.         CASE 200
  848.             PRINT "- the specified sprite sheet is not in use or does not exist"
  849.         CASE 201
  850.             PRINT "- invalid row or column selected for specified sprite sheet"
  851.         CASE 202
  852.             PRINT "- background restore behavior for a sprite can only be 0 (FALSE) or -1 (TRUE)"
  853.         CASE 300, 400, 500
  854.             PRINT "- the requested sprite does not exist"
  855.     END SELECT
  856.     COLOR 12, 0
  857.     PRINT
  858.     PRINT " See sprite library doumentation for further explanation."
  859.     COLOR 7, 0
  860.     DO: LOOP UNTIL INKEY$ = "" '                                                    clear the keyboard buffer
  861.     END '                                                                           end the program
  862.  
  863.  
  864.  
  865. '    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  866. FUNCTION SL_VALID_SPRITE (handle AS INTEGER) '                                                                                                                                         SL_VALID_SPRITE
  867.     'ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
  868.     '³                    °°°±±±²²²ÛÛÛ COMMAND DESCRIPTION AND USAGE ÛÛÛ²²²±±±°°°                     ³                                °°°±±±²²²ÛÛÛ NOTES ÛÛÛ²²²±±±°°°                                ³
  869.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  870.     '³ Reports on the validity of a sprite handle (pointer).                                          ³                                                                                               ³
  871.     '³                                                                                                ³                                                                                               ³
  872.     '³ valid% = SL_VALID_SPRITE(mysprite%)                                                            ³                                                                                               ³
  873.     '³                                                                                                ³                                                                                               ³
  874.     '³ Input : handle - the handle (pointer) of the sprite being examined.                            ³                                                                                               ³
  875.     '³                                                                                                ³                                                                                               ³
  876.     '³ Output: an integer value of zero (0) (FALSE) or negative 1 (-1) (TRUE)                         ³                                                                                               ³
  877.     '³                                                                                                ³                                                                                               ³
  878.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  879.     '³                            °°°±±±²²²ÛÛÛ KNOWN ISSUES ÛÛÛ²²²±±±°°°                              ³                               °°°±±±²²²ÛÛÛ CREDITS ÛÛÛ²²²±±±°°°                               ³
  880.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  881.     '³ None                                                                                           ³ None                                                                                          ³
  882.     '³                                                                                                ³                                                                                               ³
  883.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  884.     '³                                                                          °°°±±±²²²ÛÛÛ THEORY OF OPERATION ÛÛÛ²²²±±±°°°                                                                         ³
  885.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  886.     '³ The sprite database is examined at the index the handle points to. If .inuse is -1 (TRUE) then the sprite handle is valid.                                                                     ³
  887.     '³                                                                                                                                                                                                ³
  888.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  889.     '³                                                                                °°°±±±²²²ÛÛÛ HISTORY ÛÛÛ²²²±±±°°°                                                                               ³
  890.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  891.     '³ Date: 09/11/18 by Terry Ritchie                                                                                                                                                                ³
  892.     '³     : Initial writing of code.                                                                                                                                                                 ³
  893.     '³                                                                                                                                                                                                ³
  894.     'ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
  895.  
  896.     ' declare global variables
  897.  
  898.     SHARED SL_sprite() AS SL_SPRITE '   master working sprite array
  899.  
  900.     IF handle > UBOUND(SL_SPRITE) OR (NOT SL_sprite(handle).inuse) THEN '                                is this a valid sprite handle?
  901.         SL_VALID_SPRITE = 0 '                                                                   (FALSE)  no, return 0
  902.     ELSE '                                                                                               yes, it is valid
  903.         SL_VALID_SPRITE = -1 '                                                                   (TRUE)  return -1
  904.     END IF
  905.  
  906.  
  907.  
  908.  
  909. '    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  910.  
  911. 'ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
  912. '³                    °°°±±±²²²ÛÛÛ COMMAND DESCRIPTION AND USAGE ÛÛÛ²²²±±±°°°                     ³                                °°°±±±²²²ÛÛÛ NOTES ÛÛÛ²²²±±±°°°                                ³
  913. 'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  914. '³                                                                                                ³                                                                                               ³
  915. '³                                                                                                ³                                                                                               ³
  916. 'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  917. '³                            °°°±±±²²²ÛÛÛ KNOWN ISSUES ÛÛÛ²²²±±±°°°                              ³                               °°°±±±²²²ÛÛÛ CREDITS ÛÛÛ²²²±±±°°°                               ³
  918. 'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  919. '³                                                                                                ³                                                                                               ³
  920. '³                                                                                                ³                                                                                               ³
  921. 'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  922. '³                                                                          °°°±±±²²²ÛÛÛ THEORY OF OPERATION ÛÛÛ²²²±±±°°°                                                                         ³
  923. 'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  924. '³                                                                                                                                                                                                ³
  925. '³                                                                                                                                                                                                ³
  926. 'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  927. '³                                                                                °°°±±±²²²ÛÛÛ HISTORY ÛÛÛ²²²±±±°°°                                                                               ³
  928. 'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  929. '³                                                                                                                                                                                                ³
  930. '³                                                                                                                                                                                                ³
  931. 'ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
  932.  

34
Programs / Re: Screen 0 as LED
« on: September 03, 2018, 11:32:32 am »
Note: This message is awaiting approval by a moderator.
Cool! I like the marching robot.

35
QB64 Discussion / Strange IDE behavior
« on: August 31, 2018, 01:06:20 am »
Earlier today I ran across a few variables that had their case (lower to upper) changed throughout the code. This happened to me the other day as well so I decided to do a little digging. This is what I came up with. Take the little snippet of code below:

CARmgp = 20

car = 123

Now let's say I had a typo, I meant to type in CARmpg instead of CARmgp. I place my cursor after the p, backspace a few times, and car = 123 suddenly turns into CAR = 123. I don't remember this happening in earlier versions of the IDE. Is this a potential bug? My thinking would be syntax checking would not be done until I leave the current line being edited.

While working on the helicopter blade code I uploaded earlier it happened as well because I was using simple one letter variables for the loops (i, j, k) but while messing around with other variables these were getting upper and lower-cased occasionally on their own.

36
Programs / Helicopter blades
« on: August 31, 2018, 12:32:15 am »
I was working on an idea for helicopter blades tonight for a game similar to: http://www.helicopter-game.org/

I thought instead of using a sprite sheet why not mathematically draw them and then store them in images instead of using a sprite sheet. Below is the result which I though I would share because the routine may be useful to others. Right now it looks like a ceiling fan spinning casting a shadow, LOL.

Code: QB64: [Select]
  1. '
  2. ' Helicopter blades idea
  3.  
  4. CONST PI = 3.1415926
  5.  
  6. start = -.00000001
  7. finish = -2 * PI / 16
  8. steps = finish / 20
  9. inc = -.0981726875
  10.  
  11. SCREEN _NEWIMAGE(640, 480, 32)
  12.  
  13.     FOR j = 0 TO 15
  14.         _LIMIT 30
  15.         CIRCLE (319, 239), 35, _RGB(25, 76, 127), , , .35
  16.         PAINT (319, 239), _RGB(25, 76, 127), _RGB(25, 76, 127)
  17.         FOR i = start + (inc * j) TO finish + (inc * j) STEP steps
  18.             FOR k = 0 TO 3
  19.                 radian = i + k * -1.5707963
  20.                 IF radian < -2 * PI THEN radian = radian + 2 * PI
  21.                 CIRCLE (319, 239), 35, _RGB(12, 38, 88), radian, radian, .35
  22.                 CIRCLE (319, 209), 35, _RGB(12, 38, 88), radian, radian, .35
  23.             NEXT k
  24.         NEXT i
  25.         _DISPLAY
  26.         CLS
  27.     NEXT j

37
InForm-based programs / InForm Calculator
« on: August 29, 2018, 11:48:46 pm »
I had fun learning to use InForm. Here is the calculator program I have been working on the past few days. There are still a few bugs in it (calculation errors due to QB64 giving results ending in .00000000000001 and some values coming up in scientific notation) and the Copy/Paste features are not operative. I still need to figure out how to get InForm to recognize when CTRL is pressed along with a keystroke when not on an active control.

Anyway, this little program gave me the general feel for InForm and got me back into programming QB64, a win-win.

calculator.png

38
InForm Discussion / Capturing keyboard input using _KEYHIT
« on: August 28, 2018, 01:30:18 am »
I need to capture keyboard input using Inform. I see that __UI_Keyhit contains the value of any key being pressed and then released. However, __UI_Keyhit will only contain these values if a control currently has focus. I need to know key presses all the time whether a control has focus or not.

_KEYHIT will occasionally see a keystroke and I'm assuming this is because InForm is grabbing keyboard input.

Is there a way to turn off InForm's keyboard processing so _KEYHIT can grab the scan codes instead, or another method built in to InFrom that grabs keystrokes?

edit: I do realize I can use INKEY$ but would prefer to use _KEYHIT if possible.

39
QB64 Discussion / Library section
« on: August 25, 2018, 03:56:03 pm »
I noticed there is no dedicated area for libraries as there was on [abandoned, outdated and now likely malicious qb64 dot net website - don’t go there]. I like the way the samples area is done with only the librarian having access to changes.

Would it be possible for a library area to be created much the same as the samples area but with a twist? Owners of libraries could post and modify but other users would not be able to post replies? Library discussion could be held in the standard forum areas instead.

The [abandoned, outdated and now likely malicious qb64 dot net website - don’t go there] library section got pretty convoluted over time with posts of code that were not really a library and discussions of other topics other than that pertaining to the libraries themselves. So many of us have functional libraries to share (and in my case update) that it would be nice to have a dedicated section.

Just a thought.

40
InForm Discussion / InForm Tutorial?
« on: August 23, 2018, 05:46:33 pm »
Has anyone created an InForm tutorial? The wiki is a great resource however it lacks examples of how to implement the array of features offered.

41
Programs / QB64 Minesweeper
« on: August 22, 2018, 03:10:07 am »
Here is my QB64 version of Minesweeper I created using three of my custom libraries (which are included, as well as documentation).

screenshot1.png


 
screenshot2.png


 
screenshot3.png

42
Programs / Maze Generators
« on: August 22, 2018, 02:53:34 am »
In another thread I posted a maze generator I created many years ago. Here it is again:

Code: QB64: [Select]
  1. '**
  2. '** MAZEGEN by Terry Ritchie
  3. '**
  4. '** Creates random 20x16 braided mazes (or perfect mazes with modification)
  5. '**
  6. '** This code was created from pseudo-code obtained at MAZEWORKS.COM
  7. '**
  8. '** This code could be easily modified to create any size maze and cell size
  9. '**
  10. '** If you use this code in your program please credit me and MAZEWORKS.COM
  11. '**
  12. '** Code last modified 02/23/09
  13. '**
  14. '** This maze generating code was created to use in a MEGABUG (Tandy/Radio
  15. '** Shack game from 1982) clone to teach introductory programming. The
  16. '** original game used a 20x16 maze grid. This is why the maze generator has
  17. '** been hard coded to only use a 16x20 grid. A little modification would
  18. '** allow this code to generate any size maze with any size cell.
  19. '**
  20.  
  21. CONST false = 0, true = NOT false
  22. CONST totalcells = 320
  23.  
  24. TYPE cell
  25.   walls AS INTEGER
  26.   x AS INTEGER
  27.   y AS INTEGER
  28.  
  29. TYPE stack
  30.   x AS INTEGER
  31.   y AS INTEGER
  32.  
  33. DECLARE SUB CreateRandomMaze ()
  34. DECLARE SUB DrawMaze ()
  35. DECLARE SUB DrawCell (cellx AS INTEGER, celly AS INTEGER)
  36. DECLARE SUB RemoveWall (cellx AS INTEGER, celly AS INTEGER, dir AS INTEGER)
  37.  
  38. DIM SHARED maze(0 TO 19, 0 TO 15) AS cell
  39.  
  40. SCREEN 7, 0, 1, 0
  41.  
  42.   LINE (81, 37)-(239, 163), 0, BF   'faster than CLS
  43.   CreateRandomMaze
  44.   DrawMaze
  45.   PCOPY 1, 0
  46.   SLEEP 1               '**rem this line out to see how fast it is!
  47.  
  48.  
  49. SUB CreateRandomMaze
  50. '**
  51. '** Creates a random 20x16 braided (looping) maze by first creating a perfect
  52. '** maze (a maze with no loops) then visiting each dead end and randomly
  53. '** opening them to create loops.
  54. '**
  55. '** vcells stores valid next maze cell moves in binary (bit) format
  56. '** if all adjacent cell walls are turned on then that cell is saved in vcells
  57. '** as follows:
  58. '**             bit 1 (2^0) = north cell has all walls on
  59. '**             bit 2 (2^1) = east  cell has all walls on
  60. '**             bit 3 (2^2) = south cell has all walls on
  61. '**             bit 4 (2^3) = west  cell has all walls on
  62. '**
  63.   DIM stack(totalcells) AS stack            '** maze generation LIFO stack
  64.   DIM cellx, celly, counter AS INTEGER      '** general counters
  65.   DIM cell AS stack                         '** current cell being created
  66.   DIM pointer AS INTEGER                    '** pointer for use in LIFO stack
  67.   DIM vcells AS INTEGER                     '** which cells are valid moves?
  68.   DIM randomwall AS INTEGER                 '** random valid mover
  69.   DIM forward AS INTEGER                    '** movement indicator
  70.   RANDOMIZE TIMER                           '** seed random number generator
  71.   FOR cellx = 0 TO 19                       '** initialize maze grid
  72.     FOR celly = 0 TO 15
  73.       maze(cellx, celly).walls = 15         '** turn all walls on
  74.       maze(cellx, celly).x = 80 + cellx * 8 '** x coordinate upper left cell
  75.       maze(cellx, celly).y = 36 + celly * 8 '** y coordinate upper left cell
  76.     NEXT celly
  77.   NEXT cellx
  78.   cell.x = INT(RND(1) * 19)                 '** random x location
  79.   cell.y = INT(RND(1) * 15)                 '** random y location
  80.   visitedcells = 1                          '** initialize counter
  81.   pointer = 0                               '** initialize LIFO stack pointer
  82.   forward = false                           '** initialize movement indicator
  83.   WHILE visitedcells < totalcells           '** continue until all cells made
  84.     vcells = 0                              '** initialize valid move check
  85.     IF cell.y <> 0 THEN IF maze(cell.x, cell.y - 1).walls = 15 THEN vcells = vcells + 1
  86.     IF cell.x <> 19 THEN IF maze(cell.x + 1, cell.y).walls = 15 THEN vcells = vcells + 2
  87.     IF cell.y <> 15 THEN IF maze(cell.x, cell.y + 1).walls = 15 THEN vcells = vcells + 4
  88.     IF cell.x <> 0 THEN IF maze(cell.x - 1, cell.y).walls = 15 THEN vcells = vcells + 8
  89.     IF vcells <> 0 THEN                     '** at least 1 cell has all walls
  90.       DO                                    '** find a random move direction
  91.         randomwall = INT(RND(1) * 4)        '** 0=North 1=East 2=South 3=West
  92.       LOOP UNTIL vcells AND 2 ^ randomwall  '** is random direction valid?
  93.       stack(pointer).x = cell.x             '** save current cell position in
  94.       stack(pointer).y = cell.y             '** the stack
  95.       pointer = pointer + 1                 '** increment stack pointer
  96.       visitedcells = visitedcells + 1       '** increment cell counter
  97.       forward = true                        '** forward movement indicated
  98.       CALL RemoveWall(cell.x, cell.y, randomwall) '** remove random wall
  99.       SELECT CASE randomwall                '** which direction forward?
  100.         CASE 0
  101.           cell.y = cell.y - 1               '** move north
  102.         CASE 1
  103.           cell.x = cell.x + 1               '** move east
  104.         CASE 2
  105.           cell.y = cell.y + 1               '** move south
  106.         CASE 3
  107.           cell.x = cell.x - 1               '** move west
  108.       END SELECT
  109.     ELSE                                    '** no cells have all walls
  110.      
  111. '****** remark the lines below to create perfect mazes (no loops) ***********
  112. '****** the code below creates braided mazes (contains loops)     ***********
  113.  
  114.       IF forward THEN                       '** we hit a dead end!
  115.         forward = false                     '** forward movement stops here
  116.         IF INT(RND(1) * 2) = 1 THEN         '** 50% chance of wall removal
  117.           SELECT CASE randomwall            '** which wall?
  118.             CASE 0                          '** remove north wall
  119.               IF cell.y <> 0 THEN           '** unless it's a border
  120.                 CALL RemoveWall(cell.x, cell.y, randomwall)
  121.               END IF
  122.             CASE 1                          '** remove east wall
  123.               IF cell.x <> 19 THEN          '** unless it's a border
  124.                 CALL RemoveWall(cell.x, cell.y, randomwall)
  125.               END IF
  126.             CASE 2                          '** remove south wall
  127.               IF cell.y <> 15 THEN          '** unless it's a border
  128.                 CALL RemoveWall(cell.x, cell.y, randomwall)
  129.               END IF
  130.             CASE 3                          '** remove west wall
  131.               IF cell.x <> 0 THEN           '** unless it's a border
  132.                 CALL RemoveWall(cell.x, cell.y, randomwall)
  133.               END IF
  134.           END SELECT
  135.         END IF
  136.       END IF
  137.      
  138. '****** remark the lines above to create perfect mazes (no loops) ***********
  139. '****** the code above creates braided mazes (contains loops)     ***********
  140.  
  141.       pointer = pointer - 1                 '** decrement stack pointer
  142.       cell.x = stack(pointer).x             '** go back to previous cell
  143.       cell.y = stack(pointer).y             '** go back to previous cell
  144.     END IF
  145.   WEND                                      '** exit when all cells visited
  146.  
  147.  
  148. SUB DrawCell (cellx AS INTEGER, celly AS INTEGER)
  149.  
  150. '****************************************************************************
  151. '** draw cell to graphics screen                                            *
  152. '****************************************************************************
  153.  
  154.   IF maze(cellx, celly).walls AND 1 THEN LINE (maze(cellx, celly).x, maze(cellx, celly).y)-(maze(cellx, celly).x + 8, maze(cellx, celly).y), 1
  155.   IF maze(cellx, celly).walls AND 2 THEN LINE (maze(cellx, celly).x + 8, maze(cellx, celly).y)-(maze(cellx, celly).x + 8, maze(cellx, celly).y + 8), 1
  156.   IF maze(cellx, celly).walls AND 4 THEN LINE (maze(cellx, celly).x, maze(cellx, celly).y + 8)-(maze(cellx, celly).x + 8, maze(cellx, celly).y + 8), 1
  157.   IF maze(cellx, celly).walls AND 8 THEN LINE (maze(cellx, celly).x, maze(cellx, celly).y)-(maze(cellx, celly).x, maze(cellx, celly).y + 8), 1
  158.  
  159.  
  160. SUB DrawMaze
  161.  
  162. '****************************************************************************
  163. '* Draws the entire maze to the graphics screen                             *
  164. '****************************************************************************
  165.  
  166.   DIM x AS INTEGER                          '** holds x location of maze cell
  167.   DIM y AS INTEGER                          '** holds y location of maze cell
  168.  
  169.   FOR x = 0 TO 19                           '** cycle through all cells
  170.     FOR y = 0 TO 15
  171.       CALL DrawCell(x, y)                   '** draw each cell to the screen
  172.     NEXT y
  173.   NEXT x
  174.   LINE (79, 35)-(241, 165), 1, B            '** draw border around maze
  175.  
  176.  
  177. SUB RemoveWall (cellx AS INTEGER, celly AS INTEGER, dir AS INTEGER)
  178.  
  179. '****************************************************************************
  180. '* Removes the walls between to adjoining cells based on the direction of
  181. '* movement.                                                                *
  182. '****************************************************************************
  183.  
  184.   SELECT CASE dir                           '** which direction?
  185.     CASE 0                                  '** remove north/south walls
  186.       maze(cellx, celly).walls = maze(cellx, celly).walls - 1
  187.       maze(cellx, celly - 1).walls = maze(cellx, celly - 1).walls - 4
  188.     CASE 1                                  '** remove east/west walls
  189.       maze(cellx, celly).walls = maze(cellx, celly).walls - 2
  190.       maze(cellx + 1, celly).walls = maze(cellx + 1, celly).walls - 8
  191.     CASE 2                                  '** remove south/north walls
  192.       maze(cellx, celly).walls = maze(cellx, celly).walls - 4
  193.       maze(cellx, celly + 1).walls = maze(cellx, celly + 1).walls - 1
  194.     CASE 3                                  '** remove west/east walls
  195.       maze(cellx, celly).walls = maze(cellx, celly).walls - 8
  196.       maze(cellx - 1, celly).walls = maze(cellx - 1, celly).walls - 2
  197.  

However, while organizing my code snippets I found this second maze generator I created some years later. I completely forget I made this and can't even remember why any longer. It has many features for making, saving, and loading random and custom mazes.

Code: QB64: [Select]
  1. '**
  2. '** Maze Generator V1.0
  3. '**
  4. '** by Terry Ritchie - 02/06/13
  5. '**
  6. '** This code can generate random braided looping, non-looping or custom mazes by supplying a string of HEX characters.
  7. '**
  8. '** Mazes can be saved and loaded using the SAVEMAZE and LOADMAZE commands.
  9. '**
  10. '** An example of how to draw mazes is included as DRAWMAZE. The syntax for drawmaze is as follows:
  11. '**
  12. '** DRAWMAZE MazeType%, Thickness%, MazeColor~&
  13. '**
  14. '** - MazeType%  : 0 (or constant SQUARE) for a square maze, 1 (or constant ROUND) for a round maze
  15. '** - Thickness% : the wall thickness of the maze
  16. '** - MazeColor~&: the color of the maze walls
  17. '**
  18. '**   DRAWMAZE draws the maze image to the image handle MazeImage&
  19. '**
  20. '** To generate a random maze use the MAKEMAZE command as follows:
  21. '**
  22. '**                         +--------- R specifies a random maze
  23. '** MAKEMAZE "RL0A0A15"     |+-------- L specifies a looping maze (use N for non-looping maze)
  24. '** +-------------------+   || +------ 0A the next two characters in HEX specifies the horizontal width of maze, in this case 10
  25. '** | the command above |   || |
  26. '** | will produce a    |   vv v       The largest HEX value that can be used is FF, or 255, therefore the maximum width and height
  27. '** | random maze of 20 |   RL0A0A15   of the maze can't exceed 255x255 and the maximum cell size can't exceed 255.
  28. '** | cells wide by 20  |        ^ ^
  29. '** | cells high with   |        | |
  30. '** | each cell being   |        | +-- 15 the last two characters in HEX specifies the size of each cell in maze, in this case 21
  31. '** | 21 pixels in size |        +---- 0A the next two characters in HEX specifies the vertical height of maze, in this case 10
  32. '** +-------------------+
  33. '**
  34. '** To generate a maze of your own design use the MAKEMAZE command as follows:
  35. '**
  36. '** MAKEMAZE "050515<maze_string>"
  37. '** +-------------------+    +------- 05 the first two HEX digits specifies the horizontal width of the maze, in this case 5
  38. '** | the command above |    | +----- 05 the second two HEX digits specifies the vertical height of the maze, in this case 5
  39. '** | will produce a    |    | |
  40. '** | custom maze of 5  |    v v                  A sample maze string that creates a spiraling inward maze would be:
  41. '** | cells wide by 5   |   050515<maze_string>
  42. '** | cells high with   |        ^ ^                             "0505152AAAC6AAC55685553A953AAA9"
  43. '** | each cell being   |        | |
  44. '** | 21 pixels in size |        | +- <maze_string> is a string of HEX digits that describes the actual maze (see illustration below)
  45. '** +-------------------+        +--- 15 the last two HEX digits specifies the size of each pixel in the maze, in this case 21
  46. '**
  47. '** NOTE: Round mazes will look best if you keep the size of the cells at ODD numbers. The included DRAWMAZE example
  48. '**       subroutine was optimized to make sure that round mazes have a definite center line inside the maze, because these maze
  49. '**       rotuines are a spinoff of a game in progress that needs random round maze generation with defined center lines.
  50. '**
  51. '** After you have created a maze with MAKEMAZE you can use the SAVEMAZE command to save the maze to a file.  This will allow you to
  52. '** use the generated mazes in your own programs. The SAVEMAZE command is used as follows:
  53. '**
  54. '** SAVEMAZE "mymaze"
  55. '**
  56. '** There is no need to supply an extension. ".MAZ" will automagically be added to the name you gave your maze.
  57. '**
  58. '** You can load a previously saved maze using LOADMAZE as follows:
  59. '**
  60. '** LOADMAZE "mymaze", mymaze$
  61. '**
  62. '** The maze will be loaded and placed into the variable specified, in this case mymaze$
  63. '**
  64. '*****************************************************************************************************************************************
  65. '**                                                                                                                                      *
  66. '**                 The following is an illustration of the 16 cell conditions and their corresponding HEX values:                       *
  67. '**                                                                                                                                      *
  68. '*****************************************************************************************************************************************
  69. '**   |     |     Cell 1            *   |     |     Cell 2           *   |     |     Cell 3            *   |     |     Cell 4            *
  70. '** --|     |--   North door open   * --+--------   East door open   * --|     +--   North door open   * --+-----+--   South door open   *
  71. '**   |     |                       *   |                            *   |           East door open    *   |     |                       *
  72. '**   |     |                       *   |                            *   |                             *   |     |                       *
  73. '** --+-----+--                     * --+--------                    * --+--------                     * --|     |--                     *
  74. '**   |     |     HEX - 1           *   |     |     HEX - 2          *   |     |     HEX - 3           *   |     |     HEX - 4           *
  75. '*****************************************************************************************************************************************
  76. '**   |     |     Cell 5            *   |     |     Cell 6           *   |     |     Cell 7            *   |     |     Cell 8            *
  77. '** --|     |--   North door open   * --+--------   East door open   * --|     +--   North door open   * --------+--   West door open    *
  78. '**   |     |     South door open   *   |           South door open  *   |           South door open   *         |                       *
  79. '**   |     |                       *   |                            *   |           East door open    *         |                       *
  80. '** --|     |--                     * --|     +--                    * --|     +--                     * --------+--                     *
  81. '**   |     |     HEX - 5           *   |     |     HEX - 6          *   |     |     HEX - 7           *   |     |     HEX - 8           *
  82. '*****************************************************************************************************************************************
  83. '**   |     |     Cell 9            *   |     |     Cell 10          *   |     |     Cell 11           *   |     |     Cell 12           *
  84. '** --+     |--   North door open   * -----------   East door open   * --+     +--   North door open   * --+-----+--   South door open   *
  85. '**         |     West door open    *               West door open   *               East door open    *         |     West door open    *
  86. '**         |                       *                                *               West door open    *         |                       *
  87. '** --------+--                     * -----------                    * -----------                     * --+     +--                     *
  88. '**   |     |     HEX - 9           *   |     |     HEX - A          *   |     |     HEX - B           *   |     |     HEX - C           *
  89. '*****************************************************************************************************************************************
  90. '**   |     |     Cell 13           *   |     |     Cell 14          *   |     |     Cell 15           * \ |     | /   Cell 0            *
  91. '** --+     |--   North door open   * -----------   East door open   * --+     +--   North door open   * --+-----+--   No doors open     *
  92. '**         |     South door open   *               South door open  *               East door open    *   | \ / |     (nothing will be  *
  93. '**         |     West door open    *               West door open   *               South door open   *   | / \ |      drawn to the     *
  94. '** --+     |--                     * --+     +--                    * --+     +--   West door open    * --+-----+--    maze image)      *
  95. '**   |     |     HEX - D           *   |     |     HEX - E          *   |     |     HEX - F           * / |     | \   HEX - 0           *
  96. '*****************************************************************************************************************************************
  97. '**                                                                                                                                      *
  98. '** Each open door is treated as a digit in a binary nibble:  North = 2^0  East = 2^1  South = 2^2  West = 2^3                           *
  99. '**                                                                                                                                      *
  100. '** Therefore, one hexadecimal digit can store the state of all four doors of a cell. i.e. F = 2^0+2^1+2^2+2^3 = 15 = all doors open.    *
  101. '**                                                                                                                                      *
  102. '*****************************************************************************************************************************************
  103.  
  104. CONST FALSE = 0, TRUE = NOT FALSE '           boolean truth testers
  105. CONST PI = 3.1415926 '                        would you like a piece?
  106. CONST PIUP = 1.5707963 '                      radian pointing up
  107. CONST PIDOWN = 4.7123889 '                    radian pointing down
  108. CONST SQUARE = 0
  109. CONST ROUND = 1
  110.  
  111. TYPE CELL
  112.     Xpos AS INTEGER '                         the X screen coordinate of this cell
  113.     Ypos AS INTEGER '                         the Y screen coordinate of this cell
  114.     Doors AS INTEGER '                        the doors that are open in this cell (1-up, 2-right, 4-down, 8-left)
  115.  
  116. TYPE LOCATION
  117.     Hor AS INTEGER '                          horizontal X position of this cell
  118.     Ver AS INTEGER '                          vertical Y position of this cell
  119.  
  120. TYPE STACK
  121.     Xpos AS INTEGER '                         horizontal X position of cell in stack
  122.     Ypos AS INTEGER '                         vertical Y position of cell in stack
  123.  
  124. TYPE MAZE
  125.     Hcell AS INTEGER '                        number of horizontal cells in maze
  126.     Vcell AS INTEGER '                        number of vertical cells in maze
  127.     CellSize AS INTEGER '                     the size of each maze cell
  128.     Thickness AS INTEGER '                    the wall thickness of the maze
  129.     Colour AS _UNSIGNED LONG '                the maze wall color
  130.     MazeType AS INTEGER '                     the type of maze (0-square, 1-round)
  131.     Looping AS INTEGER '                      0 for non looping, 1 for looping
  132.  
  133. REDIM Cell(0, 0) AS CELL '                    an array of maze cells
  134. DIM Maze AS MAZE '                            the maze properties
  135. DIM MazeImage& '                              the maze image holder
  136. DIM MyMaze$
  137.  
  138. RANDOMIZE TIMER '                             seed the random number generator
  139.  
  140. SCREEN _NEWIMAGE(1280, 720, 32)
  141.  
  142. MAKEMAZE "0505152AAAC6AAC55685553A953AAA9" ' create a custom maze
  143. DRAWMAZE ROUND, 6, _RGB32(64, 64, 64) '      draw the custom round maze to the screen
  144. SAVEMAZE "mymaze" '                          save the maze as MYMAZE.MAZ
  145. _PUTIMAGE (0, 0), MazeImage& '               this puts maze on screen in real size
  146. LOCATE 2, 2: PRINT " A custom maze - saved to HDD"
  147. SLEEP '                                      wait for a key press
  148. MAKEMAZE "RL141429" '                        create a 20 x 20 random looping maze with a cell size of 41 pixels
  149. DRAWMAZE SQUARE, 6, _RGB32(64, 64, 64) '     draw the random square maze to the screen
  150. _PUTIMAGE (0, 0), MazeImage& '               this puts maze on screen in real size
  151. LOCATE 2, 2: PRINT " A random 20x20 square looping maze with 41 pixel sized cells (too big for screen)"
  152. SLEEP '                                      wait for a keypress
  153. MAKEMAZE "RN0A0A1F" '                        create a 10 x 10 random non-looping maze with a cell size of 31 pixels
  154. DRAWMAZE ROUND, 6, _RGB32(64, 64, 64) '      draw the random round maze to the screen
  155. _PUTIMAGE (0, 0), MazeImage& '               this puts maze on screen in real size
  156. LOCATE 2, 2: PRINT " A random 10x10 round non-looping maze with 31 pixel sized cells"
  157. SLEEP '                                      wait for a keypress
  158. LOADMAZE "mymaze", MyMaze$ '                 load previously saved maze and place maze in MyMaze$
  159. MAKEMAZE MyMaze$ '                           create the loaded maze
  160. DRAWMAZE SQUARE, 6, _RGB32(64, 64, 64) '     draw the loaded maze, this time in square style
  161. _PUTIMAGE (0, 0), MazeImage& '               this puts maze on screen in real size
  162. LOCATE 2, 2: PRINT " The first maze loaded from HDD and now displayed as a square maze"
  163. SLEEP '                                      wait for a keypress
  164. SYSTEM '                                     return to OS
  165.  
  166.  
  167. '** NOTE:    _PUTIMAGE , MazeImage& '        this will always squeeze maze onto screen
  168.  
  169. '----------------------------------------------------------------------------------------------------------------------
  170.  
  171. SUB LOADMAZE (MazeFile$, MazeString$)
  172.  
  173. '**
  174. '** Loads a maze from HDD
  175. '**
  176.  
  177. OPEN MazeFile$ + ".MAZ" FOR INPUT AS #1 '                                      open the maze file for input
  178. LINE INPUT #1, MazeString$ '                                                   get the maze string from the file
  179. CLOSE #1 '                                                                     close the file
  180.  
  181.  
  182. '----------------------------------------------------------------------------------------------------------------------
  183.  
  184. SUB SAVEMAZE (MazeFile$)
  185.  
  186. '**
  187. '** Saves a maze to HDD
  188. '**
  189.  
  190. SHARED Cell() AS CELL '  we need access to the cell array
  191. SHARED Maze AS MAZE '    we need access to the maze properties
  192.  
  193. DIM v%, h% '             generic counters to keep track of current cell
  194. DIM MazeString$ '        the string generated that represents the maze
  195.  
  196. '**
  197. '** save the number of horizontal cells, vertical cells and cell size to the maze string
  198. '** make sure that each HEX value saved is at least two digits in length by padding a zero at the
  199. '** beginning of each HEX value
  200. '**
  201. MazeString$ = RIGHT$("0" + HEX$(Maze.Hcell), 2) + RIGHT$("0" + HEX$(Maze.Vcell), 2) + RIGHT$("0" + HEX$(Maze.CellSize), 2)
  202. FOR v% = 1 TO Maze.Vcell '                                                     cycle through all vertical cells
  203.     FOR h% = 1 TO Maze.Hcell '                                                 cycle through all horizontal cells
  204.         MazeString$ = MazeString$ + HEX$(Cell(h%, v%).Doors) '                 save this cell's door conditions to maze string
  205.     NEXT h%
  206. NEXT v%
  207. OPEN MazeFile$ + ".MAZ" FOR OUTPUT AS #1 '                                     open the maze file for output
  208. PRINT #1, MazeString$ '                                                        write the maze string to the file
  209. CLOSE #1 '                                                                     close the maze file
  210.  
  211.  
  212. '----------------------------------------------------------------------------------------------------------------------
  213.  
  214. SUB DRAWMAZE (Mtype%, Thick%, Mcolor~&)
  215.  
  216. '**
  217. '** Draws the maze to the maze image holder
  218. '**
  219. '** This command is included as an example of how you can draw custom or random mazes for use in your own programs.
  220. '** See the DRAWCELL subroutine for the complete picture.
  221. '**
  222.  
  223. SHARED Cell() AS CELL '  we need access to the cell array
  224. SHARED MazeImage& '      we need access to the maze image holder
  225. SHARED Maze AS MAZE '    we need access to the maze properties
  226.  
  227. DIM OriginalDest& '      the saved destination of the calling routine
  228. DIM v%, h% '             current horizontal and vertical cell being drawn
  229.  
  230.  
  231. Maze.Thickness = Thick% '                                                      wall thickness of maze
  232. Maze.Colour = Mcolor~& '                                                       maze wall color
  233. Maze.MazeType = Mtype% '                                                       type of maze
  234. IF MazeImage& THEN _FREEIMAGE MazeImage& '                                     free previous maze image created if one exists
  235. MazeImage& = _NEWIMAGE(Maze.CellSize * (Maze.Hcell + 1.5) * 2, Maze.CellSize * (Maze.Vcell + 1.5) * 2, 32) ' calculate maze image size
  236. OriginalDest& = _DEST '                                                        save calling routine destination
  237. _DEST MazeImage& '                                                             maze image is new destination
  238. FOR v% = 1 TO Maze.Vcell '                                                     cycle through all cell vertical locations
  239.     FOR h% = 1 TO Maze.Hcell '                                                 cycle through all cell horizontal locations
  240.         DRAWCELL Cell(h%, v%).Xpos, Cell(h%, v%).Ypos, Cell(h%, v%).Doors '    draw the cell at this location
  241.     NEXT h%
  242. NEXT v%
  243. _DEST OriginalDest& '                                                          restore calling routine destination
  244.  
  245.  
  246. '----------------------------------------------------------------------------------------------------------------------
  247.  
  248. SUB MAKEMAZE (Maze$)
  249.  
  250. '**
  251. '** Creates a random braided optional-looping maze
  252. '**
  253.  
  254. SHARED Cell() AS CELL '     we need access to the cell array
  255. SHARED Maze AS MAZE '       we need access to the maze properties
  256.  
  257. DIM CurrentCell AS STACK '  the current cell we are working with
  258. DIM Pointer% '              the stack pointer
  259. DIM ValidCells% '           contains the valid adjacent cells we can move to
  260. DIM RandomDir% '            a random direction to move
  261. DIM Forward% '              TRUE if we are moving forward through the maze
  262. DIM CellX% '                generic counter used to initiate cells
  263. DIM CellY% '                generic counter used to initiate cells
  264. DIM VisitedCells% '         number of cells visited by subroutine
  265. DIM Remove% '               TRUE if it's ok to open a looping door
  266. DIM Mz$ '                   the string holding the maze
  267. DIM Custom% '               -1 (TRUE) if custom maze, 0 (FALSE) if random
  268. DIM Mzpointer% '            maze string position pointer
  269.  
  270. Mz$ = UCASE$(Maze$) '                                                          convert passed maze string to uppercase
  271. Mzpointer% = 0 '                                                               reset maze string position pointer
  272. Custom% = -1 '                                                                 assume this will be a custom maze
  273. IF LEFT$(Mz$, 1) = "R" THEN '                                                  should we create a random maze?
  274.     Custom% = 0 '                                                              yes, remove custom flag
  275.     IF MID$(Mz$, 2, 1) = "L" THEN '                                            should this be a looping maze?
  276.         Maze.Looping = 1 '                                                     yes, make it so number one
  277.     ELSE '                                                                     no
  278.         Maze.Looping = 0 '                                                     this will not be a looping maze
  279.     END IF
  280.     Mz$ = RIGHT$(Mz$, LEN(Mz$) - 2) '                                          remove the first two characters from maze string
  281. Maze.Hcell = VAL("&H" + LEFT$(Mz$, 2)) '                                       set the number of horizontal cells in maze
  282. Maze.Vcell = VAL("&H" + MID$(Mz$, 3, 2)) '                                     set the number of vertical cells in maze
  283. Maze.CellSize = VAL("&H" + MID$(Mz$, 5, 2)) '                                  set the size of each cell
  284. REDIM Cell(Maze.Hcell, Maze.Vcell) AS CELL '                                   create an array of maze cells
  285. IF Custom% THEN '                                                              are we creating a custom maze?
  286.     Mz$ = RIGHT$(Mz$, LEN(Mz$) - 6) '                                          yes, remove first six characters from maze string
  287. ELSE '                                                                         no, we are creating a random maze
  288.     DIM Stack(Maze.Hcell * Maze.Vcell) AS STACK '                              create a LIFO stack array
  289. FOR CellY% = 1 TO Maze.Hcell '                                                 cycle through all vertical cells
  290.     FOR CellX% = 1 TO Maze.Vcell '                                             cycle through all horizontal cells
  291.         Mzpointer% = Mzpointer% + 1 '                                          increment the maze string position pointer
  292.         Cell(CellX%, CellY%).Xpos = CellX% * Maze.CellSize * 2 '               upper left X location of this cell
  293.         Cell(CellX%, CellY%).Ypos = CellY% * Maze.CellSize * 2 '               upper left Y location of this cell
  294.         IF Custom% THEN '                                                      is this a custom maze?
  295.             Cell(CellX%, CellY%).Doors = VAL("&H" + MID$(Mz$, Mzpointer%, 1)) 'yes, get this cell's door conditions from maze string
  296.         ELSE '                                                                 no, this will be a random maze
  297.             Cell(CellX%, CellY%).Doors = 0 '                                   set all cell doors closed
  298.         END IF
  299.     NEXT CellX%
  300. NEXT CellY%
  301. IF Custom% THEN EXIT SUB '                                                     no need to go further if this is a custom maze
  302. '**
  303. '** Start of random maze generation algorithm *********************************
  304. '**
  305. CurrentCell.Xpos = INT(RND(1) * Maze.Hcell) + 1 '                              random horizontal position of cell to start at
  306. CurrentCell.Ypos = INT(RND(1) * Maze.Vcell) + 1 '                              random vertical position of cell to start at
  307. VisitedCells% = 1 '                                                            keep track of how many cells visited
  308. Pointer% = 0 '                                                                 initiate the stack pointer
  309. Forward% = 0 '                                                                 not moving forward through maze yet
  310. WHILE VisitedCells% < Maze.Hcell * Maze.Vcell '                                make sure we visit all cells
  311.     ValidCells% = 0 '                                                          initiate number of valid neighbor cells
  312.     IF CurrentCell.Ypos <> 1 THEN '                                            are we at top of maze?
  313.         IF Cell(CurrentCell.Xpos, CurrentCell.Ypos - 1).Doors = 0 THEN '       no, does cell above have all doors closed?
  314.             ValidCells% = ValidCells% + 1 '                                    yes, remember this cell
  315.         END IF
  316.     END IF
  317.     IF CurrentCell.Xpos <> Maze.Hcell THEN '                                   are we at right side of maze?
  318.         IF Cell(CurrentCell.Xpos + 1, CurrentCell.Ypos).Doors = 0 THEN '       no, does cell to right have all doors closed?
  319.             ValidCells% = ValidCells% + 2 '                                    yes, remember this cell
  320.         END IF
  321.     END IF
  322.     IF CurrentCell.Ypos <> Maze.Vcell THEN '                                   are we at bottom of maze?
  323.         IF Cell(CurrentCell.Xpos, CurrentCell.Ypos + 1).Doors = 0 THEN '       no, does cell below have all doors closed?
  324.             ValidCells% = ValidCells% + 4 '                                    yes, remember this cell
  325.         END IF
  326.     END IF
  327.     IF CurrentCell.Xpos <> 1 THEN '                                            are we at left side of maze?
  328.         IF Cell(CurrentCell.Xpos - 1, CurrentCell.Ypos).Doors = 0 THEN '       no, does cell to left have all doors closed?
  329.             ValidCells% = ValidCells% + 8 '                                    yes, remember this cell
  330.         END IF
  331.     END IF
  332.     IF ValidCells% <> 0 THEN '                                                 did at least one cell have all doors closed?
  333.         DO '                                                                   yes, one or more of the cells have all doors closed
  334.             RandomDir% = INT(RND(1) * 4) '                                     choose a random cell direction
  335.         LOOP UNTIL ValidCells% AND 2 ^ RandomDir% '                            continue if this is a valid move
  336.         Stack(Pointer%) = CurrentCell '                                        push our current location into the LIFO stack
  337.         Pointer% = Pointer% + 1 '                                              increment the stack pointer
  338.         VisitedCells% = VisitedCells% + 1 '                                    increment the number of cells visited so far
  339.         Forward% = -1 '                                                        we are moving forward in the maze
  340.         OPENDOORS CurrentCell.Xpos, CurrentCell.Ypos, RandomDir% '             open current and adjacent cell doors
  341.         SELECT CASE RandomDir% '                                               which direction did we move forward?
  342.             CASE 0 '                                                           up/north
  343.                 CurrentCell.Ypos = CurrentCell.Ypos - 1 '                      make this the new current cell
  344.             CASE 1 '                                                           right/east
  345.                 CurrentCell.Xpos = CurrentCell.Xpos + 1 '                      make this the new current cell
  346.             CASE 2 '                                                           down/south
  347.                 CurrentCell.Ypos = CurrentCell.Ypos + 1 '                      make this the new current cell
  348.             CASE 3 '                                                           left/west
  349.                 CurrentCell.Xpos = CurrentCell.Xpos - 1 '                      make this the new current cell
  350.         END SELECT
  351.     ELSE '                                                                     no, all adjacent cells had at least one door open
  352.         IF Forward% THEN '                                                     were we previously moving forward in the maze?
  353.             Forward% = 0 '                                                     yes, we are not any longer
  354.             IF Maze.Looping = 1 THEN '                                         should this be a looping maze?
  355.                 'IF INT(RND(1) * 2) = 1 THEN '                                 yes, flip a coin to see if a loop structure built here
  356.                 Remove% = 0 '                                                  assume no doors will be opened
  357.                 SELECT CASE RandomDir% '                                       which direction were we traveling in?
  358.                     CASE 0 '                                                   up/north
  359.                         IF CurrentCell.Ypos <> 1 THEN Remove% = -1 '           if not at top of maze upper door can be opened
  360.                     CASE 1 '                                                   right/east
  361.                         IF CurrentCell.Xpos <> Maze.Hcell THEN Remove% = -1 '  if not at right side of maze right door can be opened
  362.                     CASE 2 '                                                   down/south
  363.                         IF CurrentCell.Ypos <> Maze.Vcell THEN Remove% = -1 '  if not at bottom of maze bottom door can be opened
  364.                     CASE 3 '                                                   left/west
  365.                         IF CurrentCell.Xpos <> 1 THEN Remove% = -1 '           if not at left side of maze left door can be opened
  366.                 END SELECT
  367.                 IF Remove% THEN '                                              is it ok to open a door?
  368.                     OPENDOORS CurrentCell.Xpos, CurrentCell.Ypos, RandomDir% ' yes, open current and adjacent cell doors
  369.                 END IF
  370.                 'END IF
  371.             END IF
  372.         END IF
  373.         Pointer% = Pointer% - 1 '                                              decrement the stack pointer
  374.         CurrentCell = Stack(Pointer%) '                                        pop the previous cell position from the LIFO stack
  375.     END IF
  376. REDIM Stack(0) AS STACK '                                                      clear the memory used by the stack
  377.  
  378.  
  379. '----------------------------------------------------------------------------------------------------------------------
  380.  
  381. SUB OPENDOORS (x%, y%, Direction%)
  382.  
  383. '**
  384. '** Opens a door in the current cell and the corresponding door in the adjacent cell
  385. '**
  386.  
  387. SHARED Cell() AS CELL '   we need access to the cell array
  388.  
  389. SELECT CASE Direction% '                                                       which direction are we going?
  390.     CASE 0 '                                                                   up/north
  391.         Cell(x%, y%).Doors = Cell(x%, y%).Doors + 1 '                          open the current cell's up door
  392.         Cell(x%, y% - 1).Doors = Cell(x%, y% - 1).Doors + 4 '                  open the adjacent cell's south door
  393.     CASE 1 '                                                                   right/east
  394.         Cell(x%, y%).Doors = Cell(x%, y%).Doors + 2 '                          open the current cell's right door
  395.         Cell(x% + 1, y%).Doors = Cell(x% + 1, y%).Doors + 8 '                  open the adjacent cell's left door
  396.     CASE 2 '                                                                   down/south
  397.         Cell(x%, y%).Doors = Cell(x%, y%).Doors + 4 '                          open the current cell's down door
  398.         Cell(x%, y% + 1).Doors = Cell(x%, y% + 1).Doors + 1 '                  open the adjacent cell's up door
  399.     CASE 3 '                                                                   left/west
  400.         Cell(x%, y%).Doors = Cell(x%, y%).Doors + 8 '                          open this cell's left door
  401.         Cell(x% - 1, y%).Doors = Cell(x% - 1, y%).Doors + 2 '                  open the adjacent cell's right door
  402.  
  403.  
  404. '----------------------------------------------------------------------------------------------------------------------
  405.  
  406. SUB DRAWCELL (x%, y%, n%)
  407.  
  408. '**
  409. '** Draws a maze cell
  410. '**
  411. '** The drawing routines below can produce either a square maze (0) or a round maze (1) as defined by Maze.MazeType
  412. '** These drawing routines are included to act as an example of how you can create custom maze drawing routines for
  413. '** the mazes you generate and use in your programs.
  414. '**
  415.  
  416. SHARED Maze AS MAZE '        we need access to the maze properties
  417.  
  418. DIM xc% '                    center X coordinate of cell
  419. DIM yc% '                    center Y coordiante of cell
  420. DIM Radius! '                radius of various maze corners
  421.  
  422. xc% = x% + Maze.CellSize \ 2 '                                                 calculate center X coordinate of cell
  423. yc% = y% + Maze.CellSize \ 2 '                                                 calculate center Y coordinate of cell
  424.  
  425. SELECT CASE n% '                                                               which cell to draw?
  426.     CASE 1 '                                                                   ** up door open
  427.         IF Maze.MazeType = 0 THEN
  428.             FOR Radius! = 1 TO Maze.Thickness - .5 STEP .5
  429.                 CIRCLES x% - 1, y% + Maze.CellSize, Radius!, Maze.Colour, PI, PIDOWN, 0
  430.                 CIRCLES x% + Maze.CellSize, y% + Maze.CellSize, Radius!, Maze.Colour, PIDOWN, 0, 0
  431.             NEXT Radius!
  432.             LINE (x% - 1, y% + Maze.CellSize)-(x% - Maze.Thickness, yc% - Maze.CellSize), Maze.Colour, BF
  433.             LINE (x% + Maze.CellSize, y% + Maze.CellSize)-(x% + Maze.CellSize + Maze.Thickness - 1, yc% - Maze.CellSize), Maze.Colour, BF
  434.             LINE (x% - 1, y% + Maze.CellSize)-(x% + Maze.CellSize, y% + Maze.CellSize + Maze.Thickness - 1), Maze.Colour, BF
  435.         ELSE '                                                                 ** round maze
  436.             FOR Radius! = Maze.CellSize / 2 + 1 TO Maze.CellSize / 2 + Maze.Thickness STEP .5
  437.                 CIRCLES xc%, yc%, Radius!, Maze.Colour, PI, 0, 0
  438.             NEXT Radius!
  439.             LINE (x% - 1, yc%)-(x% - Maze.Thickness, yc% - Maze.CellSize), Maze.Colour, BF
  440.             LINE (x% + Maze.CellSize, yc%)-(x% + Maze.CellSize + Maze.Thickness - 1, yc% - Maze.CellSize), Maze.Colour, BF
  441.         END IF
  442.     CASE 2 '                                                                   ** right door open
  443.         IF Maze.MazeType = 0 THEN
  444.             FOR Radius! = 1 TO Maze.Thickness - .5 STEP .5
  445.                 CIRCLES x% - 1, y% - 1, Radius!, Maze.Colour, PIUP, PI, 0
  446.                 CIRCLES x% - 1, y% + Maze.CellSize, Radius!, Maze.Colour, PI, PIDOWN, 0
  447.             NEXT Radius!
  448.             LINE (x% - 1, y% - 1)-(xc% + Maze.CellSize, y% - Maze.Thickness), Maze.Colour, BF
  449.             LINE (x% - 1, y% + Maze.CellSize)-(xc% + Maze.CellSize, y% + Maze.CellSize + Maze.Thickness - 1), Maze.Colour, BF
  450.             LINE (x% - 1, y% - 1)-(x% - Maze.Thickness, y% + Maze.CellSize), Maze.Colour, BF
  451.         ELSE
  452.             FOR Radius! = Maze.CellSize / 2 + 1 TO Maze.CellSize / 2 + Maze.Thickness STEP .5
  453.                 CIRCLES xc%, yc%, Radius!, Maze.Colour, PIUP, PIDOWN, 0
  454.             NEXT Radius!
  455.             LINE (xc%, y% - 1)-(xc% + Maze.CellSize, y% - Maze.Thickness), Maze.Colour, BF
  456.             LINE (xc%, y% + Maze.CellSize)-(xc% + Maze.CellSize, y% + Maze.CellSize + Maze.Thickness - 1), Maze.Colour, BF
  457.         END IF
  458.     CASE 3 '                                                                   ** up and right doors open
  459.         IF Maze.MazeType = 0 THEN
  460.             FOR Radius! = 1 TO Maze.Thickness - .5 STEP .5
  461.                 CIRCLES x% + Maze.CellSize + Maze.Thickness - 1, y% - Maze.Thickness, Radius!, Maze.Colour, PI, PIDOWN, 0
  462.                 CIRCLES x% - 1, y% + Maze.CellSize, Radius!, Maze.Colour, PI, PIDOWN, 0
  463.             NEXT Radius!
  464.             LINE (x% - 1, y% + Maze.CellSize)-(x% - Maze.Thickness, yc% - Maze.CellSize), Maze.Colour, BF
  465.             LINE (x% - 1, y% + Maze.CellSize)-(xc% + Maze.CellSize, y% + Maze.CellSize + Maze.Thickness - 1), Maze.Colour, BF
  466.             LINE (x% + Maze.CellSize, yc% - Maze.CellSize)-(x% + Maze.CellSize + Maze.Thickness - 1, y% - Maze.Thickness), Maze.Colour, BF
  467.             LINE (x% + Maze.CellSize + Maze.Thickness - 1, y% - 1)-(xc% + Maze.CellSize, y% - Maze.Thickness), Maze.Colour, BF
  468.         ELSE
  469.             FOR Radius! = Maze.CellSize / 2 - Maze.Thickness TO Maze.CellSize / 2 STEP .5
  470.                 CIRCLES xc% + Maze.CellSize, yc% - Maze.CellSize, Radius!, Maze.Colour, PI, PIDOWN, 0
  471.             NEXT Radius!
  472.             FOR Radius! = Maze.CellSize * 1.5 + Maze.Thickness TO Maze.CellSize * 1.5 + 1 STEP -.5
  473.                 CIRCLES xc% + Maze.CellSize, yc% - Maze.CellSize, Radius!, Maze.Colour, PI, PIDOWN, 0
  474.             NEXT Radius!
  475.         END IF
  476.     CASE 4 '                                                                   ** down door open
  477.         IF Maze.MazeType = 0 THEN
  478.             FOR Radius! = 1 TO Maze.Thickness - .5 STEP .5
  479.                 CIRCLES x% - 1, y% - 1, Radius!, Maze.Colour, PIUP, PI, 0
  480.                 CIRCLES x% + Maze.CellSize, y% - 1, Radius!, Maze.Colour, 0, PIUP, 0
  481.             NEXT Radius!
  482.             LINE (x% - 1, y% - 1)-(x% - Maze.Thickness, yc% + Maze.CellSize), Maze.Colour, BF
  483.             LINE (x% + Maze.CellSize, y% - 1)-(x% + Maze.CellSize + Maze.Thickness - 1, yc% + Maze.CellSize), Maze.Colour, BF
  484.             LINE (x% - 1, y% - 1)-(x% + Maze.CellSize, y% - Maze.Thickness), Maze.Colour, BF
  485.         ELSE
  486.             FOR Radius! = Maze.CellSize / 2 + 1 TO Maze.CellSize / 2 + Maze.Thickness STEP .5
  487.                 CIRCLES xc%, yc%, Radius!, Maze.Colour, 0, PI, 0
  488.             NEXT Radius!
  489.             LINE (x% - 1, yc%)-(x% - Maze.Thickness, yc% + Maze.CellSize), Maze.Colour, BF
  490.             LINE (x% + Maze.CellSize, yc%)-(x% + Maze.CellSize + Maze.Thickness - 1, yc% + Maze.CellSize), Maze.Colour, BF
  491.         END IF
  492.     CASE 5 '                                                                   **  up and down doors open
  493.         LINE (x% - 1, yc% - Maze.CellSize)-(x% - Maze.Thickness, yc% + Maze.CellSize), Maze.Colour, BF
  494.         LINE (x% + Maze.CellSize, yc% - Maze.CellSize)-(x% + Maze.CellSize + Maze.Thickness - 1, yc% + Maze.CellSize), Maze.Colour, BF
  495.     CASE 6 '                                                                   ** down and right doors open
  496.         IF Maze.MazeType = 0 THEN
  497.             FOR Radius! = 1 TO Maze.Thickness - .5 STEP .5
  498.                 CIRCLES x% - 1, y% - 1, Radius!, Maze.Colour, PIUP, PI, 0
  499.                 CIRCLES x% + Maze.CellSize + Maze.Thickness - 1, y% + Maze.CellSize + Maze.Thickness - 1, Radius!, Maze.Colour, PIUP, PI, 0
  500.             NEXT Radius!
  501.             LINE (x% - 1, y% - 1)-(x% - Maze.Thickness, yc% + Maze.CellSize), Maze.Colour, BF
  502.             LINE (x% - 1, y% - 1)-(xc% + Maze.CellSize, y% - Maze.Thickness), Maze.Colour, BF
  503.             LINE (x% + Maze.CellSize + Maze.Thickness - 1, y% + Maze.CellSize)-(xc% + Maze.CellSize, y% + Maze.CellSize + Maze.Thickness - 1), Maze.Colour, BF
  504.             LINE (x% + Maze.CellSize, y% + Maze.CellSize + Maze.Thickness - 1)-(x% + Maze.CellSize + Maze.Thickness - 1, yc% + Maze.CellSize), Maze.Colour, BF
  505.         ELSE
  506.             FOR Radius! = Maze.CellSize / 2 - Maze.Thickness TO Maze.CellSize / 2 STEP .5
  507.                 CIRCLES xc% + Maze.CellSize, yc% + Maze.CellSize, Radius!, Maze.Colour, PIUP, PI, 0
  508.             NEXT Radius!
  509.             FOR Radius! = Maze.CellSize * 1.5 + Maze.Thickness TO Maze.CellSize * 1.5 + 1 STEP -.5
  510.                 CIRCLES xc% + Maze.CellSize, yc% + Maze.CellSize, Radius!, Maze.Colour, PIUP, PI, 0
  511.             NEXT Radius!
  512.         END IF
  513.     CASE 7 '                                                                   ** up and down and right doors open
  514.         IF Maze.MazeType = 0 THEN
  515.             FOR Radius! = 1 TO Maze.Thickness - .5 STEP .5
  516.                 CIRCLES x% + Maze.CellSize + Maze.Thickness - 1, y% - Maze.Thickness, Radius!, Maze.Colour, PI, PIDOWN, 0
  517.                 CIRCLES x% + Maze.CellSize + Maze.Thickness - 1, y% + Maze.CellSize + Maze.Thickness - 1, Radius!, Maze.Colour, PIUP, PI, 0
  518.             NEXT Radius!
  519.             LINE (x% - 1, yc% - Maze.CellSize)-(x% - Maze.Thickness, yc% + Maze.CellSize), Maze.Colour, BF
  520.             LINE (x% + Maze.CellSize + Maze.Thickness - 1, y% + Maze.CellSize)-(xc% + Maze.CellSize, y% + Maze.CellSize + Maze.Thickness - 1), Maze.Colour, BF
  521.             LINE (x% + Maze.CellSize, y% + Maze.CellSize + Maze.Thickness - 1)-(x% + Maze.CellSize + Maze.Thickness - 1, yc% + Maze.CellSize), Maze.Colour, BF
  522.             LINE (x% + Maze.CellSize, yc% - Maze.CellSize)-(x% + Maze.CellSize + Maze.Thickness - 1, y% - Maze.Thickness), Maze.Colour, BF
  523.             LINE (xc% + Maze.CellSize, y% - 1)-(x% + Maze.CellSize + Maze.Thickness - 1, y% - Maze.Thickness), Maze.Colour, BF
  524.         ELSE
  525.             FOR Radius! = Maze.CellSize / 2 - Maze.Thickness TO Maze.CellSize / 2 STEP .5
  526.                 CIRCLES xc% + Maze.CellSize, yc% - Maze.CellSize, Radius!, Maze.Colour, PI, PIDOWN, 0
  527.                 CIRCLES xc% + Maze.CellSize, yc% + Maze.CellSize, Radius!, Maze.Colour, PIUP, PI, 0
  528.             NEXT Radius!
  529.             LINE (x% - 1, yc% - Maze.CellSize)-(x% - Maze.Thickness, yc% + Maze.CellSize), Maze.Colour, BF
  530.         END IF
  531.     CASE 8 '                                                                   ** left door open
  532.         IF Maze.MazeType = 0 THEN
  533.             FOR Radius! = 1 TO Maze.Thickness - .5 STEP .5
  534.                 CIRCLES x% + Maze.CellSize, y% - 1, Radius!, Maze.Colour, 0, PIUP, 0
  535.                 CIRCLES x% + Maze.CellSize, y% + Maze.CellSize, Radius!, Maze.Colour, PIDOWN, 0, 0
  536.             NEXT Radius!
  537.             LINE (xc% - Maze.CellSize, y% - 1)-(x% + Maze.CellSize, y% - Maze.Thickness), Maze.Colour, BF
  538.             LINE (xc% - Maze.CellSize, y% + Maze.CellSize)-(x% + Maze.CellSize, y% + Maze.CellSize + Maze.Thickness - 1), Maze.Colour, BF
  539.             LINE (x% + Maze.CellSize, y% - 1)-(x% + Maze.CellSize + Maze.Thickness - 1, y% + Maze.CellSize), Maze.Colour, BF
  540.         ELSE
  541.             FOR Radius! = Maze.CellSize / 2 + 1 TO Maze.CellSize / 2 + Maze.Thickness STEP .5
  542.                 CIRCLES xc%, yc%, Radius!, Maze.Colour, PIDOWN, PIUP, 0
  543.             NEXT Radius!
  544.             LINE (xc% - Maze.CellSize, y% - 1)-(xc%, y% - Maze.Thickness), Maze.Colour, BF
  545.             LINE (xc% - Maze.CellSize, y% + Maze.CellSize)-(xc%, y% + Maze.CellSize + Maze.Thickness - 1), Maze.Colour, BF
  546.         END IF
  547.     CASE 9 '                                                                   ** up and left doors open
  548.         IF Maze.MazeType = 0 THEN
  549.             FOR Radius! = 1 TO Maze.Thickness - .5 STEP .5
  550.                 CIRCLES x% - Maze.Thickness, y% - Maze.Thickness, Radius!, Maze.Colour, PIDOWN, 0, 0
  551.                 CIRCLES x% + Maze.CellSize, y% + Maze.CellSize, Radius!, Maze.Colour, PIDOWN, 0, 0
  552.             NEXT Radius!
  553.             LINE (xc% - Maze.CellSize, y% + Maze.CellSize)-(x% + Maze.CellSize, y% + Maze.CellSize + Maze.Thickness - 1), Maze.Colour, BF
  554.             LINE (x% + Maze.CellSize, yc% - Maze.CellSize)-(x% + Maze.CellSize + Maze.Thickness - 1, y% + Maze.CellSize), Maze.Colour, BF
  555.             LINE (xc% - Maze.CellSize, y% - 1)-(x% - Maze.Thickness, y% - Maze.Thickness), Maze.Colour, BF
  556.             LINE (x% - 1, yc% - Maze.CellSize)-(x% - Maze.Thickness, y% - Maze.Thickness), Maze.Colour, BF
  557.         ELSE
  558.             FOR Radius! = Maze.CellSize / 2 - Maze.Thickness TO Maze.CellSize / 2 STEP .5
  559.                 CIRCLES xc% - Maze.CellSize, yc% - Maze.CellSize, Radius!, Maze.Colour, PIDOWN, 0, 0
  560.             NEXT Radius!
  561.             FOR Radius! = Maze.CellSize * 1.5 + Maze.Thickness TO Maze.CellSize * 1.5 + 1 STEP -.5
  562.                 CIRCLES xc% - Maze.CellSize, yc% - Maze.CellSize, Radius!, Maze.Colour, PIDOWN, 0, 0
  563.             NEXT Radius!
  564.         END IF
  565.     CASE 10 '                                                                  ** left and right doors open
  566.         LINE (xc% - Maze.CellSize, y% - 1)-(xc% + Maze.CellSize, y% - Maze.Thickness), Maze.Colour, BF
  567.         LINE (xc% - Maze.CellSize, y% + Maze.CellSize)-(xc% + Maze.CellSize, y% + Maze.CellSize + Maze.Thickness - 1), Maze.Colour, BF
  568.     CASE 11 '                                                                  ** up and left and right doors open
  569.         IF Maze.MazeType = 0 THEN
  570.             FOR Radius! = 1 TO Maze.Thickness - .5 STEP .5
  571.                 CIRCLES x% - Maze.Thickness, y% - Maze.Thickness, Radius!, Maze.Colour, PIDOWN, 0, 0
  572.                 CIRCLES x% + Maze.CellSize + Maze.Thickness - 1, y% - Maze.Thickness, Radius!, Maze.Colour, PI, PIDOWN, 0
  573.             NEXT Radius!
  574.             LINE (xc% - Maze.CellSize, y% + Maze.CellSize)-(xc% + Maze.CellSize, y% + Maze.CellSize + Maze.Thickness - 1), Maze.Colour, BF
  575.             LINE (xc% - Maze.CellSize, y% - 1)-(x% - Maze.Thickness, y% - Maze.Thickness), Maze.Colour, BF
  576.             LINE (x% - 1, yc% - Maze.CellSize)-(x% - Maze.Thickness, y% - Maze.Thickness), Maze.Colour, BF
  577.             LINE (x% + Maze.CellSize, yc% - Maze.CellSize)-(x% + Maze.CellSize + Maze.Thickness - 1, y% - Maze.Thickness), Maze.Colour, BF
  578.             LINE (xc% + Maze.CellSize, y% - 1)-(x% + Maze.CellSize + Maze.Thickness - 1, y% - Maze.Thickness), Maze.Colour, BF
  579.         ELSE
  580.             FOR Radius! = Maze.CellSize / 2 - Maze.Thickness TO Maze.CellSize / 2 STEP .5
  581.                 CIRCLES xc% - Maze.CellSize, yc% - Maze.CellSize, Radius!, Maze.Colour, PIDOWN, 0, 0
  582.                 CIRCLES xc% + Maze.CellSize, yc% - Maze.CellSize, Radius!, Maze.Colour, PI, PIDOWN, 0
  583.             NEXT Radius!
  584.             LINE (xc% - Maze.CellSize, y% + Maze.CellSize)-(xc% + Maze.CellSize, y% + Maze.CellSize + Maze.Thickness - 1), Maze.Colour, BF
  585.         END IF
  586.     CASE 12 '                                                                  ** down and left doors open
  587.         IF Maze.MazeType = 0 THEN
  588.             FOR Radius! = 1 TO Maze.Thickness - .5 STEP .5
  589.                 CIRCLES x% + Maze.CellSize, y% - 1, Radius!, Maze.Colour, 0, PIUP, 0
  590.                 CIRCLES x% - Maze.Thickness, y% + Maze.CellSize + Maze.Thickness - 1, Radius!, Maze.Colour, 0, PIUP, 0
  591.             NEXT Radius!
  592.             LINE (xc% - Maze.CellSize, y% - 1)-(x% + Maze.CellSize, y% - Maze.Thickness), Maze.Colour, BF
  593.             LINE (x% + Maze.CellSize, y% - 1)-(x% + Maze.CellSize + Maze.Thickness - 1, yc% + Maze.CellSize), Maze.Colour, BF
  594.             LINE (xc% - Maze.CellSize, y% + Maze.CellSize)-(x% - Maze.Thickness, y% + Maze.CellSize + Maze.Thickness - 1), Maze.Colour, BF
  595.             LINE (x% - 1, yc% + Maze.CellSize)-(x% - Maze.Thickness, y% + Maze.CellSize + Maze.Thickness - 1), Maze.Colour, BF
  596.         ELSE
  597.             FOR Radius! = Maze.CellSize / 2 - Maze.Thickness TO Maze.CellSize / 2 STEP .5
  598.                 CIRCLES xc% - Maze.CellSize, yc% + Maze.CellSize, Radius!, Maze.Colour, 0, PIUP, 0
  599.             NEXT Radius!
  600.             FOR Radius! = Maze.CellSize * 1.5 + Maze.Thickness TO Maze.CellSize * 1.5 + 1 STEP -.5
  601.                 CIRCLES xc% - Maze.CellSize, yc% + Maze.CellSize, Radius!, Maze.Colour, 0, PIUP, 0
  602.             NEXT Radius!
  603.         END IF
  604.     CASE 13 '                                                                  ** up and down and left doors open
  605.         IF Maze.MazeType = 0 THEN
  606.             FOR Radius! = 1 TO Maze.Thickness - .5 STEP .5
  607.                 CIRCLES x% - Maze.Thickness, y% - Maze.Thickness, Radius!, Maze.Colour, PIDOWN, 0, 0
  608.                 CIRCLES x% - Maze.Thickness, y% + Maze.CellSize + Maze.Thickness - 1, Radius!, Maze.Colour, 0, PIUP, 0
  609.             NEXT Radius!
  610.             LINE (x% + Maze.CellSize, yc% - Maze.CellSize)-(x% + Maze.CellSize + Maze.Thickness - 1, yc% + Maze.CellSize), Maze.Colour, BF
  611.             LINE (xc% - Maze.CellSize, y% - 1)-(x% - Maze.Thickness, y% - Maze.Thickness), Maze.Colour, BF
  612.             LINE (x% - 1, yc% - Maze.CellSize)-(x% - Maze.Thickness, y% - Maze.Thickness), Maze.Colour, BF
  613.             LINE (xc% - Maze.CellSize, y% + Maze.CellSize)-(x% - Maze.Thickness, y% + Maze.CellSize + Maze.Thickness - 1), Maze.Colour, BF
  614.             LINE (x% - 1, yc% + Maze.CellSize)-(x% - Maze.Thickness, y% + Maze.CellSize + Maze.Thickness - 1), Maze.Colour, BF
  615.         ELSE
  616.             FOR Radius! = Maze.CellSize / 2 - Maze.Thickness TO Maze.CellSize / 2 STEP .5
  617.                 CIRCLES xc% - Maze.CellSize, yc% + Maze.CellSize, Radius!, Maze.Colour, 0, PIUP, 0
  618.                 CIRCLES xc% - Maze.CellSize, yc% - Maze.CellSize, Radius!, Maze.Colour, PIDOWN, 0, 0
  619.             NEXT Radius!
  620.             LINE (x% + Maze.CellSize, yc% - Maze.CellSize)-(x% + Maze.CellSize + Maze.Thickness - 1, yc% + Maze.CellSize), Maze.Colour, BF
  621.         END IF
  622.     CASE 14 '                                                                  ** down and left and right doors open
  623.         IF Maze.MazeType = 0 THEN
  624.             FOR Radius! = 1 TO Maze.Thickness - .5 STEP .5
  625.                 CIRCLES x% + Maze.CellSize + Maze.Thickness - 1, y% + Maze.CellSize + Maze.Thickness - 1, Radius!, Maze.Colour, PIUP, PI, 0
  626.                 CIRCLES x% - Maze.Thickness, y% + Maze.CellSize + Maze.Thickness - 1, Radius!, Maze.Colour, 0, PIUP, 0
  627.             NEXT Radius!
  628.             LINE (xc% - Maze.CellSize, y% - 1)-(xc% + Maze.CellSize, y% - Maze.Thickness), Maze.Colour, BF
  629.             LINE (xc% - Maze.CellSize, y% + Maze.CellSize)-(x% - Maze.Thickness, y% + Maze.CellSize + Maze.Thickness - 1), Maze.Colour, BF
  630.             LINE (xc% + Maze.CellSize, y% + Maze.CellSize)-(x% + Maze.CellSize + Maze.Thickness - 1, y% + Maze.CellSize + Maze.Thickness - 1), Maze.Colour, BF
  631.             LINE (x% - 1, yc% + Maze.CellSize)-(x% - Maze.Thickness, y% + Maze.CellSize + Maze.Thickness - 1), Maze.Colour, BF
  632.             LINE (x% + Maze.CellSize, yc% + Maze.CellSize)-(x% + Maze.CellSize + Maze.Thickness - 1, y% + Maze.CellSize + Maze.Thickness - 1), Maze.Colour, BF
  633.         ELSE
  634.             FOR Radius! = Maze.CellSize / 2 - Maze.Thickness TO Maze.CellSize / 2 STEP .5
  635.                 CIRCLES xc% - Maze.CellSize, yc% + Maze.CellSize, Radius!, Maze.Colour, 0, PIUP, 0
  636.                 CIRCLES xc% + Maze.CellSize, yc% + Maze.CellSize, Radius!, Maze.Colour, PIUP, PI, 0
  637.             NEXT Radius!
  638.             LINE (xc% - Maze.CellSize, y% - 1)-(xc% + Maze.CellSize, y% - Maze.Thickness), Maze.Colour, BF
  639.         END IF
  640.     CASE 15 '                                                                  ** all doors open
  641.         IF Maze.MazeType = 0 THEN
  642.             FOR Radius! = 1 TO Maze.Thickness - .5 STEP .5
  643.                 CIRCLES x% - Maze.Thickness, y% - Maze.Thickness, Radius!, Maze.Colour, PIDOWN, 0, 0
  644.                 CIRCLES x% + Maze.CellSize + Maze.Thickness - 1, y% - Maze.Thickness, Radius!, Maze.Colour, PI, PIDOWN, 0
  645.                 CIRCLES x% + Maze.CellSize + Maze.Thickness - 1, y% + Maze.CellSize + Maze.Thickness - 1, Radius!, Maze.Colour, PIUP, PI, 0
  646.                 CIRCLES x% - Maze.Thickness, y% + Maze.CellSize + Maze.Thickness - 1, Radius!, Maze.Colour, 0, PIUP, 0
  647.             NEXT Radius!
  648.             LINE (xc% - Maze.CellSize, y% - 1)-(x% - Maze.Thickness, y% - Maze.Thickness), Maze.Colour, BF
  649.             LINE (x% - 1, yc% - Maze.CellSize)-(x% - Maze.Thickness, y% - Maze.Thickness), Maze.Colour, BF
  650.             LINE (x% + Maze.CellSize, yc% - Maze.CellSize)-(x% + Maze.CellSize + Maze.Thickness - 1, y% - Maze.Thickness), Maze.Colour, BF
  651.             LINE (xc% + Maze.CellSize, y% - 1)-(x% + Maze.CellSize + Maze.Thickness - 1, y% - Maze.Thickness), Maze.Colour, BF
  652.             LINE (xc% - Maze.CellSize, y% + Maze.CellSize)-(x% - Maze.Thickness, y% + Maze.CellSize + Maze.Thickness - 1), Maze.Colour, BF
  653.             LINE (xc% + Maze.CellSize, y% + Maze.CellSize)-(x% + Maze.CellSize + Maze.Thickness - 1, y% + Maze.CellSize + Maze.Thickness - 1), Maze.Colour, BF
  654.             LINE (x% - 1, yc% + Maze.CellSize)-(x% - Maze.Thickness, y% + Maze.CellSize + Maze.Thickness - 1), Maze.Colour, BF
  655.             LINE (x% + Maze.CellSize, yc% + Maze.CellSize)-(x% + Maze.CellSize + Maze.Thickness - 1, y% + Maze.CellSize + Maze.Thickness - 1), Maze.Colour, BF
  656.         ELSE
  657.             FOR Radius! = Maze.CellSize / 2 - Maze.Thickness TO Maze.CellSize / 2 STEP .5
  658.                 CIRCLES xc% - Maze.CellSize, yc% - Maze.CellSize, Radius!, Maze.Colour, PIDOWN, 0, 0
  659.                 CIRCLES xc% - Maze.CellSize, yc% + Maze.CellSize, Radius!, Maze.Colour, 0, PIUP, 0
  660.                 CIRCLES xc% + Maze.CellSize, yc% - Maze.CellSize, Radius!, Maze.Colour, PI, PIDOWN, 0
  661.                 CIRCLES xc% + Maze.CellSize, yc% + Maze.CellSize, Radius!, Maze.Colour, PIUP, PI, 0
  662.             NEXT Radius!
  663.         END IF
  664.  
  665.  
  666. '----------------------------------------------------------------------------------------------------------------------
  667.  
  668. SUB CIRCLES (cx%, cy%, r!, c~&, s!, e!, a!)
  669.  
  670. '**
  671. '** QB64 temporary replacement CIRCLE command.
  672. '**
  673. '** The CIRCLE command in QB64 has a few bugs listed below:
  674. '**
  675. '** - radian end points are not calculate properly when creating arcs
  676. '** - center line to radian end points do not close properly due to previous bug listed
  677. '**
  678. '** This circle command replacement works very similiarly to the native CIRCLE command:
  679. '**
  680. '** SYNTAX: CIRCLES x%, y%, radius!, color~&, start_radian!, end_radian!, aspect_ratio!
  681. '**
  682. '**   x%            - center X coordinate of circle
  683. '**   y%            - center Y coordinate of circle
  684. '**   radius!       - the radius of the circle
  685. '**   color~&       - the circle's color
  686. '**   start_radian! - the radian on circle curcunference to begin drawing at
  687. '**   end_radian!   - the radian on circle circumference to end drawing at
  688. '**   aspect_ratio! - the aspect ratio of the circle
  689. '**
  690. '** NOTE: unlike the native CIRCLE command, all arguments MUST be supplied. For example,
  691. '**       with the native command this will draw a perfect circle with the default color,
  692. '**       start radian, end radian and aspect ratio:
  693. '**
  694. '**       CIRCLE (319, 239), 100
  695. '**
  696. '**       To do the same thing with this replacement command you must supply everything:
  697. '**
  698. '**       CIRCLES 319, 239, 100, _RGB32(255, 255, 255), 0, 0, 0
  699. '**
  700. '** ACKNOWLEGEMENTS: The FOR/NEXT step formula was was written by Codeguy for Unseen
  701. '**                  Machine's Visual library EllipseXS command. Specifically:
  702. '**                         MinStep! = 1 / (2 * PI535 * Radius!)
  703. '**            NOTE: The FOR/NEXT loop was replaced with a DO/LOOP by SMcNeill - 02/02/-13
  704. '**
  705. '** Includes performance tweaks made by SMcNeill on 02/02/13 - specifically removing a few redundant * -1
  706. '** statements and converting the FOR/NEXT loop to a DO loop for a ~3% increase in performance.
  707. '**
  708. '** Corrected bug in which variables being passed in were being modified and passed back - 02/02/13
  709. '**
  710.  
  711. DIM s%, e%, nx%, ny%, xr!, yr!, st!, en!, asp! '     local variables used
  712.  
  713. st! = s! '                                           copy start radian to local variable
  714. en! = e! '                                           copy end radian to local variable
  715. asp! = a! '                                          copy aspect ratio to local variable
  716. IF asp! <= 0 THEN asp! = 1 '                         keep aspect ratio between 0 and 4
  717. IF asp! > 4 THEN asp! = 4
  718. IF asp! < 1 THEN xr! = r! * asp! * 4 ELSE xr! = r! ' calculate x/y radius based on aspect ratio
  719. IF asp! > 1 THEN yr! = r! * asp! ELSE yr! = r!
  720. IF st! < 0 THEN s% = -1: st! = -st! '                remember if line needs drawn from center to start radian
  721. IF en! < 0 THEN e% = -1: en! = -en! '                remember if line needs drawn from center to end radian
  722. IF s% THEN '                                         draw line from center to start radian?
  723.     nx% = cx% + xr! * COS(st!) '                     yes, compute starting point on circle's circumference
  724.     ny% = cy% + yr! * -SIN(st!)
  725.     LINE (cx%, cy%)-(nx%, ny%), c~& '                draw line from center to radian
  726. IF en! <= st! THEN en! = en! + 6.2831852 '           come back around to proper location (draw counterclockwise)
  727. stepp! = 0.159154945806 / r!
  728. c! = st! '                                           cycle from start radian to end radian
  729.     nx% = cx% + xr! * COS(c!) '                      compute next point on circle's circumfrerence
  730.     ny% = cy% + yr! * -SIN(c!)
  731.     PSET (nx%, ny%), c~& '                           draw the point
  732.     c! = c! + stepp!
  733. LOOP UNTIL c! >= en!
  734. IF e% THEN LINE -(cx%, cy%), c~& '                   draw line from center to end radian if needed
  735.  
  736.  
  737. '----------------------------------------------------------------------------------------------------------------------
  738.  

43
Programs / Scrolling LED Sign
« on: August 22, 2018, 02:43:31 am »
I've been going through all my code snippets to organize them. I ran across this one and thought others might like it. It's a very simple method for creating a scrolling sign of any size.

Code: QB64: [Select]
  1. '********************************
  2. '*                              *
  3. '* LED Maker  by  Terry Ritchie *
  4. '*                              *
  5. '********************************
  6.  
  7. CONST ROUND = 0, SQUARE = 1
  8.  
  9. TYPE LED
  10.     Screen AS LONG ' the LED screen to show on screen
  11.     Image AS LONG '  the LED image to work on in the background
  12.     Mask AS LONG '   the LED mask to place over the LED image
  13.  
  14. DIM LED AS LED
  15. DIM News$
  16. DIM Mpos%
  17.  
  18. News$ = "                Breaking News!                QB64.org is awesome! "
  19.  
  20. MAKELED 128, 16, 10, ROUND '                                                   create LED screen
  21. SCREEN LED.Screen '                                                            set LED screen as view screen
  22. _TITLE "LED Scrolling Sign" '                                                  give screen a title
  23. Mpos% = 0 '                                                                    reset message position pointer
  24.     _LIMIT 5 '                                                                 5 frames per second
  25.     _DEST LED.Image '                                                          set small image as destination
  26.     COLOR _RGB32(255, 255, 0) '                                                set text color to yellow
  27.     Mpos% = Mpos% + 1 '                                                        increment message pointer
  28.     IF Mpos% > LEN(News$) THEN Mpos% = 1 '                                     reset pointer at end of message
  29.     LOCATE 1, 1 '                                                              position cursor
  30.     PRINT MID$(News$, Mpos%, 16); '                                            display portion of message
  31.     _DEST 0 '                                                                  set LED screen back to destination
  32.     _PUTIMAGE , LED.Image '                                                    stretch the small image across screen
  33.     _PUTIMAGE , LED.Mask '                                                     place LED mask over image
  34.     _DISPLAY '                                                                 viola', the screen looks pixelized
  35.  
  36. '----------------------------------------------------------------------------------------------------------------------
  37. '                                                                                                               MAKELED
  38. SUB MAKELED (w%, h%, psize%, pshape%)
  39.  
  40. SHARED LED AS LED '  need access to LED screen properties
  41.  
  42. DIM OriginalDest& '  calling routine destination
  43. DIM LEDPixel& '      temporary image to hold single LED pixel
  44.  
  45. OriginalDest& = _DEST '                                                        remember calling routine destination
  46. LED.Screen = _NEWIMAGE(w% * psize%, h% * psize%, 32) '                         create LED screen image holder
  47. LED.Image = _NEWIMAGE(w%, h%, 32) '                                            create LED work image
  48. LED.Mask = _COPYIMAGE(LED.Screen) '                                            create LED matrix image mask
  49. LEDPixel& = _NEWIMAGE(psize%, psize%, 32) '                                    create LED pixel
  50. _DEST LEDPixel& '                                                              set LED pixel as destination image
  51. CLS '                                                                          remove 0,0,0 alpha transparency
  52. LINE (0, 0)-(psize% - 1, psize% - 1), _RGB32(10, 10, 10), BF '                 set background color
  53. SELECT CASE pshape% '                                                          which pixel shape should be created?
  54.     CASE ROUND '                                                               round pixels
  55.         CIRCLE (psize% \ 2, psize% \ 2), psize% \ 2 - 1, _RGB32(0, 0, 2) '     create round pixel in center of image
  56.         PAINT (psize% \ 2, psize% \ 2), _RGB32(0, 0, 1), _RGB32(0, 0, 2) '     fill the pixel in
  57.     CASE SQUARE '                                                              square pixels
  58.         LINE (1, 1)-(psize% - 1, psize% - 1), _RGB32(0, 0, 2), B '            create square pixel in center of image
  59.         LINE (2, 2)-(psize% - 2, psize% - 2), _RGB32(0, 0, 1), BF
  60. _DEST LED.Mask '                                                               set LED mask as destination image
  61. CLS '                                                                          remove 0,0,0 alpha transparency
  62. FOR x% = 0 TO w% * psize% - 1 STEP psize% '                                    cycle through horizontal pixel positions
  63.     FOR y% = 0 TO h% * psize% - 1 STEP psize% '                                cycle through vertical pixel positions
  64.         _PUTIMAGE (x%, y%), LEDPixel& '                                        place a pixel image
  65.     NEXT y%
  66. NEXT x%
  67. FOR x% = 0 TO w% * psize% - 1 STEP psize% * 8 '                                cycle every 8 horizontal pixels
  68.     LINE (x%, 0)-(x%, h% * psize% - 1), _RGB32(0, 0, 0) '                      draw a divider line
  69. NEXT x%
  70. FOR y% = 0 TO h% * psize% - 1 STEP psize% * 8 '                                cycle every 8 vertical pixels
  71.     LINE (0, y%)-(w% * psize% - 1, y%), _RGB32(0, 0, 0) '                      draw a divider line
  72. NEXT y%
  73. _SETALPHA 0, _RGB32(0, 0, 1) '                                                 set transparency color of mask
  74. _SETALPHA 63, _RGB32(0, 0, 2)
  75. _DEST OriginalDest& '                                                          return to calling routine destination
  76. _FREEIMAGE LEDPixel& '                                                         removel pixel image from memory
  77.  
  78.  
  79. '----------------------------------------------------------------------------------------------------------------------
  80.  

44
Programs / Physics Engine
« on: August 21, 2018, 03:23:22 am »
Here's an attempt I made at a physics engine a while back. Move the mouse around inside the window. The program still has a few quirks.

Code: QB64: [Select]
  1. CONST FALSE = 0, TRUE = NOT FALSE
  2. CONST TIMESTEP = 1 / 30 '          total engine updates per second - should match any _LIMIT FPS in program
  3. CONST BALLS = 25
  4. CONST ROUND = 0, SQUARE = 1
  5. CONST SWIDTH = 800
  6. CONST SHEIGHT = 600
  7. CONST FIXED = TRUE
  8. CONST NONFIXED = FALSE
  9.  
  10. TYPE OBJECT
  11.     Inuse AS INTEGER '         is object currently in use (TRUE / FALSE)
  12.     Xpos AS SINGLE '           x position of object
  13.     Ypos AS SINGLE '           y position of object
  14.     Xvel AS SINGLE '           horizontal velocity of object
  15.     Yvel AS SINGLE '           vertical velocity of object
  16.     Radius AS SINGLE '         radius of object
  17.     Gravity AS SINGLE '        object is affected by gravity (0 = no gravity, >0 gravity present)
  18.     Friction AS SINGLE '       object has friction (0 = no friction, >0 friction present, use small increments of .1)
  19.     Attract AS SINGLE '        amount of attraction to another object (0 = no attraction, <0 = repulsion, >0 = attraction)
  20.     AttractedTo AS INTEGER '   handle of object attracted to
  21.     Elastic AS SINGLE '        object has elastic collisions
  22.     Fixed AS INTEGER '         object is in a fixed position (TRUE / FALSE)
  23.     MaxSpeed AS SINGLE '       object's maximum speed
  24.     Shape AS INTEGER '         object's shape (0 for circle, 1 for square)
  25.  
  26. REDIM Object(0) AS OBJECT '    array to hold objects
  27. DIM Ball%(BALLS)
  28. DIM Bcolor~&(BALLS)
  29. DIM Count%
  30. DIM rndRadius!, rndXpos!, rndYpos!, rndXvel!, rndYvel!
  31. DIM Dummy%
  32. DIM Paddle%
  33. DIM OldMouseX%, OldMouseY%
  34.  
  35. SCREEN _NEWIMAGE(SWIDTH, SHEIGHT, 32)
  36.  
  37. FOR Count% = 1 TO BALLS '                                                      create random ball objects
  38.     rndRadius! = INT(RND(1) * 20) + 10
  39.     Bcolor~&(Count%) = _RGB32(INT(RND(1) * 256), INT(RND(1) * 256), INT(RND(1) * 256))
  40.     Ball%(Count%) = DEFINEOBJECT(ROUND, rndRadius!)
  41.     APPLYFRICTION Ball%(Count%), .01
  42.     APPLYMAXSPEED Ball%(Count%), 100
  43.     APPLYELASTIC Ball%(Count%), 1
  44.     rndXpos! = INT(RND(1) * (SWIDTH - 1 - OBJECTRADIUS(Ball%(Count%)) * 2)) + OBJECTRADIUS(Ball%(Count%))
  45.     rndYpos! = INT(RND(1) * (SHEIGHT - 1 - OBJECTRADIUS(Ball%(Count%)) * 2)) + OBJECTRADIUS(Ball%(Count%))
  46.     rndXvel! = (RND(1) - RND(1)) '* 3
  47.     rndYvel! = (RND(1) - RND(1)) '* 3
  48.     PUTOBJECT Ball%(Count%), rndXpos!, rndYpos!, rndXvel!, rndYvel!, NONFIXED ' define where ball resides
  49. NEXT Count%
  50.  
  51. Paddle% = DEFINEOBJECT(ROUND, 40) '                                            create a fixed ball with radius of 40
  52. APPLYELASTIC Paddle%, .1 '                                                     give a slightly bouncy surface
  53. PUTOBJECT Paddle%, SWIDTH / 2 - 1, SHEIGHT / 2 - 1, 0, 0, FIXED '              define where object resides
  54. _MOUSEMOVE SWIDTH / 2 - 1, SHEIGHT / 2 - 1
  55.  
  56.     _LIMIT 30 ' we limit simulation to 30FPS - note that TIMESTEP constant should match this to avoid tunneling through objects
  57.     CLS
  58.     WHILE _MOUSEINPUT: WEND '                                                  get latest mouse information
  59.     SETOBJECTX Paddle%, _MOUSEX '                                              set paddle object X location
  60.     SETOBJECTY Paddle%, _MOUSEY '                                              set paddle object Y location
  61.     SETOBJECTXVEL Paddle%, OBJECTX(Paddle%) - OldMouseX% '                     set paddle object X velocity
  62.     SETOBJECTYVEL Paddle%, OBJECTY(Paddle%) - OldMouseY% '                     set paddle object Y velocity
  63.     OldMouseX% = OBJECTX(Paddle%) '                                            remember paddle X position
  64.     OldMouseY% = OBJECTY(Paddle%) '                                            remember paddle Y location
  65.     FOR Count% = 1 TO BALLS '
  66.         Dummy% = INTERACTION(Ball%(Count%)) '                                  check this ball's interaction with all other objects
  67.         IF OBJECTX(Ball%(Count%)) < OBJECTRADIUS(Ball%(Count%)) THEN '         keep balls constrained to screen
  68.             SETOBJECTXVEL Ball%(Count%), -OBJECTXVEL(Ball%(Count%))
  69.             SETOBJECTX Ball%(Count%), OBJECTRADIUS(Ball%(Count%))
  70.         END IF
  71.         IF OBJECTX(Ball%(Count%)) > SWIDTH - OBJECTRADIUS(Ball%(Count%)) THEN
  72.             SETOBJECTXVEL Ball%(Count%), -OBJECTXVEL(Ball%(Count%))
  73.             SETOBJECTX Ball%(Count%), SWIDTH - OBJECTRADIUS(Ball%(Count%))
  74.         END IF
  75.         IF OBJECTY(Ball%(Count%)) < OBJECTRADIUS(Ball%(Count%)) THEN
  76.             SETOBJECTYVEL Ball%(Count%), -OBJECTYVEL(Ball%(Count%))
  77.             SETOBJECTY Ball%(Count%), OBJECTRADIUS(Ball%(Count%))
  78.         END IF
  79.         IF OBJECTY(Ball%(Count%)) > SHEIGHT - OBJECTRADIUS(Ball%(Count%)) THEN
  80.             SETOBJECTYVEL Ball%(Count%), -OBJECTYVEL(Ball%(Count%))
  81.             SETOBJECTY Ball%(Count%), SHEIGHT - OBJECTRADIUS(Ball%(Count%))
  82.         END IF
  83.         CIRCLE (OBJECTX(Ball%(Count%)), OBJECTY(Ball%(Count%))), OBJECTRADIUS(Ball%(Count%)), Bcolor~&(Count%)
  84.         PAINT (OBJECTX(Ball%(Count%)), OBJECTY(Ball%(Count%))), Bcolor~&(Count%), Bcolor~&(Count%)
  85.     NEXT Count%
  86.     CIRCLE (OBJECTX(Paddle%), OBJECTY(Paddle%)), OBJECTRADIUS(Paddle%), _RGB32(255, 255, 255)
  87.     PAINT (OBJECTX(Paddle%), OBJECTY(Paddle%)), _RGB32(255, 255, 255), _RGB32(255, 255, 255)
  88.     _DISPLAY
  89.  
  90. '------------------------------------------------------------------------------
  91.  
  92. FUNCTION OBJECTYVEL (Handle%)
  93.  
  94. '**
  95. '** returns the Y velocity of an object
  96. '**
  97.  
  98. SHARED Object() AS OBJECT
  99.  
  100. OBJECTYVEL = Object(Handle%).Yvel
  101.  
  102.  
  103. '------------------------------------------------------------------------------
  104.  
  105. SUB SETOBJECTY (Handle%, Ypos!)
  106.  
  107. '**
  108. '** returns the Y location of an object
  109. '**
  110.  
  111. SHARED Object() AS OBJECT
  112.  
  113. Object(Handle%).Ypos = Ypos!
  114.  
  115.  
  116. '------------------------------------------------------------------------------
  117.  
  118. SUB SETOBJECTYVEL (Handle%, Yvel!)
  119.  
  120. '**
  121. '** sets the Y velocity of an object
  122. '**
  123.  
  124. SHARED Object() AS OBJECT
  125.  
  126. Object(Handle%).Yvel = Yvel!
  127.  
  128.  
  129. '------------------------------------------------------------------------------
  130.  
  131. SUB SETOBJECTX (Handle%, Xpos!)
  132.  
  133. '**
  134. '** sets the X location of an object
  135. '**
  136.  
  137. SHARED Object() AS OBJECT
  138.  
  139. Object(Handle%).Xpos = Xpos!
  140.  
  141.  
  142. '------------------------------------------------------------------------------
  143.  
  144. FUNCTION OBJECTXVEL (Handle%)
  145.  
  146. '**
  147. '** returns the X velocity of an object
  148. '**
  149.  
  150. SHARED Object() AS OBJECT
  151.  
  152. OBJECTXVEL = Object(Handle%).Xvel
  153.  
  154.  
  155. '------------------------------------------------------------------------------
  156.  
  157. SUB SETOBJECTXVEL (Handle%, Xvel!)
  158.  
  159. '**
  160. '** sets the X velocity of an object
  161. '**
  162.  
  163. SHARED Object() AS OBJECT
  164.  
  165. Object(Handle%).Xvel = Xvel!
  166.  
  167.  
  168. '------------------------------------------------------------------------------
  169.  
  170. FUNCTION DEFINEOBJECT (Shape%, Radius!)
  171.  
  172. '**
  173. '** defines an object (very basic, not finished yet)
  174. '**
  175.  
  176. SHARED Object() AS OBJECT
  177.  
  178. DIM ob%
  179.  
  180. ob% = UBOUND(Object) + 1
  181. REDIM _PRESERVE Object(ob%) AS OBJECT
  182.  
  183. Object(ob%).Inuse = -1
  184. Object(ob%).Xpos = 0
  185. Object(ob%).Ypos = 0
  186. Object(ob%).Xvel = 0
  187. Object(ob%).Yvel = 0
  188. Object(ob%).Radius = Radius!
  189. Object(ob%).Gravity = 0
  190. Object(ob%).Friction = 0
  191. Object(ob%).Attract = 0
  192. Object(ob%).AttractedTo = 0
  193. Object(ob%).Elastic = 1
  194. Object(ob%).Fixed = 0
  195. Object(ob%).MaxSpeed = 100
  196. Object(ob%).Shape = Shape%
  197.  
  198. DEFINEOBJECT = ob%
  199.  
  200.  
  201. '------------------------------------------------------------------------------
  202.  
  203. FUNCTION OBJECTRADIUS (Handle%)
  204.  
  205. '**
  206. '** returns the radius of an object
  207. '**
  208.  
  209. SHARED Object() AS OBJECT
  210.  
  211. OBJECTRADIUS = Object(Handle%).Radius
  212.  
  213.  
  214. '------------------------------------------------------------------------------
  215.  
  216. FUNCTION OBJECTY (Handle%)
  217.  
  218. '**
  219. '** returns the Y location of an object
  220. '**
  221.  
  222. SHARED Object() AS OBJECT
  223.  
  224. OBJECTY = Object(Handle%).Ypos
  225.  
  226.  
  227. '------------------------------------------------------------------------------
  228.  
  229. FUNCTION OBJECTX (Handle%)
  230.  
  231. '**
  232. '** returns the X location of an object
  233. '**
  234.  
  235. SHARED Object() AS OBJECT
  236.  
  237. OBJECTX = Object(Handle%).Xpos
  238.  
  239.  
  240. '------------------------------------------------------------------------------
  241.  
  242. SUB APPLYMAXSPEED (Handle%, Maxspeed!)
  243.  
  244. '**
  245. '** sets the maximum speed of an object (setting too low causes 45 degree movement, need to investigate)
  246. '**
  247.  
  248. SHARED Object() AS OBJECT
  249.  
  250. Object(Handle%).MaxSpeed = Maxspeed!
  251.  
  252.  
  253. '------------------------------------------------------------------------------
  254.  
  255. SUB APPLYELASTIC (Handle%, Elastic!)
  256.  
  257. '**
  258. '** sets the elastic property of an object (setting too low allows tunneling, need to investigate)
  259. '**
  260.  
  261. SHARED Object() AS OBJECT
  262.  
  263. Object(Handle%).Elastic = Elastic!
  264.  
  265.  
  266. '------------------------------------------------------------------------------
  267.  
  268. SUB APPLYATTRACTION (Handle%, HandleTo%, Attract!)
  269.  
  270. '**
  271. '** sets the attration to another object
  272. '**
  273.  
  274. SHARED Object() AS OBJECT
  275.  
  276. Object(Handle%).Attract = Attract!
  277. Object(Handle%).AttractedTo = HandleTo%
  278.  
  279.  
  280. '------------------------------------------------------------------------------
  281.  
  282. SUB APPLYFRICTION (Handle%, Friction!)
  283.  
  284. '**
  285. '** sets the friction amount for an object
  286. '**
  287.  
  288. SHARED Object() AS OBJECT
  289.  
  290. Object(Handle%).Friction = Friction!
  291.  
  292.  
  293. '------------------------------------------------------------------------------
  294.  
  295. SUB APPLYGRAVITY (Handle%, Gravity!)
  296.  
  297. '**
  298. '** sets the amount of gravity on an object
  299. '**
  300.  
  301. SHARED Object() AS OBJECT
  302.  
  303. Object(Handle%).Gravity = Gravity!
  304.  
  305.  
  306. '------------------------------------------------------------------------------
  307.  
  308. SUB PUTOBJECT (Handle%, Xpos!, Ypos!, Xvel!, Yvel!, Fixed%)
  309.  
  310. '**
  311. '** defines where object resides
  312. '**
  313.  
  314. SHARED Object() AS OBJECT
  315.  
  316. Object(Handle%).Xpos = Xpos!
  317. Object(Handle%).Ypos = Ypos!
  318. Object(Handle%).Xvel = Xvel!
  319. Object(Handle%).Yvel = Yvel!
  320. Object(Handle%).Fixed = Fixed%
  321.  
  322.  
  323. '------------------------------------------------------------------------------
  324.  
  325. FUNCTION INTERACTION (H1%)
  326.  
  327. '**
  328. '** Checks the interaction between objects for a collision then calculates
  329. '** the new object position based on those calculations.
  330. '**
  331. '** H1% - handle of object to test for collision
  332. '**
  333. '** Returns: 0 (FALSE) if no collision occured
  334. '**         >0 the object that was collided with
  335. '**
  336. '** Function also updates gravity, friction and repulsion/attraction between the two objects.
  337. '**
  338. '** Note: this function is far from complete. Variables need to be updated with variables names and
  339. '**       types identifiers that make sense.
  340. '**
  341.  
  342.  
  343. SHARED Object() AS OBJECT
  344.  
  345. DIM Diameter! '                                   the radius of object 1 plus the radius of object 2
  346. DIM Distance! '                                   the distance from the center point of object 1 to the center point of object 2
  347. DIM FrictionScale! '                              amount of frictional force to add to an object
  348. DIM Xdifference! '                                the distance between object 1 X position and object 2 X position
  349. DIM Ydifference! '                                the distance between object 1 Y position and onject 2 Y position
  350. DIM H1Xvel!, H1Yvel!, H1Xpos!, H1Ypos! '          object 1's X and Y velocities and X and Y positions
  351. DIM H2Xvel!, H2Yvel!, H2Xpos!, H2Ypos! '          object 2's X and Y velocities and X and Y positions
  352. DIM cH1Xvel!, cH1Yvel!, cH1Xpos!, cH1Ypos! '      object 1's X and Y velocities and X and Y positions
  353. DIM cH2Xvel!, cH2Yvel!, cH2Xpos!, cH2Ypos! '      object 2's X and Y velocities and X and Y positions
  354. DIM CoefA!, CoefB!, CoefC! '                      object collision time coefficients
  355. DIM TouchTime! '                                  actual time when object's touched
  356. DIM MomentumX!, MomentumY! '                      momentum loss of objects when collision occurred
  357. DIM OB! '                                         center line velocity vector
  358. DIM Elastic! '                                    amount of elasticity applied to objects
  359.  
  360. IF Object(H1%).Fixed THEN EXIT FUNCTION '                                                if object is in a fixed position no need to continue
  361.  
  362. FOR H2% = 1 TO UBOUND(Object) '                                                          cycle through all defined objects
  363.     IF (H2% <> H1%) AND Object(H2%).Inuse THEN '                                         object can't check itself or objects not in use
  364.  
  365.         diam = Object(H1%).Radius + Object(H2%).Radius '                                 calculate the length of both object radii
  366.  
  367.         '** update object position
  368.  
  369.         u = MIN(Object(H1%).MaxSpeed, MAX(Object(H1%).Xvel, -Object(H1%).MaxSpeed)) '    set maximum X velocity of object if needed
  370.         v = MIN(Object(H1%).MaxSpeed, MAX(Object(H1%).Yvel, -Object(H1%).MaxSpeed)) '    set maximum Y velocity of object if needed
  371.         x = Object(H1%).Xpos + TIMESTEP * u '                                            update object's X position
  372.         y = Object(H1%).Ypos + TIMESTEP * v '                                            update object's Y position
  373.  
  374.         ' ** Gravity and Friction
  375.  
  376.         u = Object(H1%).Xvel '                                                           get object's X velocity
  377.         v = Object(H1%).Yvel '                                                           get object's Y velocity
  378.         fricscale = 1 - Object(H1%).Friction / SQR(1 + u ^ 2 + v ^ 2) '                  calculate the amount of friction needed (if any)
  379.         Object(H1%).Xvel = fricscale * u '                                               apply friction amount to object's X velocity
  380.         Object(H1%).Yvel = fricscale * v + Object(H1%).Gravity '                         apply friction and gravity amounts tp object's Y velocity
  381.  
  382.         '** check for collision
  383.  
  384.         xi = x '                                                                         copy object's updated X position
  385.         yi = y '                                                                         copy object's updated Y position
  386.         xj = Object(H2%).Xpos '                                                          get 2nd object's X position
  387.         yj = Object(H2%).Ypos '                                                          get 2nd object's Y position
  388.         dx = xi - xj '                                                                   calculate X distance between objects
  389.         dy = yi - yj '                                                                   calculate Y distance between objetcs
  390.         dist = SQR(dx ^ 2 + dy ^ 2) '                                                    calculate center to center distance between objects
  391.         IF dist < diam THEN '                                                            is center to center distance less than diameter?
  392.             INTERACTION = H2% '                                                          yes, return object that was collided with
  393.  
  394.             '** get object vectors
  395.  
  396.             ui = Object(H1%).Xvel '                                                      get object's X velocity
  397.             vi = Object(H1%).Yvel '                                                      get object's Y velocity
  398.             uj = Object(H2%).Xvel '                                                      get 2nd object's X velocity
  399.             vj = Object(H2%).Yvel '                                                      get 2nd object's Y velocity
  400.  
  401.             '** move backwards in time until the two objects are just touching
  402.  
  403.             CoefA = (ui - uj) ^ 2 + (vi - vj) ^ 2 '                                      calculate time coefficiants of actual objects touching
  404.             CoefB = 2 * ((ui - uj) * (xi - xj) + (vi - vj) * (yi - yj))
  405.             CoefC = (xi - xj) ^ 2 + (yi - yj) ^ 2 - diam ^ 2
  406.             IF CoefA = 0 THEN
  407.                 t = -CoefC / CoefB
  408.             ELSE
  409.                 IF TIMESTEP >= 0 THEN
  410.                     t = (-CoefB - SQR(CoefB ^ 2 - 4 * CoefA * CoefC)) / (2 * CoefA)
  411.                 ELSE
  412.                     t = (-CoefB + SQR(CoefB ^ 2 - 4 * CoefA * CoefC)) / (2 * CoefA)
  413.                 END IF
  414.             END IF
  415.             xi = xi + t * ui '                                                           move object's X location to this point in time
  416.             yi = yi + t * vi '                                                           move object's Y location to this point in time
  417.             xj = xj + t * uj '                                                           move 2nd object's X location to this point in time
  418.             yj = yj + t * vj '                                                           move 2nd object's Y location to this point in time
  419.  
  420.             '** center of momentum coordinates
  421.  
  422.             mx = (ui + uj) / 2 '                                                         calculate horizontal loss of momentum between objects
  423.             my = (vi + vj) / 2 '                                                         calculate vertical loss of momentum between objects
  424.             ui = ui - mx '                                                               update object's X velocity based on momentum loss
  425.             vi = vi - my '                                                               update object's Y velocity based on momentum loss
  426.             uj = uj - mx '                                                               update 2nd object's X velocity based on momentum loss
  427.             vj = vj - my '                                                               update 2nd object's Y velocity based on momentum loss
  428.  
  429.             '** new center to center line
  430.  
  431.             dx = xi - xj '                                                               calculate X distance between objects
  432.             dy = yi - yj '                                                               calculate Y distance between objects
  433.             dist = SQR(dx ^ 2 + dy ^ 2) '                                                calculate center to center distance between objects
  434.             dx = dx / dist '
  435.             dy = dy / dist
  436.  
  437.             '** reflect object veolcity vectors in center to center line
  438.  
  439.             OB = -(dx * ui + dy * vi)
  440.             ui = ui + 2 * OB * dx
  441.             vi = vi + 2 * OB * dy
  442.             OB = -(dx * uj + dy * vj)
  443.             uj = uj + 2 * OB * dx
  444.             vj = vj + 2 * OB * dy
  445.  
  446.             '** back to moving coordinates with elastic velocity change
  447.  
  448.             e = SQR(Object(H1%).Elastic)
  449.             ui = e * (ui + mx)
  450.             vi = e * (vi + my)
  451.             uj = e * (uj + mx)
  452.             vj = e * (vj + my)
  453.  
  454.             '** move to new bounced position
  455.  
  456.             xi = xi - t * ui
  457.             yi = yi - t * vi
  458.             xj = xj - t * uj
  459.             yj = yj - t * vj
  460.  
  461.             '** set object velocities
  462.  
  463.             Object(H1%).Xvel = ui
  464.             Object(H1%).Yvel = vi
  465.  
  466.             '** set 2nd object velocities and position if allowed to respond to first object
  467.  
  468.             IF NOT Object(H2%).Fixed THEN
  469.                 Object(H2%).Xvel = uj
  470.                 Object(H2%).Yvel = vj
  471.                 Object(H2%).Xpos = xj
  472.                 Object(H2%).Ypos = yj
  473.             END IF
  474.  
  475.             '** set object position
  476.  
  477.             x = xi
  478.             y = yi
  479.         END IF
  480.  
  481.         '** attrack/repel the two objects to/against each other
  482.  
  483.         IF (Object(H1%).Attract <> 0) AND (Object(H1%).AttractedTo = H2%) THEN
  484.             xm = Object(H2%).Xpos - x
  485.             ym = Object(H2%).Ypos - y
  486.             dist = xm ^ 2 + ym ^ 2
  487.             dist = MAX(dist, Object(H1%).Radius ^ 2)
  488.             Object(H1%).Xvel = Object(H1%).Attract * xm / dist + Object(H1%).Xvel
  489.             Object(H1%).Yvel = Object(H1%).Attract * ym / dist + Object(H1%).Yvel
  490.             Object(H2%).Xvel = Object(H1%).Attract * xm / dist + Object(H2%).Xvel
  491.             Object(H2%).Yvel = -Object(H1%).Attract * ym / dist + Object(H2%).Yvel
  492.         END IF
  493.  
  494.         '** save position of object
  495.  
  496.         Object(H1%).Xpos = x
  497.         Object(H1%).Ypos = y
  498.  
  499.     END IF
  500. NEXT H2%
  501.  
  502.  
  503. '------------------------------------------------------------------------------
  504.  
  505. FUNCTION MIN (Num1!, Num2!)
  506.  
  507. '**
  508. '** returns the smallest number passed in
  509. '**
  510.  
  511. IF Num1! < Num2! THEN
  512.     MIN = Num1!
  513.     MIN = Num2!
  514.  
  515.  
  516. '------------------------------------------------------------------------------
  517.  
  518. FUNCTION MAX (Num1!, Num2!)
  519.  
  520. '**
  521. '** returns the largest number passed in
  522. '**
  523.  
  524. IF Num1! > Num2! THEN
  525.     MAX = Num1!
  526.     MAX = Num2!
  527.  
  528.  

Here is a simplified version of it with the source of the idea cited in the code.

Code: QB64: [Select]
  1. 'Most of the math in this code was realized from the following source:
  2. 'http://smallbasic.com/program/?PMT149
  3.  
  4. CONST FALSE = 0, TRUE = NOT FALSE
  5. CONST SWIDTH = 800, SHEIGHT = 600
  6. CONST GRAVITY = 0 '   puck feels the affect of gravity. Higher numbers equal more gravity
  7. CONST FRICTION = 0 '  puck had added friction. Use small increments of .1
  8. CONST FOLLOW = 0
  9. CONST ATTRACT = 0 '   puck is attracted to paddle. Higher numbers equal more attraction
  10. CONST TIMESTEP = 1
  11. CONST SHAPE = 0
  12. CONST ELASTIC = 1
  13.  
  14. TYPE OBJECT
  15.     Xpos AS SINGLE
  16.     Ypos AS SINGLE
  17.     Xvel AS SINGLE
  18.     Yvel AS SINGLE
  19.     Radius AS INTEGER
  20.  
  21. DIM Puck AS OBJECT
  22. DIM Paddle AS OBJECT
  23. DIM OldXpos!
  24. DIM OldYpos!
  25.  
  26. SCREEN _NEWIMAGE(SWIDTH, SHEIGHT, 32)
  27. Puck.Xpos = SWIDTH \ 2 - 1
  28. Puck.Ypos = SHEIGHT \ 2 - 1
  29. Puck.Xvel = 0
  30. Puck.Yvel = 0
  31. Puck.Radius = 20
  32. Paddle.Xpos = SWIDTH \ 2 - 1
  33. Paddle.Ypos = SHEIGHT - SHEIGHT \ 4
  34. Paddle.Xvel = 0
  35. Paddle.Yvel = 0
  36. Paddle.Radius = 40
  37. _MOUSEMOVE Paddle.Xpos, Paddle.Ypos
  38.  
  39. diam = Paddle.Radius + Puck.Radius
  40.  
  41.     _LIMIT 60
  42.     CLS
  43.  
  44.     '** get paddle position based on mouse position
  45.  
  46.     Paddle.Xpos = _MOUSEX
  47.     Paddle.Ypos = _MOUSEY
  48.  
  49.     '** calculate paddle velocities based on movement from last position
  50.  
  51.     Paddle.Xvel = Paddle.Xpos - OldXpos!
  52.     Paddle.Yvel = Paddle.Ypos - OldYpos!
  53.     OldXpos! = Paddle.Xpos
  54.     OldYpos! = Paddle.Ypos
  55.  
  56.     '** update puck position
  57.  
  58.     u = MIN(100, MAX(Puck.Xvel, -100))
  59.     v = MIN(100, MAX(Puck.Yvel, -100))
  60.     x = Puck.Xpos + TIMESTEP * u
  61.     y = Puck.Ypos + TIMESTEP * v
  62.     IF x < Puck.Radius THEN
  63.         Puck.Xvel = -Puck.Xvel
  64.         x = Puck.Radius
  65.     END IF
  66.  
  67.     '** check for edge bounces
  68.  
  69.     IF x > SWIDTH - Puck.Radius THEN
  70.         Puck.Xvel = -Puck.Xvel
  71.         x = SWIDTH - Puck.Radius
  72.     END IF
  73.     IF y < Puck.Radius THEN
  74.         Puck.Yvel = -Puck.Yvel
  75.         y = Puck.Radius
  76.     END IF
  77.     IF y > SHEIGHT - Puck.Radius THEN
  78.         Puck.Yvel = -Puck.Yvel
  79.         y = SHEIGHT - Puck.Radius
  80.     END IF
  81.  
  82.     ' ** Gravity, Friction and Follow paddle
  83.  
  84.     xm = Paddle.Xpos - x
  85.     ym = Paddle.Ypos - y
  86.     dist = xm ^ 2 + ym ^ 2
  87.     dist = MAX(dist, Puck.Radius * Puck.Radius)
  88.     'dist = dist * SQR(dist)
  89.     u = Puck.Xvel
  90.     v = Puck.Yvel
  91.     fricscale = 1 - FRICTION / SQR(1 + u ^ 2 + v ^ 2)
  92.     Puck.Xvel = FOLLOW * xm / dist + fricscale * u
  93.     Puck.Yvel = FOLLOW * ym / dist + fricscale * v + GRAVITY
  94.  
  95.     '** check for collision
  96.  
  97.     xi = x
  98.     yi = y
  99.     xj = Paddle.Xpos
  100.     yj = Paddle.Ypos
  101.     dx = xi - xj
  102.     dy = yi - yj
  103.     dist = SQR(dx ^ 2 + dy ^ 2)
  104.     IF dist < diam THEN
  105.         iscollision = TRUE
  106.  
  107.         '** get puck vectors
  108.  
  109.         ui = Puck.Xvel
  110.         vi = Puck.Yvel
  111.         uj = Paddle.Xvel
  112.         vj = Paddle.Yvel
  113.  
  114.         '** move backwards (forwards if TIMESTEP < 0) in time until puck and paddle are just touching
  115.  
  116.         coefa = (ui - uj) ^ 2 + (vi - vj) ^ 2
  117.         coefb = 2 * ((ui - uj) * (xi - xj) + (vi - vj) * (yi - yj))
  118.         coefc = (xi - xj) ^ 2 + (yi - yj) ^ 2 - diam ^ 2
  119.         IF coefa = 0 THEN
  120.             t = -coefc / coefb
  121.         ELSE
  122.             IF TIMESTEP >= 0 THEN
  123.                 t = (-coefb - SQR(coefb ^ 2 - 4 * coefa * coefc)) / (2 * coefa)
  124.             ELSE
  125.                 t = (-coefb + SQR(coefb ^ 2 - 4 * coefa * coefc)) / (2 * coefa)
  126.             END IF
  127.         END IF
  128.         xi = xi + t * ui
  129.         yi = yi + t * vi
  130.         xj = xj + t * uj
  131.         yj = yj + t * vj
  132.  
  133.         '** center of momentum coordinates
  134.  
  135.         mx = (ui + uj) / 2
  136.         my = (vi + vj) / 2
  137.         ui = ui - mx
  138.         vi = vi - my
  139.         uj = uj - mx
  140.         vj = vj - my
  141.  
  142.         '** new center to center line
  143.  
  144.         dx = xi - xj
  145.         dy = yi - yj
  146.         dist = SQR(dx ^ 2 + dy ^ 2)
  147.         dx = dx / dist
  148.         dy = dy / dist
  149.  
  150.         '** reflect puck veolcity vectors in center to center line
  151.  
  152.         OB = -(dx * ui + dy * vi)
  153.         ui = ui + 2 * OB * dx
  154.         vi = vi + 2 * OB * dy
  155.         OB = -(dx * uj + dy * vj)
  156.         uj = uj + 2 * OB * dx
  157.         vj = vj + 2 * OB * dy
  158.  
  159.         '** back to moving coordinates with elastic velocity change
  160.  
  161.         e = SQR(ELASTIC)
  162.         ui = e * (ui + mx)
  163.         vi = e * (vi + my)
  164.         uj = e * (uj + mx)
  165.         vj = e * (vj + my)
  166.  
  167.         '** move to new bounced position
  168.  
  169.         xi = xi - t * ui
  170.         yi = yi - t * vi
  171.         xj = xj - t * uj
  172.         yj = yj - t * vj
  173.  
  174.         '** set puck velocities
  175.  
  176.         Puck.Xvel = ui
  177.         Puck.Yvel = vi
  178.  
  179.         '** set paddle velocities and position if allowed to respond to puck
  180.  
  181.         'Paddle.Xvel = uj
  182.         'Paddle.Yvel = vj
  183.         'Paddle.Xpos = xj
  184.         'Paddle.Ypos = yj
  185.  
  186.         '** set puck position
  187.  
  188.         x = xi
  189.         y = yi
  190.     END IF
  191.  
  192.     '** attrack/repel puck and paddle to each other
  193.  
  194.     IF ATTRACT <> 0 THEN
  195.         xm = Paddle.Xpos - x
  196.         ym = Paddle.Ypos - y
  197.         dist = xm ^ 2 + ym ^ 2
  198.         dist = MAX(dist, Puck.Radius ^ 2) ' *******  may be wrong?
  199.         'dist = dist * SQR(dist)
  200.         Puck.Xvel = ATTRACT * xm / dist + Puck.Xvel
  201.         Puck.Yvel = ATTRACT * ym / dist + Puck.Yvel
  202.         Paddle.Xvel = ATTRACT * xm / dist + Paddle.Xvel
  203.         Paddle.Yvel = -ATTRACT * ym / dist + Paddle.Yvel
  204.     END IF
  205.  
  206.     '** save position of puck
  207.  
  208.     Puck.Xpos = x
  209.     Puck.Ypos = y
  210.  
  211.     '** draw puck and paddle
  212.  
  213.     CIRCLE (x, y), Puck.Radius, _RGB32(127, 127, 127)
  214.     CIRCLE (Paddle.Xpos, Paddle.Ypos), Paddle.Radius, _RGB32(255, 255, 255)
  215.  
  216.     '** draw right angle between puck and paddle
  217.  
  218.     'LINE (Paddle.Xpos, Paddle.Ypos)-(Puck.Xpos, Puck.Ypos), _RGB32(64, 64, 64)
  219.     'LINE -(Puck.Xpos, Paddle.Ypos), _RGB32(64, 64, 64)
  220.     'LINE -(Paddle.Xpos, Paddle.Ypos), _RGB32(64, 64, 64)
  221.     'LINE (Puck.Xpos, Paddle.Ypos)-(Puck.Xpos + (SGN(Paddle.Xpos - Puck.Xpos) * 10), Paddle.Ypos + (SGN(Puck.Ypos - Paddle.Ypos) * 10)), _RGB32(64, 64, 64), B
  222.  
  223.     '** play collision sound
  224.  
  225.     'IF iscollision THEN
  226.     'play sound here
  227.     'END IF
  228.  
  229.     '** update the display with changes
  230.  
  231.     _DISPLAY
  232.  
  233.  
  234. '------------------------------------------------------------------------------
  235.  
  236. FUNCTION MIN (Num1!, Num2!)
  237.  
  238. IF Num1! < Num2! THEN
  239.     MIN = Num1!
  240.     MIN = Num2!
  241.  
  242.  
  243. '------------------------------------------------------------------------------
  244.  
  245. FUNCTION MAX (Num1!, Num2!)
  246.  
  247. IF Num1! > Num2! THEN
  248.     MAX = Num1!
  249.     MAX = Num2!
  250.  
  251.  

45
Programs / Spark Generator
« on: August 21, 2018, 03:16:37 am »
Here's a little spark generator I created years ago. Press any key and see some sparks. Hold a key down for spark mania!

Code: QB64: [Select]
  1. CONST FALSE = 0, TRUE = NOT FALSE
  2.  
  3. TYPE SPARK
  4.     count AS INTEGER
  5.     x AS SINGLE
  6.     y AS SINGLE
  7.     xdir AS SINGLE
  8.     ydir AS SINGLE
  9.     speed AS SINGLE
  10.     fade AS INTEGER
  11.  
  12. REDIM sparks(0) AS SPARK
  13.  
  14. SCREEN _NEWIMAGE(1024, 768, 32)
  15.  
  16.     keypress$ = INKEY$
  17.     _LIMIT 32
  18.     CLS
  19.     IF keypress$ = " " THEN MakeSparks INT(RND(1) * 1024), INT(RND(1) * 768)
  20.     UpdateSparks
  21.     _DISPLAY
  22. LOOP UNTIL keypress$ = CHR$(27)
  23.  
  24. '------------------------------
  25.  
  26. SUB MakeSparks (x%, y%)
  27.  
  28. SHARED sparks() AS SPARK
  29.  
  30. DIM cleanup%, count%, topspark%
  31.  
  32. cleanup% = TRUE
  33. FOR count% = 1 TO UBOUND(sparks)
  34.     IF sparks(count%).count <> 0 THEN
  35.         cleanup% = FALSE
  36.         EXIT FOR
  37.     END IF
  38. NEXT count%
  39. IF cleanup% THEN REDIM sparks(0) AS SPARK
  40. topspark% = UBOUND(sparks)
  41. REDIM _PRESERVE sparks(topspark% + 11) AS SPARK
  42. FOR count% = 1 TO 10
  43.     sparks(topspark% + count%).count = 32
  44.     sparks(topspark% + count%).x = x%
  45.     sparks(topspark% + count%).y = y%
  46.     sparks(topspark% + count%).fade = 255
  47.     sparks(topspark% + count%).speed = INT(RND(1) * 6) + 6
  48.     sparks(topspark% + count%).xdir = RND(1) - RND(1)
  49.     sparks(topspark% + count%).ydir = RND(1) - RND(1)
  50. NEXT count%
  51.  
  52.  
  53. '--------------------------------------
  54.  
  55. SUB UpdateSparks ()
  56.  
  57. SHARED sparks() AS SPARK
  58.  
  59. DIM count%, fade1%, fade2%
  60.  
  61. FOR count% = 1 TO UBOUND(sparks)
  62.     IF sparks(count%).count > 0 THEN
  63.         fade1% = sparks(count%).fade / 2
  64.         fade2% = sparks(count%).fade / 4
  65.         PSET (sparks(count%).x, sparks(count%).y), _RGB(sparks(count%).fade, sparks(count%).fade, sparks(count%).fade)
  66.         PSET (sparks(count%).x + 1, sparks(count%).y), _RGB(fade1%, fade1%, fade1%)
  67.         PSET (sparks(count%).x - 1, sparks(count%).y), _RGB(fade1%, fade1%, fade1%)
  68.         PSET (sparks(count%).x, sparks(count%).y + 1), _RGB(fade1%, fade1%, fade1%)
  69.         PSET (sparks(count%).x, sparks(count%).y - 1), _RGB(fade1%, fade1%, fade1%)
  70.         PSET (sparks(count%).x + 1, sparks(count%).y + 1), _RGB(fade2%, fade2%, fade2%)
  71.         PSET (sparks(count%).x - 1, sparks(count%).y - 1), _RGB(fade2%, fade2%, fade2%)
  72.         PSET (sparks(count%).x - 1, sparks(count%).y + 1), _RGB(fade2%, fade2%, fade2%)
  73.         PSET (sparks(count%).x + 1, sparks(count%).y - 1), _RGB(fade2%, fade2%, fade2%)
  74.         sparks(count%).fade = sparks(count%).fade - 8
  75.         sparks(count%).x = sparks(count%).x + sparks(count%).xdir * sparks(count%).speed
  76.         sparks(count%).y = sparks(count%).y + sparks(count%).ydir * sparks(count%).speed
  77.         sparks(count%).speed = sparks(count%).speed / 1.1
  78.         sparks(count%).count = sparks(count%).count - 1
  79.     END IF
  80. NEXT count%
  81.  
  82.  

Pages: 1 2 [3] 4