Author Topic: Hocus Pocus  (Read 4386 times)

0 Members and 1 Guest are viewing this topic.

Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
    • View Profile
Hocus Pocus
« on: May 07, 2020, 10:41:42 am »
While updating the tutorials I ran across this little gem called Hocus Pocus that I created to highlight color use in QB64.

You can change the CONST values at the beginning of the program to change the behavior of the color blooms. You'll also need the sound file attached.

Move the mouse around to make the magic happen.

Code: QB64: [Select]
  1. '*
  2. '* Hocus Pocus V2.2 by Terry Ritchie 01/24/14
  3. '*
  4. '* Use the mouse to create magic. Press ESC to leave this magical place.
  5. '*
  6.  
  7. '--------------------------------
  8. '- Variable Declaration Section -
  9. '--------------------------------
  10.  
  11. CONST FALSE = 0, TRUE = NOT FALSE
  12.  
  13. CONST SWIDTH = 640 '       screen width
  14. CONST SHEIGHT = 480 '      screen height
  15. CONST BLOOMAMOUNT = 5 '    number of blooms per mouse movement (don't go too high!)
  16. CONST MAXSIZE = 64 '       maximum size of blooms (don't go too high!)
  17. CONST MAXLIFE = 32 '       maximum life time on screen
  18. CONST MAXXSPEED = 6 '      maximum horizontal speed at bloom creation
  19. CONST MAXYSPEED = 10 '     maximum vertical speed at bloom creation
  20. CONST BOUNCE = FALSE '     set to TRUE to have blooms bounce off bottom of screen
  21.  
  22. TYPE CADABRA '             image properties
  23.     lifespan AS INTEGER '  life span of bloom on screen
  24.     x AS SINGLE '          x location of bloom
  25.     y AS SINGLE '          y location of bloom
  26.     size AS INTEGER '      size of bloom
  27.     xdir AS SINGLE '       horizontal direction of bloom
  28.     ydir AS SINGLE '       vertical direction of bloom
  29.     xspeed AS SINGLE '     horizontal speed of bloom
  30.     yspeed AS SINGLE '     vertical speed of bloom
  31.     image AS LONG '        bloom image handle
  32.     freed AS INTEGER '     boolean indicating if image handle has been freed
  33.  
  34. REDIM Abra(1) AS CADABRA ' dynamic array to hold properties
  35. DIM x% '                   current x position of mouse
  36. DIM y% '                   current y position of mouse
  37. DIM Oldx% '                previous x position of mouse
  38. DIM Oldy% '                previous y position of mouse
  39. DIM Blooms% '              bloom counter
  40. DIM sa& '                  Sorcerer's Apprentice sound file
  41.  
  42. '----------------------------
  43. '- Main Program Begins Here -
  44. '----------------------------
  45.  
  46. SCREEN _NEWIMAGE(SWIDTH, SHEIGHT, 32) '      create 32 bit graphics screen
  47. _SCREENMOVE _MIDDLE '                        move window to center of desktop
  48. sa& = _SNDOPEN("apprentice.ogg") '           load sound file into RAM
  49. _SNDLOOP sa& '                               play music in continuous loop
  50. _MOUSEHIDE '                                 hide the mouse pointer
  51. _MOUSEMOVE SWIDTH \ 2, SHEIGHT \ 2 '         move mouse pointer to middle of screen
  52. WHILE _MOUSEINPUT: WEND '                    get latest mouse information
  53. x% = _MOUSEX '                               get current mouse x position
  54. y% = _MOUSEY '                               get current mouse y position
  55. Oldx% = x% '                                 remember mouse x position
  56. Oldy% = y% '                                 remember mouse y position
  57. Abra(1).freed = TRUE '                       first index is free to use
  58. RANDOMIZE TIMER '                            seed random number generator
  59. DO '                                         begin main loop
  60.     _LIMIT 30 '                              30 frames per second
  61.     WHILE _MOUSEINPUT: WEND '                get latest mouse information
  62.     x% = _MOUSEX '                           get current mouse x position
  63.     y% = _MOUSEY '                           get current mouse y position
  64.     IF (Oldx% <> x%) OR (Oldy% <> y%) THEN ' has mouse moved since last loop?
  65.         FOR Blooms% = 1 TO BLOOMAMOUNT '     yes, create set number of blooms
  66.             HOCUS x%, y% '                   create bloom at current mouse location
  67.         NEXT Blooms%
  68.         Oldx% = x% '                         remember mouse x position
  69.         Oldy% = y% '                         remember mouse y position
  70.     END IF
  71.     CLS '                                    clear screen
  72.     POCUS '                                  draw active blooms
  73.     _DISPLAY '                               update screen with changes
  74. LOOP UNTIL _KEYDOWN(27) '                    leave when ESC pressed
  75. SYSTEM '                                     return to Windows
  76.  
  77. '-----------------------------------
  78. '- Function and Subroutine section -
  79. '-----------------------------------
  80.  
  81. '----------------------------------------------------------------------------------------------------------------------
  82.  
  83. SUB HOCUS (hx%, hy%)
  84.  
  85.     '*
  86.     '* Maintains the bloom array by creating bloom properties for a new bloom.
  87.     '* If no array indexes are free a new one is added to the end of the array to
  88.     '* hold the new bloom. If an unused index is available the new bloom will occupy
  89.     '* that free index position. If no blooms are currently active the array is
  90.     '* erased and reset to an index of 1 to be built again.
  91.     '*
  92.     '* hx% - x location of new bloom
  93.     '* hy% - y location of new bloom
  94.     '*
  95.  
  96.     SHARED Abra() AS CADABRA ' need access to bloom array
  97.  
  98.     DIM CleanUp% '             if true array will be reset
  99.     DIM Count% '               generic counter
  100.     DIM Index% '               array index to create new bloom in
  101.     DIM OriginalDest& '        destination screen/image of calling routine
  102.     DIM Red% '                 red color component of bloom
  103.     DIM Green% '               green color component of bloom
  104.     DIM Blue% '                blue color component of bloom
  105.     DIM RedStep% '             red fade amount
  106.     DIM GreenStep% '           green fade amount
  107.     DIM BlueStep% '            blue fade amount
  108.     DIM Alpha% '               alpha channel fade amount
  109.  
  110.     CleanUp% = TRUE '                                           assume array will need reset
  111.     Index% = 0 '                                                reset available index marker
  112.     Count% = 1 '                                                start array index counter at 1
  113.     DO WHILE Count% <= UBOUND(Abra) '                           cycle through entire array
  114.         IF Abra(Count%).lifespan = 0 THEN '                     has this image run its course?
  115.             IF NOT Abra(Count%).freed THEN '                    yes, has the image been freed from RAM?
  116.                 _FREEIMAGE Abra(Count%).image '                 no, remove the image from RAM
  117.                 Abra(Count%).freed = TRUE '                     remember that it has been removed
  118.             END IF
  119.             IF Index% = 0 THEN '                                has an available array index been chosen?
  120.                 Index% = Count% '                               no, mark this array index as available
  121.             END IF
  122.         ELSE '                                                  no, this image is still active
  123.             CleanUp% = FALSE '                                  do not clear the array
  124.         END IF
  125.         Count% = Count% + 1 '                                   increment array index counter
  126.     LOOP
  127.     IF CleanUp% THEN '                                          have all images run their course?
  128.         REDIM Abra(1) AS CADABRA '                              yes, reset the array
  129.         Abra(1).freed = TRUE '                                  there is no image here yet
  130.         Index% = 1 '                                            mark first index as available
  131.     ELSE '                                                      no, there are still active images
  132.         IF Index% = 0 THEN '                                    were all the images in the array active?
  133.             REDIM _PRESERVE Abra(UBOUND(abra) + 1) AS CADABRA ' yes, increase the array size by 1
  134.             Index% = UBOUND(abra) '                             mark top index as available
  135.         END IF
  136.     END IF
  137.     Abra(Index%).lifespan = INT(RND(1) * MAXLIFE) + 16 '        random length of time to live (frames)
  138.     Abra(Index%).x = hx% '                                      bloom x location
  139.     Abra(Index%).y = hy% '                                      bloom y location
  140.     Abra(Index%).size = INT(RND(1) * (MAXSIZE * .75) + (MAXSIZE * .25)) ' random size of bloom
  141.     Abra(Index%).xdir = (RND(1) - RND(1)) * 3 '                 random horizontal direction of bloom
  142.     Abra(Index%).ydir = -1 '                                    vertical direction of bloom (up)
  143.     Abra(Index%).xspeed = INT(RND(1) * MAXXSPEED) '             random horizontal speed of bloom
  144.     Abra(Index%).yspeed = INT(RND(1) * MAXYSPEED) '             random vertical speed of bloom
  145.     Abra(Index%).image = _NEWIMAGE(Abra(Index%).size * 2, Abra(Index%).size * 2, 32) ' create image holder
  146.     Red% = INT(RND(1) * 255) + 1 '                              random red component value
  147.     Green% = INT(RND(1) * 255) + 1 '                            random green compoenent value
  148.     Blue% = INT(RND(1) * 255) + 1 '                             random blue component value
  149.     RedStep% = (255 - Red%) \ Abra(Index%).size '               random fade of red component
  150.     GreenStep% = (255 - Green%) \ Abra(Index%).size '           random fade of green component
  151.     BlueStep% = (255 - Blue%) \ Abra(Index%).size '             random fade of blue component
  152.     AlphaStep! = 255 \ Abra(Index%).size '                      compute fade of alpha channel
  153.     Alpha% = 0 '                                                start alpha channel completely transparent
  154.     OriginalDest& = _DEST '                                     save calling routine's destination screen/image
  155.     _DEST Abra(Index%).image '                                  set destination to bloom image
  156.     Count% = Abra(Index%).size '                                start from outside of bloom working in
  157.     DO WHILE Count% > 0 '                                       start bloom drawing loop
  158.         '*
  159.         '* Draw circle with current red, green, blue components
  160.         '*
  161.         CIRCLE (_WIDTH(Abra(Index%).image) / 2, _HEIGHT(Abra(Index%).image) / 2), Count%, _RGB32(Red%, Green%, Blue%)
  162.         '*
  163.         '* Paint circle with current red, green, blue components
  164.         '*
  165.         PAINT (_WIDTH(Abra(Index%).image) / 2, _HEIGHT(Abra(Index%).image) / 2), _RGB32(Red%, Green%, Blue%), _RGB32(Red%, Green%, Blue%)
  166.         _SETALPHA Alpha%, _RGB32(Red%, Green%, Blue%) '         set transparency level of current color
  167.         Red% = Red% + RedStep% '                                increase red component
  168.         Green% = Green% + GreenStep% '                          increase green component
  169.         Blue% = Blue% + BlueStep% '                             increase blue component
  170.         Alpha% = Alpha% + AlphaStep! '                          increase opacity level of alpha channel
  171.         Count% = Count% - 1 '                                   decrease size of circle
  172.     LOOP '                                                      leave loop when smallest circle drawn
  173.     _DEST OriginalDest& '                                       return original destination to calling routine
  174.  
  175.  
  176. '----------------------------------------------------------------------------------------------------------------------
  177.  
  178. SUB POCUS ()
  179.  
  180.     '*
  181.     '* places active blooms onto the screen or current image and updates their
  182.     '* position, size and speed
  183.     '*
  184.  
  185.     SHARED Abra() AS CADABRA ' need access to bloom array
  186.  
  187.     DIM c% '                   array index counter
  188.     DIM o% '                   bloom image size x,y offset
  189.  
  190.     c% = UBOUND(Abra) '                                                 start at top of array
  191.     DO WHILE c% > 0 '                                                   loop until beginning of array
  192.         IF Abra(c%).lifespan > 0 THEN '                                 is this bloom active?
  193.             o% = INT(Abra(c%).size) '                                   yes, get current size of bloom image
  194.             _PUTIMAGE (Abra(c%).x - o%, Abra(c%).y - o%)-(Abra(c%).x + o%, Abra(c%).y + o%), Abra(c%).image
  195.             Abra(c%).lifespan = Abra(c%).lifespan - 1 '                 decrement lifespan of bloom
  196.             Abra(c%).size = Abra(c%).size * .95 '                       decrease size of bloom slightly
  197.             Abra(c%).x = Abra(c%).x + Abra(c%).xdir * Abra(c%).xspeed ' update x position of bloom
  198.             Abra(c%).y = Abra(c%).y + Abra(c%).ydir * Abra(c%).yspeed ' update y position of bloom
  199.             IF Abra(c%).y > SHEIGHT - 1 THEN '                          has bloom left bottom of screen?
  200.                 IF BOUNCE THEN '                                        should bloom bounce?
  201.                     Abra(c%).yspeed = -Abra(c%).yspeed '                yes, reverse y velocity
  202.                 ELSE '                                                  no
  203.                     Abra(c%).lifespan = 0 '                             kill it, no longer needed
  204.                 END IF
  205.             END IF
  206.             Abra(c%).xspeed = Abra(c%).xspeed * .9 '                    decrease x velocity slightly
  207.             Abra(c%).yspeed = Abra(c%).yspeed - .5 '                    decrease y velocity (simulating gravity)
  208.         END IF
  209.         c% = c% - 1 '                                                   decrement to next index in array
  210.     LOOP
  211.  
  212.  
  213. '----------------------------------------------------------------------------------------------------------------------
  214.  
* apprentice.ogg (Filesize: 2.15 MB, Downloads: 223)
In order to understand recursion, one must first understand recursion.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Hocus Pocus
« Reply #1 on: May 07, 2020, 11:06:06 am »
Oh that's fun and I just noticed your signature :)

Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
    • View Profile
Re: Hocus Pocus
« Reply #2 on: May 07, 2020, 12:38:44 pm »
It is fun isn't it :-) I catch myself moving the mouse around in a daze watching all the colorful lights dance around. I think the music is perfect for the effect too.

In Task 16 of the tutorial (which I should have finished today) I have a complete breakdown of this program to explain how this effect is created. It's so simple but the effect it achieves makes it look as though some code kung fu was needed to create it.
In order to understand recursion, one must first understand recursion.

Offline Dav

  • Forum Resident
  • Posts: 792
    • View Profile
Re: Hocus Pocus
« Reply #3 on: May 07, 2020, 01:45:54 pm »
What a nice effect!   This is a keeper for sure.

- Dav

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Hocus Pocus
« Reply #4 on: May 07, 2020, 02:41:53 pm »
Really very nice! I like it.

Offline Dimster

  • Forum Resident
  • Posts: 500
    • View Profile
Re: Hocus Pocus
« Reply #5 on: May 07, 2020, 04:04:11 pm »
Works great with a glass of champagne. With two or three glasses even better. This must be how Walt Disney does it with that fairy wand.

Offline Ashish

  • Forum Resident
  • Posts: 630
  • Never Give Up!
    • View Profile
Re: Hocus Pocus
« Reply #6 on: May 09, 2020, 09:03:44 am »
Cool effect! I like it!
if (Me.success) {Me.improve()} else {Me.tryAgain()}


My Projects - https://github.com/AshishKingdom?tab=repositories
OpenGL tutorials - https://ashishkingdom.github.io/OpenGL-Tutorials