Author Topic: Particle engine  (Read 5410 times)

0 Members and 1 Guest are viewing this topic.

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: Particle engine
« Reply #15 on: August 30, 2020, 03:26:36 am »
Alright, this is the one you want to try...

Red objects are hot and make the particles rise.
Blue objects cool hot particles down quickly.
Green objects are one-way, upward-biased capillaries.

Draw red things with mouse1.
Draw blue things with mouse2.
Draw green things with mouse3.

I suggest drawing a shape in black space and then connecting it with green. See screenshot.

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(1024, 768, 32)
  2.  
  3. TYPE Vector
  4.     x AS DOUBLE
  5.     y AS DOUBLE
  6.  
  7. TYPE Pixel
  8.     active AS INTEGER
  9.     position AS Vector
  10.     velocity AS Vector
  11.     acceleration AS Vector
  12.     size AS DOUBLE
  13.     shadered AS DOUBLE
  14.     shadegreen AS DOUBLE
  15.     shadeblue AS DOUBLE
  16.     shadealpha AS DOUBLE
  17.  
  18. TYPE Object
  19.     position AS Vector
  20.     size AS DOUBLE
  21.     amplitude AS Vector
  22.     frequency AS DOUBLE
  23.     shadered AS DOUBLE
  24.     shadegreen AS DOUBLE
  25.     shadeblue AS DOUBLE
  26.     shadealpha AS DOUBLE
  27.  
  28. DIM SHARED PixelCloud(3000) AS Pixel
  29. DIM SHARED Level(5000) AS Object
  30. DIM SHARED ObjectCount AS INTEGER
  31. ObjectCount = 0
  32.  
  33. FOR k = 1 TO UBOUND(PixelCloud)
  34.     PixelCloud(k).active = 1
  35.     PixelCloud(k).size = 3
  36.     PixelCloud(k).acceleration.x = 0
  37.     PixelCloud(k).acceleration.y = 0
  38.     PixelCloud(k).velocity.x = 0
  39.     PixelCloud(k).velocity.y = 0
  40.     PixelCloud(k).position.x = (RND - .5) * _WIDTH * .9
  41.     PixelCloud(k).position.y = (RND - .5) * _HEIGHT * .9
  42.     CALL SetPixelShade(k, 0, 0, 255, 150)
  43.  
  44. CALL InitializeLevel
  45.  
  46. DIM SHARED whirlyparameter AS DOUBLE
  47. whirlyparameter = 0
  48.  
  49.     CALL UserInput
  50.     CLS
  51.     CALL DrawBorder
  52.     CALL DrawPixels
  53.     CALL DrawLevel
  54.     CALL Dynamics
  55.  
  56.     whirlyparameter = whirlyparameter + ATN(1) / 10
  57.     IF whirlyparameter > 16 * ATN(1) THEN whirlyparameter = whirlyparameter - 16 * ATN(1)
  58.     _DISPLAY
  59.     _LIMIT 30
  60.  
  61.  
  62. SUB Dynamics
  63.     DIM k AS INTEGER
  64.     FOR k = 1 TO UBOUND(PixelCloud)
  65.         CALL CalculateInfluence(k)
  66.         CALL UpdatePosition(k)
  67.     NEXT
  68.  
  69. SUB UpdatePosition (i AS INTEGER)
  70.     DIM dt AS DOUBLE
  71.     DIM damp AS DOUBLE
  72.     DIM brownian AS DOUBLE
  73.     dt = 2
  74.     damp = .25
  75.     brownian = .25
  76.     PixelCloud(i).velocity.x = damp * PixelCloud(i).velocity.x + dt * PixelCloud(i).acceleration.x
  77.     PixelCloud(i).velocity.y = damp * PixelCloud(i).velocity.y + dt * PixelCloud(i).acceleration.y
  78.     PixelCloud(i).position.x = PixelCloud(i).position.x + dt * PixelCloud(i).velocity.x + (RND - .5) * brownian
  79.     PixelCloud(i).position.y = PixelCloud(i).position.y + dt * PixelCloud(i).velocity.y + (RND - .5) * brownian
  80.     IF (PixelCloud(i).position.y <= -_HEIGHT / 2 + 2 * PixelCloud(i).size + 1) THEN
  81.         PixelCloud(i).position.y = _HEIGHT / 2 - 2 * PixelCloud(i).size
  82.     END IF
  83.  
  84. SUB DrawBorder
  85.     LINE (0, 0)-(_WIDTH, _HEIGHT), _RGB32(255, 0, 0, 255), BF
  86.     LINE (10, 10)-(_WIDTH - 10, _HEIGHT - 10), _RGB32(0, 0, 0, 255), BF
  87.  
  88. SUB DrawPixels
  89.     DIM k AS INTEGER
  90.     DIM x AS DOUBLE
  91.     DIM y AS DOUBLE
  92.     DIM s AS DOUBLE
  93.     FOR k = 1 TO UBOUND(PixelCloud)
  94.         IF (PixelCloud(k).active = 1) THEN
  95.             x = PixelCloud(k).position.x
  96.             y = PixelCloud(k).position.y
  97.             s = PixelCloud(k).size
  98.             CALL clinebf(x - s, y - s, x + s, y + s, _RGBA(PixelCloud(k).shadered, PixelCloud(k).shadegreen, PixelCloud(k).shadeblue, PixelCloud(k).shadealpha))
  99.         END IF
  100.     NEXT
  101.  
  102. SUB DrawLevel
  103.     DIM k AS INTEGER
  104.     DIM x AS DOUBLE
  105.     DIM y AS DOUBLE
  106.     DIM s AS DOUBLE
  107.     DIM t AS DOUBLE
  108.     t = whirlyparameter
  109.     FOR k = 1 TO ObjectCount
  110.         x = Level(k).position.x + Level(k).amplitude.x * SIN(Level(k).frequency * t)
  111.         y = Level(k).position.y + Level(k).amplitude.y * SIN(Level(k).frequency * t)
  112.         s = Level(k).size
  113.         CALL clinebf(x - s, y - s, x + s, y + s, _RGBA(Level(k).shadered, Level(k).shadegreen, Level(k).shadeblue, Level(k).shadealpha))
  114.     NEXT
  115.  
  116. FUNCTION cpoint& (x1 AS DOUBLE, y1 AS DOUBLE)
  117.     DIM TheReturn AS _UNSIGNED LONG
  118.     TheReturn = POINT(_WIDTH / 2 + x1, -y1 + _HEIGHT / 2)
  119.     cpoint = TheReturn
  120.  
  121. SUB clinebf (x1 AS DOUBLE, y1 AS DOUBLE, x2 AS DOUBLE, y2 AS DOUBLE, col AS _UNSIGNED LONG)
  122.     LINE (_WIDTH / 2 + x1, -y1 + _HEIGHT / 2)-(_WIDTH / 2 + x2 - 0, -y2 + _HEIGHT / 2 + 0), col, BF
  123.  
  124. SUB SetPixelShade (i AS INTEGER, r AS INTEGER, g AS INTEGER, b AS INTEGER, a AS INTEGER)
  125.     PixelCloud(i).shadered = r
  126.     PixelCloud(i).shadegreen = g
  127.     PixelCloud(i).shadeblue = b
  128.     PixelCloud(i).shadealpha = a
  129.  
  130. SUB SetObjectShade (i AS INTEGER, r AS INTEGER, g AS INTEGER, b AS INTEGER, a AS INTEGER)
  131.     Level(i).shadered = r
  132.     Level(i).shadegreen = g
  133.     Level(i).shadeblue = b
  134.     Level(i).shadealpha = a
  135.  
  136. SUB InitializeLevel
  137.     DIM xx AS DOUBLE
  138.     DIM yy AS DOUBLE
  139.     DIM mx AS DOUBLE
  140.     DIM my AS DOUBLE
  141.     FOR xx = -20 TO 20
  142.         FOR yy = -252 TO -250
  143.             mx = xx - xx MOD (3 * 2.5)
  144.             my = yy - yy MOD (3 * 2.5)
  145.             IF ((_RED32(cpoint(mx, my)) <> 255) AND (_GREEN32(cpoint(mx, my)) <> 255) AND (_BLUE32(cpoint(mx, my)) <> 255)) THEN
  146.                 ObjectCount = ObjectCount + 1
  147.                 Level(ObjectCount).size = 3
  148.                 Level(ObjectCount).position.x = mx
  149.                 Level(ObjectCount).position.y = my
  150.                 Level(ObjectCount).amplitude.x = 0
  151.                 Level(ObjectCount).amplitude.y = 70
  152.                 Level(ObjectCount).frequency = .5
  153.                 CALL SetObjectShade(ObjectCount, 0, 255, 0, 255)
  154.             END IF
  155.  
  156.         NEXT
  157.     NEXT
  158.     FOR xx = -27 TO -25
  159.         FOR yy = -250 - 70 TO -250 + 70
  160.             mx = xx - xx MOD (3 * 2.5)
  161.             my = yy - yy MOD (3 * 2.5)
  162.             IF ((_RED32(cpoint(mx, my)) <> 255) AND (_GREEN32(cpoint(mx, my)) <> 255) AND (_BLUE32(cpoint(mx, my)) <> 255)) THEN
  163.                 ObjectCount = ObjectCount + 1
  164.                 Level(ObjectCount).size = 3
  165.                 Level(ObjectCount).position.x = mx
  166.                 Level(ObjectCount).position.y = my
  167.                 Level(ObjectCount).amplitude.x = 0
  168.                 Level(ObjectCount).amplitude.y = 0
  169.                 Level(ObjectCount).frequency = 0
  170.                 CALL SetObjectShade(ObjectCount, 255, 0, 0, 255)
  171.             END IF
  172.  
  173.         NEXT
  174.     NEXT
  175.     FOR xx = 25 TO 27
  176.         FOR yy = -250 - 70 TO -250 + 70
  177.             mx = xx - xx MOD (3 * 2.5)
  178.             my = yy - yy MOD (3 * 2.5)
  179.             IF ((_RED32(cpoint(mx, my)) <> 255) AND (_GREEN32(cpoint(mx, my)) <> 255) AND (_BLUE32(cpoint(mx, my)) <> 255)) THEN
  180.                 ObjectCount = ObjectCount + 1
  181.                 Level(ObjectCount).size = 3
  182.                 Level(ObjectCount).position.x = mx
  183.                 Level(ObjectCount).position.y = my
  184.                 Level(ObjectCount).amplitude.x = 0
  185.                 Level(ObjectCount).amplitude.y = 0
  186.                 Level(ObjectCount).frequency = 0
  187.                 CALL SetObjectShade(ObjectCount, 255, 0, 0, 255)
  188.             END IF
  189.         NEXT
  190.     NEXT
  191.  
  192. SUB UserInput
  193.     DIM mb1 AS INTEGER
  194.     DIM mb2 AS INTEGER
  195.     DIM mb3 AS INTEGER
  196.     DIM mx AS DOUBLE
  197.     DIM my AS DOUBLE
  198.     DIM sz AS DOUBLE
  199.     IF (ObjectCount > 0) THEN
  200.         sz = Level(ObjectCount).size
  201.     ELSE
  202.         sz = 3
  203.     END IF
  204.     mb1 = 0
  205.     mb2 = 0
  206.     mb3 = 0
  207.         IF (_MOUSEBUTTON(1) = -1) AND (mb1 <> -1) THEN
  208.             mb1 = -1
  209.             mx = (_MOUSEX - _WIDTH / 2)
  210.             my = (-_MOUSEY + _HEIGHT / 2)
  211.             mx = mx - mx MOD (sz * 2.5)
  212.             my = my - my MOD (sz * 2.5)
  213.             IF ((_RED32(cpoint(mx, my)) <> 255) AND (_GREEN32(cpoint(mx, my)) <> 255) AND (_BLUE32(cpoint(mx, my)) <> 255)) THEN
  214.                 ObjectCount = ObjectCount + 1
  215.                 Level(ObjectCount).size = sz
  216.                 Level(ObjectCount).position.x = mx
  217.                 Level(ObjectCount).position.y = my
  218.                 CALL SetObjectShade(ObjectCount, 255, 0, 0, 255)
  219.             END IF
  220.         END IF
  221.         IF (_MOUSEBUTTON(2) = -1) AND (mb2 <> -1) THEN
  222.             mb2 = -1
  223.             mx = (_MOUSEX - _WIDTH / 2)
  224.             my = (-_MOUSEY + _HEIGHT / 2)
  225.             mx = mx - mx MOD (sz * 2.5)
  226.             my = my - my MOD (sz * 2.5)
  227.             IF ((_RED32(cpoint(mx, my)) <> 255) AND (_GREEN32(cpoint(mx, my)) <> 255) AND (_BLUE32(cpoint(mx, my)) <> 255)) THEN
  228.                 ObjectCount = ObjectCount + 1
  229.                 Level(ObjectCount).size = sz
  230.                 Level(ObjectCount).position.x = mx
  231.                 Level(ObjectCount).position.y = my
  232.                 CALL SetObjectShade(ObjectCount, 0, 0, 255, 255)
  233.             END IF
  234.         END IF
  235.         IF (_MOUSEBUTTON(3) = -1) AND (mb3 <> -1) THEN
  236.             mb3 = -1
  237.             mx = (_MOUSEX - _WIDTH / 2)
  238.             my = (-_MOUSEY + _HEIGHT / 2)
  239.             mx = mx - mx MOD (sz * 2.5)
  240.             my = my - my MOD (sz * 2.5)
  241.             IF ((_RED32(cpoint(mx, my)) <> 255) AND (_GREEN32(cpoint(mx, my)) <> 255) AND (_BLUE32(cpoint(mx, my)) <> 255)) THEN
  242.                 ObjectCount = ObjectCount + 1
  243.                 Level(ObjectCount).size = sz
  244.                 Level(ObjectCount).position.x = mx
  245.                 Level(ObjectCount).position.y = my
  246.                 Level(ObjectCount).frequency = 1
  247.                 CALL SetObjectShade(ObjectCount, 0, 255, 0, 255)
  248.             END IF
  249.         END IF
  250.     LOOP
  251.  
  252.     IF (INKEY$ = " ") THEN
  253.         ObjectCount = ObjectCount - 1
  254.         IF (ObjectCount < 0) THEN ObjectCount = 0
  255.     END IF
  256.  
  257.  
  258. SUB CalculateInfluence (i AS INTEGER)
  259.     DIM x AS DOUBLE
  260.     DIM y AS DOUBLE
  261.     DIM xr AS DOUBLE
  262.     DIM yr AS DOUBLE
  263.     DIM xg AS DOUBLE
  264.     DIM yg AS DOUBLE
  265.     DIM xb AS DOUBLE
  266.     DIM yb AS DOUBLE
  267.     DIM dx AS DOUBLE
  268.     DIM dy AS DOUBLE
  269.     DIM WPoint(9) AS _UNSIGNED LONG
  270.     DIM WRed(9) AS INTEGER
  271.     DIM WGreen(9) AS INTEGER
  272.     DIM WBlue(9) AS INTEGER
  273.     x = PixelCloud(i).position.x
  274.     y = PixelCloud(i).position.y
  275.     dx = 2 * PixelCloud(i).size
  276.     dy = 2 * PixelCloud(i).size
  277.     WPoint(7) = cpoint(x - dx, y + dy)
  278.     WPoint(8) = cpoint(x, y + dy)
  279.     WPoint(9) = cpoint(x + dx, y + dy)
  280.     WPoint(4) = cpoint(x - dx, y)
  281.     WPoint(6) = cpoint(x + dx, y)
  282.     WPoint(1) = cpoint(x - dx, y - dy)
  283.     WPoint(2) = cpoint(x, y - dy)
  284.     WPoint(3) = cpoint(x + dx, y - dy)
  285.     WRed(7) = _RED32(WPoint(7))
  286.     WRed(8) = _RED32(WPoint(8))
  287.     WRed(9) = _RED32(WPoint(9))
  288.     WRed(4) = _RED32(WPoint(4))
  289.     WRed(6) = _RED32(WPoint(6))
  290.     WRed(1) = _RED32(WPoint(1))
  291.     WRed(2) = _RED32(WPoint(2))
  292.     WRed(3) = _RED32(WPoint(3))
  293.     WGreen(7) = _GREEN32(WPoint(7))
  294.     WGreen(8) = _GREEN32(WPoint(8))
  295.     WGreen(9) = _GREEN32(WPoint(9))
  296.     WGreen(4) = _GREEN32(WPoint(4))
  297.     WGreen(6) = _GREEN32(WPoint(6))
  298.     WGreen(1) = _GREEN32(WPoint(1))
  299.     WGreen(2) = _GREEN32(WPoint(2))
  300.     WGreen(3) = _GREEN32(WPoint(3))
  301.     WBlue(7) = _BLUE32(WPoint(7))
  302.     WBlue(8) = _BLUE32(WPoint(8))
  303.     WBlue(9) = _BLUE32(WPoint(9))
  304.     WBlue(4) = _BLUE32(WPoint(4))
  305.     WBlue(6) = _BLUE32(WPoint(6))
  306.     WBlue(1) = _BLUE32(WPoint(1))
  307.     WBlue(2) = _BLUE32(WPoint(2))
  308.     WBlue(3) = _BLUE32(WPoint(3))
  309.  
  310.     xr = (WRed(6) - WRed(4) + (WRed(9) + WRed(3)) / SQR(2) - (WRed(7) + WRed(1)) / SQR(2))
  311.     yr = (WRed(8) - WRed(2) + (WRed(7) + WRed(9)) / SQR(2) - (WRed(1) + WRed(3)) / SQR(2))
  312.     'xg = (WGreen(6) - WGreen(4) + (WGreen(9) + WGreen(3)) / SQR(2) - (WGreen(7) + WGreen(1)) / SQR(2))
  313.     'yg = (WGreen(8) - WGreen(2) + (WGreen(7) + WGreen(9)) / SQR(2) - (WGreen(1) + WGreen(3)) / SQR(2))
  314.     xg = -(WGreen(6) - WGreen(4) + (WGreen(9) + WGreen(3)) / SQR(2) - (WGreen(7) + WGreen(1)) / SQR(2))
  315.     yg = -10 * (WGreen(8) - 0 + (WGreen(7) + WGreen(9)) / SQR(2) - (0 + 0) / SQR(2))
  316.     yg = 10 * (0 - WGreen(2) + (0 + 0) / SQR(2) - (WGreen(1) + WGreen(3)) / SQR(2))
  317.     xb = (WBlue(6) - WBlue(4) + (WBlue(9) + WBlue(3)) / SQR(2) - (WBlue(7) + WBlue(1)) / SQR(2))
  318.     yb = (WBlue(8) - WBlue(2) + (WBlue(7) + WBlue(9)) / SQR(2) - (WBlue(1) + WBlue(3)) / SQR(2))
  319.     x = xr + xg + xb
  320.     y = yr + yg + yb
  321.  
  322.     IF (xr ^ 2 + yr ^ 2 > xb ^ 2 + yb ^ 2) AND (xr ^ 2 + yr ^ 2 > 15) THEN
  323.         PixelCloud(i).shadered = PixelCloud(i).shadered + 128
  324.         IF (PixelCloud(i).shadered >= 255) THEN PixelCloud(i).shadered = 255
  325.         PixelCloud(i).shadeblue = PixelCloud(i).shadeblue - 128
  326.         IF (PixelCloud(i).shadeblue <= 0) THEN PixelCloud(i).shadeblue = 0
  327.     END IF
  328.  
  329.     IF (xb ^ 2 + yb ^ 2 > xr ^ 2 + yr ^ 2) THEN
  330.         PixelCloud(i).shadered = PixelCloud(i).shadered - 128
  331.         IF (PixelCloud(i).shadered <= 0) THEN PixelCloud(i).shadered = 0
  332.         PixelCloud(i).shadeblue = PixelCloud(i).shadeblue + 128
  333.         IF (PixelCloud(i).shadeblue >= 255) THEN PixelCloud(i).shadeblue = 255
  334.     END IF
  335.  
  336.     y = y - 2 * (PixelCloud(i).shadered - PixelCloud(i).shadeblue) / 255
  337.  
  338.     IF (ABS(x) < .001) THEN
  339.         PixelCloud(i).acceleration.x = 0
  340.     ELSE
  341.         PixelCloud(i).acceleration.x = -x / SQR(x * x + y * y)
  342.     END IF
  343.     IF (ABS(y) < .001) THEN
  344.         PixelCloud(i).acceleration.y = 0
  345.     ELSE
  346.         PixelCloud(i).acceleration.y = -y / SQR(x * x + y * y)
  347.     END IF
  348.  
  349.     PixelCloud(i).shadered = PixelCloud(i).shadered - 5
  350.     IF (PixelCloud(i).shadered <= 0) THEN PixelCloud(i).shadered = 0
  351.     PixelCloud(i).shadeblue = PixelCloud(i).shadeblue + 5
  352.     IF (PixelCloud(i).shadeblue >= 255) THEN PixelCloud(i).shadeblue = 255

ss.png
* ss.png (Filesize: 72.37 KB, Dimensions: 1024x768, Views: 196)
You're not done when it works, you're done when it's right.

Offline loudar

  • Newbie
  • Posts: 73
  • improve it bit by bit.
    • View Profile
Re: Particle engine
« Reply #16 on: September 04, 2020, 07:54:58 pm »
Built a little heat chamber which cooled down at the top :D

One thing I noticed is that particles cool down reaaally quickly, which is why I needed so much red to get it all the way to the top and keep it there.
Untitled-1.png
* Untitled-1.png (Filesize: 35.31 KB, Dimensions: 1024x794, Views: 177)
Check out what I do besides coding: http://loudar.myportfolio.com/

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: Particle engine
« Reply #17 on: September 04, 2020, 09:44:46 pm »
Thanks for trying it loudar!!!

About to post a new version and announce next changes over at https://www.qb64.org/forum/index.php?topic=2972.0

I love the screenshot too!
You're not done when it works, you're done when it's right.