Author Topic: Emerging game: FluidCraft  (Read 5187 times)

0 Members and 1 Guest are viewing this topic.

This topic contains a post which is marked as Best Answer. Press here if you would like to see it.

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Emerging game: FluidCraft
« on: September 01, 2020, 02:06:40 am »
Hello all,

Continuing the work started in https://www.qb64.org/forum/index.php?topic=2967.0, it's time to give this thing a name, and perhaps, a purpose. The so-called "particle engine" is now called FluidCraft, a 2D sandbox/pseudo-simulation tool for dealing with compressible fluids (a kind of thick gas you can play with). Left on their own, the gas particles will naturally repel each other, but not strictly - with enough "weight" involved, the particles compress and want to burst apart. Particles also bear a notion of hotness - the hot ones will rise, the cold ones will fall - and particles conduct or steal energy from their neighbors.

Apart from gravity, there are three fundamental "control" structures you can draw with the mouse (use mouse1 to draw, mousewheel to choose color).

1) Red lines are sources of heat and serve as a boundary for particles.
2) Blue lines are a source of cooling and are also a boundary.
3) Green lines move the particles strictly upward, no matter what.

So those are the fundamentals... Then, with no real effort at all, we get new effects by mixing colors. So far I've only hardcoded yellow, which is a mixture of red and green. Averaging the effects of red and green, yellow lines are "hot capillaries". Right mouse button deletes level elements.

There is also an export button, "e", for saving levels... which must imply a "load" feature. Indeed, drag+drop a level onto Untitled.exe (or FluidCraft.exe if you actually save it). I've included a sample level as a download. It never plays exactly the same twice. Of course, if you load no level, you get a blank slate, more or less. No screenshot this time, you have to run it.

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

Offline Juan Tamarit

  • Newbie
  • Posts: 53
    • View Profile
Re: Emerging game: FluidCraft
« Reply #1 on: September 02, 2020, 01:55:21 am »
Code: QB64: [Select]
  1. TYPE ShadeVector
  2.     shadered AS DOUBLE
  3.     shadegreen AS DOUBLE
  4.     shadeblue AS DOUBLE
  5.     shadealpha AS DOUBLE
  6.  
  7. TYPE ShadeElement
  8.     TheName AS STRING
  9.     TheShade AS ShadeVector
  10.  

I'm very interested about this. In line 22 of your code you got a TYPE inside a TYPE? How do you access it? say... How can you access the string and the doubles?

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: Emerging game: FluidCraft
« Reply #2 on: September 02, 2020, 06:38:36 am »
Good morning Juan,

Types within types are a dream aren't they? To access embedded stuff, we have the "dot" operator ( . ), which you can use more than once per line, like so:

Code: QB64: [Select]
  1. PixelCloud(i).acceleration.x = -x / SQR(x * x + y * y)

Looks like I came to the particle fountain party too late because you have the first legit question about any of this! Whats the matter boys, everything in here too trivial for you?
You're not done when it works, you're done when it's right.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Emerging game: FluidCraft
« Reply #3 on: September 02, 2020, 03:35:15 pm »
As per usual very interesting "game"? red goes right through green as if not there but green stops blue. Blue may contain red a bit...

I immediately wish for black eraser.

 
STx Game.PNG
« Last Edit: September 02, 2020, 03:39:56 pm by bplus »

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: Emerging game: FluidCraft
« Reply #4 on: September 02, 2020, 03:56:42 pm »
Right click to erase (sorry on road no verbosity)
You're not done when it works, you're done when it's right.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Emerging game: FluidCraft
« Reply #5 on: September 02, 2020, 04:29:37 pm »
Right click to erase (sorry on road no verbosity)

Ah OK, thanks :)

Offline Juan Tamarit

  • Newbie
  • Posts: 53
    • View Profile
Re: Emerging game: FluidCraft
« Reply #6 on: September 03, 2020, 01:29:24 am »
Good morning Juan,

Types within types are a dream aren't they? To access embedded stuff, we have the "dot" operator ( . ), which you can use more than once per line, like so:

Code: QB64: [Select]
  1. PixelCloud(i).acceleration.x = -x / SQR(x * x + y * y)

Looks like I came to the particle fountain party too late because you have the first legit question about any of this! Whats the matter boys, everything in here too trivial for you?

Bro, thank you for your reply. Very interesting what you comment on TYPEs inside TYPEs... i can't mentally DIM it yet (feels like from another planet more than another dimension), but i will think about it. I honestly don´t know what particles are, didn't get to that point of Terrie's course yet, but sounds like a bit of pieces blowing away from an explosion hehehe

Offline Ashish

  • Forum Resident
  • Posts: 630
  • Never Give Up!
    • View Profile
Re: Emerging game: FluidCraft
« Reply #7 on: September 04, 2020, 12:38:57 am »
Wow! This is great! I spend 30 mins playing with this. I could also create a loop! It will be great if we could draw the obstacles as well. :D
if (Me.success) {Me.improve()} else {Me.tryAgain()}


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

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: Emerging game: FluidCraft
« Reply #8 on: September 04, 2020, 09:53:03 pm »
Thanks Ashish and everyone - bplus, loudar, Juan and whoever else - for trying this.

So this latest version has updated mechanics. We still have the same rules as before (except new behavior for yellow), plus some new ones...

1) Red lines are sources of heat and serve as a boundary for particles.
2) Blue lines are a source of cooling and are also a boundary.
3) Green lines move the particles strictly upward.
4) Aqua lines move particles strictly to the right.
5) Yellow lines move particles strictly to the left.
6) White lines move particles strictly downward.

The mouse control is way way better too. (Thanks for tolerating the crappy first take...) You'll find that colors can be stacked all the way to white. Right click to delete, use mousewheel to select between them.

Updated code, test level, and screenshot below. You can see this one is all about getting all the primitive behavior correct. By now we can represent most of the plumbing and hvac apparatus found in north america. The next update will prolly be less about mechanics and more about UI.

Code: QB64: [Select]
  1. _TITLE "FluidCraft"
  2. _DELAY .25
  3. SCREEN _NEWIMAGE(1024, 768, 32)
  4.  
  5. TYPE Vector
  6.     x AS DOUBLE
  7.     y AS DOUBLE
  8.  
  9. TYPE ShadeVector
  10.     shadered AS DOUBLE
  11.     shadegreen AS DOUBLE
  12.     shadeblue AS DOUBLE
  13.     shadealpha AS DOUBLE
  14.  
  15. TYPE ShadeElement
  16.     TheName AS STRING
  17.     TheShade AS ShadeVector
  18.  
  19. TYPE Pixel
  20.     active AS INTEGER
  21.     position AS Vector
  22.     velocity AS Vector
  23.     acceleration AS Vector
  24.     size AS DOUBLE
  25.     TheShade AS ShadeVector
  26.  
  27. DIM SHARED ShadeData(7) AS ShadeElement
  28. DIM SHARED ActiveShade AS INTEGER
  29. DIM SHARED PixelCloud(3000) AS Pixel
  30. DIM SHARED ObjectSize AS DOUBLE
  31. DIM SHARED GridSize AS Vector
  32. ObjectSize = 6
  33. GridSize.x = 1 + INT(_WIDTH / ObjectSize)
  34. GridSize.y = 1 + INT(_HEIGHT / ObjectSize)
  35. DIM SHARED Level(GridSize.x, GridSize.y) AS ShadeVector
  36.  
  37. CALL InitializeAll
  38. CALL LoadFile
  39.  
  40.     CALL UserInput
  41.     CLS
  42.     CALL DrawBorder
  43.     CALL DrawPixels
  44.     CALL DrawLevel
  45.     CALL Dynamics
  46.     LINE (ObjectSize * INT(_MOUSEX / ObjectSize) - ObjectSize / 2, ObjectSize * INT(_MOUSEY / ObjectSize) - ObjectSize / 2)-(ObjectSize * INT(_MOUSEX / ObjectSize) + ObjectSize / 2 - 1, ObjectSize * INT(_MOUSEY / ObjectSize) + ObjectSize / 2 - 1), _RGBA(ShadeData(ActiveShade).TheShade.shadered, ShadeData(ActiveShade).TheShade.shadegreen, ShadeData(ActiveShade).TheShade.shadeblue, ShadeData(ActiveShade).TheShade.shadealpha), BF
  47.     _DISPLAY
  48.     _LIMIT 30
  49.  
  50.  
  51. SUB DrawBorder
  52.     LINE (0, 0)-(_WIDTH, _HEIGHT), _RGB32(255, 0, 0, 255), BF
  53.     LINE (10, 10)-(_WIDTH - 10, _HEIGHT - 10), _RGB32(0, 0, 0, 255), BF
  54.  
  55. SUB DrawPixels
  56.     DIM k AS INTEGER
  57.     DIM x AS DOUBLE
  58.     DIM y AS DOUBLE
  59.     DIM s AS DOUBLE
  60.     FOR k = 1 TO UBOUND(PixelCloud)
  61.         IF (PixelCloud(k).active = 1) THEN
  62.             x = PixelCloud(k).position.x
  63.             y = PixelCloud(k).position.y
  64.             s = PixelCloud(k).size
  65.             CALL clinebf(x - s, y - s, x + s, y + s, _RGBA(PixelCloud(k).TheShade.shadered, PixelCloud(k).TheShade.shadegreen, PixelCloud(k).TheShade.shadeblue, PixelCloud(k).TheShade.shadealpha))
  66.         END IF
  67.     NEXT
  68.  
  69. SUB DrawLevel
  70.     DIM i AS INTEGER
  71.     DIM j AS INTEGER
  72.     DIM x AS DOUBLE
  73.     DIM y AS DOUBLE
  74.     DIM s AS DOUBLE
  75.     s = ObjectSize
  76.     FOR i = 1 TO GridSize.x
  77.         FOR j = 1 TO GridSize.y
  78.             x = (i - 1) * s
  79.             y = (j - 1) * s
  80.             CALL slinebf(x - s / 2, y - s / 2, x + s / 2 - 1, y + s / 2 - 1, _RGBA(Level(i, j).shadered, Level(i, j).shadegreen, Level(i, j).shadeblue, Level(i, j).shadealpha))
  81.         NEXT
  82.     NEXT
  83.  
  84. SUB InitializeAll
  85.     DIM k AS INTEGER
  86.     ShadeData(1).TheName = "red"
  87.     ShadeData(1).TheShade.shadered = 255
  88.     ShadeData(1).TheShade.shadegreen = 0
  89.     ShadeData(1).TheShade.shadeblue = 0
  90.     ShadeData(1).TheShade.shadealpha = 255
  91.     ShadeData(2).TheName = "green"
  92.     ShadeData(2).TheShade.shadered = 0
  93.     ShadeData(2).TheShade.shadegreen = 255
  94.     ShadeData(2).TheShade.shadeblue = 0
  95.     ShadeData(2).TheShade.shadealpha = 255
  96.     ShadeData(3).TheName = "blue"
  97.     ShadeData(3).TheShade.shadered = 0
  98.     ShadeData(3).TheShade.shadegreen = 0
  99.     ShadeData(3).TheShade.shadeblue = 255
  100.     ShadeData(3).TheShade.shadealpha = 255
  101.     ShadeData(4).TheName = "yellow"
  102.     ShadeData(4).TheShade.shadered = 255
  103.     ShadeData(4).TheShade.shadegreen = 255
  104.     ShadeData(4).TheShade.shadeblue = 0
  105.     ShadeData(4).TheShade.shadealpha = 255
  106.     ShadeData(5).TheName = "aqua"
  107.     ShadeData(5).TheShade.shadered = 0
  108.     ShadeData(5).TheShade.shadegreen = 255
  109.     ShadeData(5).TheShade.shadeblue = 255
  110.     ShadeData(5).TheShade.shadealpha = 255
  111.     ShadeData(6).TheName = "violet"
  112.     ShadeData(6).TheShade.shadered = 255
  113.     ShadeData(6).TheShade.shadegreen = 0
  114.     ShadeData(6).TheShade.shadeblue = 255
  115.     ShadeData(6).TheShade.shadealpha = 255
  116.     ShadeData(7).TheName = "white"
  117.     ShadeData(7).TheShade.shadered = 255
  118.     ShadeData(7).TheShade.shadegreen = 255
  119.     ShadeData(7).TheShade.shadeblue = 255
  120.     ShadeData(7).TheShade.shadealpha = 255
  121.  
  122.  
  123.     ActiveShade = 1
  124.     FOR k = 1 TO UBOUND(PixelCloud)
  125.         PixelCloud(k).active = 1
  126.         PixelCloud(k).size = 3
  127.         PixelCloud(k).acceleration.x = 0
  128.         PixelCloud(k).acceleration.y = 0
  129.         PixelCloud(k).velocity.x = 0
  130.         PixelCloud(k).velocity.y = 0
  131.         PixelCloud(k).position.x = (RND - .5) * _WIDTH * .9
  132.         PixelCloud(k).position.y = (RND - .5) * _HEIGHT * .9
  133.         CALL SetPixelShade(k, 0, 0, 255, 150)
  134.     NEXT
  135.  
  136. SUB SetPixelShade (i AS INTEGER, r AS INTEGER, g AS INTEGER, b AS INTEGER, a AS INTEGER)
  137.     PixelCloud(i).TheShade.shadered = r
  138.     PixelCloud(i).TheShade.shadegreen = g
  139.     PixelCloud(i).TheShade.shadeblue = b
  140.     PixelCloud(i).TheShade.shadealpha = a
  141.  
  142. SUB UserInput
  143.     DIM mb1 AS INTEGER
  144.     DIM mb2 AS INTEGER
  145.     DIM mb3 AS INTEGER
  146.     DIM i AS INTEGER
  147.     DIM j AS INTEGER
  148.     mb1 = 0
  149.     mb2 = 0
  150.     mb3 = 0
  151.         IF (_MOUSEBUTTON(1) = -1) AND (mb1 <> 1) THEN
  152.             mb1 = -1
  153.             i = 1 + INT(_MOUSEX / ObjectSize)
  154.             j = 1 + INT(_MOUSEY / ObjectSize)
  155.             Level(i, j).shadered = Level(i, j).shadered + ShadeData(ActiveShade).TheShade.shadered
  156.             Level(i, j).shadegreen = Level(i, j).shadegreen + ShadeData(ActiveShade).TheShade.shadegreen
  157.             Level(i, j).shadeblue = Level(i, j).shadeblue + ShadeData(ActiveShade).TheShade.shadeblue
  158.             Level(i, j).shadealpha = Level(i, j).shadealpha + ShadeData(ActiveShade).TheShade.shadealpha
  159.         END IF
  160.         IF ((_MOUSEBUTTON(2) = -1) AND (mb2 <> -1)) THEN
  161.             mb2 = -1
  162.             i = 1 + INT(_MOUSEX / ObjectSize)
  163.             j = 1 + INT(_MOUSEY / ObjectSize)
  164.             Level(i, j).shadered = 0
  165.             Level(i, j).shadegreen = 0
  166.             Level(i, j).shadeblue = 0
  167.             Level(i, j).shadealpha = 0
  168.         END IF
  169.         IF (_MOUSEWHEEL = -1) THEN
  170.             ActiveShade = ActiveShade + 1
  171.             IF (ActiveShade > UBOUND(ShadeData)) THEN
  172.                 ActiveShade = 1
  173.             END IF
  174.         END IF
  175.         IF (_MOUSEWHEEL = 1) THEN
  176.             ActiveShade = ActiveShade - 1
  177.             IF (ActiveShade < 1) THEN
  178.                 ActiveShade = UBOUND(ShadeData)
  179.             END IF
  180.         END IF
  181.     LOOP
  182.         CASE ASC("e"), ASC("E")
  183.             CALL Export
  184.         CASE 27
  185.             FOR i = 1 TO GridSize.x
  186.                 FOR j = 1 TO GridSize.y
  187.                     Level(i, j).shadered = 0
  188.                     Level(i, j).shadegreen = 0
  189.                     Level(i, j).shadeblue = 0
  190.                     Level(i, j).shadealpha = 0
  191.                 NEXT
  192.             NEXT
  193.     END SELECT
  194.  
  195. SUB Export
  196.     DIM i AS INTEGER
  197.     DIM j AS INTEGER
  198.     OPEN "FluidCraft" + LTRIM$(RTRIM$(STR$(INT(TIMER)))) + ".txt" FOR OUTPUT AS #1
  199.     FOR i = 1 TO UBOUND(Level, 1)
  200.         FOR j = 1 TO UBOUND(Level, 2)
  201.             PRINT #1, i, j, Level(i, j).shadered, Level(i, j).shadegreen, Level(i, j).shadeblue, Level(i, j).shadealpha
  202.         NEXT
  203.     NEXT
  204.     CLOSE #1
  205.  
  206. SUB Dynamics
  207.     DIM k AS INTEGER
  208.     FOR k = 1 TO UBOUND(PixelCloud)
  209.         CALL CalculateInfluence(k)
  210.         CALL UpdatePosition(k)
  211.     NEXT
  212.  
  213. SUB UpdatePosition (i AS INTEGER)
  214.     DIM dt AS DOUBLE
  215.     DIM damp AS DOUBLE
  216.     DIM brownian AS DOUBLE
  217.     dt = 1
  218.     damp = 0.8 '.1 '0.5 '.25
  219.     brownian = .5 '1 'PixelCloud(i).size / 4 '1 '.525
  220.     PixelCloud(i).velocity.x = damp * PixelCloud(i).velocity.x + dt * PixelCloud(i).acceleration.x
  221.     PixelCloud(i).velocity.y = damp * PixelCloud(i).velocity.y + dt * PixelCloud(i).acceleration.y
  222.     PixelCloud(i).position.x = PixelCloud(i).position.x + dt * PixelCloud(i).velocity.x + (RND - .5) * brownian
  223.     PixelCloud(i).position.y = PixelCloud(i).position.y + dt * PixelCloud(i).velocity.y + (RND - .5) * brownian
  224.     IF (PixelCloud(i).position.y <= -_HEIGHT / 2 + 2 * PixelCloud(i).size + 1) THEN
  225.         PixelCloud(i).position.y = _HEIGHT / 2 - 2 * PixelCloud(i).size
  226.     END IF
  227.  
  228. SUB CalculateInfluence (i AS INTEGER)
  229.     DIM x AS DOUBLE
  230.     DIM y AS DOUBLE
  231.     DIM dx AS DOUBLE
  232.     DIM dy AS DOUBLE
  233.     DIM xr AS DOUBLE
  234.     DIM yr AS DOUBLE
  235.     DIM xg AS DOUBLE
  236.     DIM yg AS DOUBLE
  237.     DIM xb AS DOUBLE
  238.     DIM yb AS DOUBLE
  239.     DIM WPoint(9) AS _UNSIGNED LONG
  240.     DIM WRed(9) AS DOUBLE
  241.     DIM WGreen(9) AS DOUBLE
  242.     DIM WBlue(9) AS DOUBLE
  243.     x = PixelCloud(i).position.x
  244.     y = PixelCloud(i).position.y
  245.     dx = 2 * PixelCloud(i).size
  246.     dy = 2 * PixelCloud(i).size
  247.     WPoint(7) = cpoint(x - dx, y + dy)
  248.     WPoint(8) = cpoint(x, y + dy)
  249.     WPoint(9) = cpoint(x + dx, y + dy)
  250.     WPoint(4) = cpoint(x - dx, y)
  251.     WPoint(6) = cpoint(x + dx, y)
  252.     WPoint(1) = cpoint(x - dx, y - dy)
  253.     WPoint(2) = cpoint(x, y - dy)
  254.     WPoint(3) = cpoint(x + dx, y - dy)
  255.     WRed(7) = _RED32(WPoint(7)) * _ALPHA32(WPoint(7))
  256.     WRed(8) = _RED32(WPoint(8)) * _ALPHA32(WPoint(8))
  257.     WRed(9) = _RED32(WPoint(9)) * _ALPHA32(WPoint(9))
  258.     WRed(4) = _RED32(WPoint(4)) * _ALPHA32(WPoint(4))
  259.     'WRed(5) = 0
  260.     WRed(6) = _RED32(WPoint(6)) * _ALPHA32(WPoint(6))
  261.     WRed(1) = _RED32(WPoint(1)) * _ALPHA32(WPoint(1))
  262.     WRed(2) = _RED32(WPoint(2)) * _ALPHA32(WPoint(2))
  263.     WRed(3) = _RED32(WPoint(3)) * _ALPHA32(WPoint(3))
  264.     WGreen(7) = _GREEN32(WPoint(7)) * _ALPHA32(WPoint(7))
  265.     WGreen(8) = _GREEN32(WPoint(8)) * _ALPHA32(WPoint(8))
  266.     WGreen(9) = _GREEN32(WPoint(9)) * _ALPHA32(WPoint(9))
  267.     WGreen(4) = _GREEN32(WPoint(4)) * _ALPHA32(WPoint(4))
  268.     'WGreen(5) = 0
  269.     WGreen(6) = _GREEN32(WPoint(6)) * _ALPHA32(WPoint(6))
  270.     WGreen(1) = _GREEN32(WPoint(1)) * _ALPHA32(WPoint(1))
  271.     WGreen(2) = _GREEN32(WPoint(2)) * _ALPHA32(WPoint(2))
  272.     WGreen(3) = _GREEN32(WPoint(3)) * _ALPHA32(WPoint(3))
  273.     WBlue(7) = _BLUE32(WPoint(7)) * _ALPHA32(WPoint(7))
  274.     WBlue(8) = _BLUE32(WPoint(8)) * _ALPHA32(WPoint(8))
  275.     WBlue(9) = _BLUE32(WPoint(9)) * _ALPHA32(WPoint(9))
  276.     WBlue(4) = _BLUE32(WPoint(4)) * _ALPHA32(WPoint(4))
  277.     'WBlue(5) = 0
  278.     WBlue(6) = _BLUE32(WPoint(6)) * _ALPHA32(WPoint(6))
  279.     WBlue(1) = _BLUE32(WPoint(1)) * _ALPHA32(WPoint(1))
  280.     WBlue(2) = _BLUE32(WPoint(2)) * _ALPHA32(WPoint(2))
  281.     WBlue(3) = _BLUE32(WPoint(3)) * _ALPHA32(WPoint(3))
  282.  
  283.     xr = (WRed(6) - WRed(4) + (WRed(9) + WRed(3)) / SQR(2) - (WRed(7) + WRed(1)) / SQR(2))
  284.     yr = (WRed(8) - WRed(2) + (WRed(7) + WRed(9)) / SQR(2) - (WRed(1) + WRed(3)) / SQR(2))
  285.     xg = -(WGreen(6) - WGreen(4) + (WGreen(9) + WGreen(3)) / SQR(2) - (WGreen(7) + WGreen(1)) / SQR(2))
  286.     yg = (0 - WGreen(2) + (0 + 0) / SQR(2) - (WGreen(1) + WGreen(3)) / SQR(2))
  287.     xb = (WBlue(6) - WBlue(4) + (WBlue(9) + WBlue(3)) / SQR(2) - (WBlue(7) + WBlue(1)) / SQR(2))
  288.     yb = (WBlue(8) - WBlue(2) + (WBlue(7) + WBlue(9)) / SQR(2) - (WBlue(1) + WBlue(3)) / SQR(2))
  289.  
  290.     x = xr + xg + xb
  291.     y = yr + yg + yb
  292.  
  293.     '''
  294.     DIM k AS INTEGER
  295.     DIM WMixed(9) AS DOUBLE
  296.     DIM xc AS DOUBLE
  297.     DIM yc AS DOUBLE
  298.     DIM cs AS INTEGER
  299.     cs = 0
  300.  
  301.     ' yellow
  302.     xc = 0
  303.     yc = 0
  304.     FOR k = 1 TO 9
  305.         IF WRed(k) > 250 AND WGreen(k) > 250 AND WBlue(k) < 50 AND k <> 5 THEN
  306.             WMixed(k) = 255
  307.         ELSE
  308.             WMixed(k) = 0
  309.         END IF
  310.     NEXT
  311.     xc = (WMixed(6) - 0 + (WMixed(9) + WMixed(3)) / SQR(2) - (0 + 0) / SQR(2))
  312.     yc = -(WMixed(8) - WMixed(2) + (WMixed(7) + WMixed(9)) / SQR(2) - (WMixed(1) + WMixed(3)) / SQR(2))
  313.     IF xc <> 0 OR yc <> 0 THEN
  314.         cs = 1
  315.         x = xc
  316.         y = yc
  317.     END IF
  318.  
  319.     ' aqua
  320.     xc = 0
  321.     yc = 0
  322.     FOR k = 1 TO 9
  323.         IF WRed(k) < 50 AND WGreen(k) > 250 AND WBlue(k) > 250 AND k <> 5 THEN
  324.             WMixed(k) = 255
  325.         ELSE
  326.             WMixed(k) = 0
  327.         END IF
  328.     NEXT
  329.     xc = -(WMixed(6) - 0 + (WMixed(9) + WMixed(3)) / SQR(2) - (0 + 0) / SQR(2))
  330.     yc = -(WMixed(8) - WMixed(2) + (WMixed(7) + WMixed(9)) / SQR(2) - (WMixed(1) + WMixed(3)) / SQR(2))
  331.     IF xc <> 0 OR yc <> 0 THEN
  332.         cs = 1
  333.         x = xc
  334.         y = yc
  335.     END IF
  336.  
  337.     ' white
  338.     xc = 0
  339.     yc = 0
  340.     FOR k = 1 TO 9
  341.         IF WRed(k) >= 254 AND WGreen(k) >= 254 AND WBlue(k) >= 254 AND k <> 5 THEN
  342.             WMixed(k) = 255
  343.         ELSE
  344.             WMixed(k) = 0
  345.         END IF
  346.     NEXT
  347.     xc = -(WMixed(6) - WMixed(4) + (WMixed(9) + WMixed(3)) / SQR(2) - (WMixed(7) + WMixed(1)) / SQR(2))
  348.     yc = -(0 - WMixed(2) + (0 + 0) / SQR(2) - (WMixed(1) + WMixed(3)) / SQR(2))
  349.     IF xc <> 0 OR yc <> 0 THEN
  350.         cs = 1
  351.         x = xc
  352.         y = yc
  353.     END IF
  354.  
  355.  
  356.  
  357.  
  358.  
  359.     '''
  360.  
  361.     ' Particle conductivity
  362.     IF cs = 0 THEN
  363.         IF (((xr * xr + yr * yr) > (xb * xb + yb * yb)) AND (xr * xr + yr * yr > 16) AND (xg * xg + yg * yg < 16)) THEN
  364.             PixelCloud(i).TheShade.shadered = PixelCloud(i).TheShade.shadered + 64
  365.             IF (PixelCloud(i).TheShade.shadered >= 255) THEN PixelCloud(i).TheShade.shadered = 255
  366.             PixelCloud(i).TheShade.shadeblue = PixelCloud(i).TheShade.shadeblue - 64
  367.             IF (PixelCloud(i).TheShade.shadeblue <= 0) THEN PixelCloud(i).TheShade.shadeblue = 0
  368.         END IF
  369.  
  370.         IF ((xb * xb + yb * yb) > (xr * xr + yr * yr) AND (xg * xg + yg * yg < 16)) THEN
  371.             PixelCloud(i).TheShade.shadered = PixelCloud(i).TheShade.shadered - 64
  372.             IF (PixelCloud(i).TheShade.shadered <= 0) THEN PixelCloud(i).TheShade.shadered = 0
  373.             PixelCloud(i).TheShade.shadeblue = PixelCloud(i).TheShade.shadeblue + 64
  374.             IF (PixelCloud(i).TheShade.shadeblue >= 255) THEN PixelCloud(i).TheShade.shadeblue = 255
  375.         END IF
  376.     END IF
  377.  
  378.     ' Gravity or levity
  379.     y = y - (PixelCloud(i).TheShade.shadered - PixelCloud(i).TheShade.shadeblue) / 255
  380.  
  381.     ' Normalize acceleration
  382.     IF (ABS(x) < .001) THEN
  383.         PixelCloud(i).acceleration.x = 0
  384.     ELSE
  385.         PixelCloud(i).acceleration.x = -x / SQR(x * x + y * y)
  386.     END IF
  387.     IF (ABS(y) < .001) THEN
  388.         PixelCloud(i).acceleration.y = 0
  389.     ELSE
  390.         PixelCloud(i).acceleration.y = -y / SQR(x * x + y * y)
  391.     END IF
  392.  
  393.     ' Auto-cooling
  394.     PixelCloud(i).TheShade.shadered = PixelCloud(i).TheShade.shadered - 2
  395.     IF (PixelCloud(i).TheShade.shadered <= 0) THEN PixelCloud(i).TheShade.shadered = 0
  396.     PixelCloud(i).TheShade.shadeblue = PixelCloud(i).TheShade.shadeblue + 2
  397.     IF (PixelCloud(i).TheShade.shadeblue >= 255) THEN PixelCloud(i).TheShade.shadeblue = 255
  398.  
  399.  
  400. FUNCTION cpoint& (x1 AS DOUBLE, y1 AS DOUBLE)
  401.     DIM TheReturn AS _UNSIGNED LONG
  402.     TheReturn = POINT(_WIDTH / 2 + x1, -y1 + _HEIGHT / 2)
  403.     cpoint = TheReturn
  404.  
  405. SUB clinebf (x1 AS DOUBLE, y1 AS DOUBLE, x2 AS DOUBLE, y2 AS DOUBLE, col AS _UNSIGNED LONG)
  406.     LINE (_WIDTH / 2 + x1, -y1 + _HEIGHT / 2)-(_WIDTH / 2 + x2 - 0, -y2 + _HEIGHT / 2 + 0), col, BF
  407.  
  408. SUB slinebf (x1 AS DOUBLE, y1 AS DOUBLE, x2 AS DOUBLE, y2 AS DOUBLE, col AS _UNSIGNED LONG)
  409.     LINE (x1, y1)-(x2, y2), col, BF
  410.  
  411. SUB LoadFile
  412.     DIM i AS INTEGER
  413.     DIM j AS INTEGER
  414.     DIM r AS INTEGER
  415.     DIM g AS INTEGER
  416.     DIM b AS INTEGER
  417.     DIM a AS INTEGER
  418.     IF (COMMAND$ <> "") THEN
  419.         PRINT "Loading..."
  420.         OPEN COMMAND$ FOR INPUT AS #1
  421.         DO WHILE NOT EOF(1)
  422.             INPUT #1, i, j, r, g, b, a
  423.             Level(i, j).shadered = r
  424.             Level(i, j).shadegreen = g
  425.             Level(i, j).shadeblue = b
  426.             Level(i, j).shadealpha = a
  427.         LOOP
  428.         CLOSE #1
  429.     END IF
  430.  
* FluidCraft78191.txt (Filesize: 1.58 MB, Downloads: 128)
ss.png
* ss.png (Filesize: 53.64 KB, Dimensions: 1024x767, Views: 149)
« Last Edit: September 04, 2020, 09:57:57 pm by STxAxTIC »
You're not done when it works, you're done when it's right.

Marked as best answer by STxAxTIC on September 05, 2020, 05:38:49 pm

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: Emerging game: FluidCraft
« Reply #9 on: September 05, 2020, 09:38:44 pm »
Another mechanics overhaul - I have much better control over things now... And holy crap, the result was better than expected. I call this the plasma update. This one's for you @loudar - you were right about the red not being conductive enough.

Now the UI is different. The mouse pointer tells you which color is selected; right click to draw with that color. Right clicking will change the selected color to whatever was under the mouse. See top corner of the screen for available swatches. Mousewheel and mouse3 do nothing. Press ESC to clear all hand-drawn lines.

Color guide:
Red = heat source / barrier
Blue = cold source / barrier
Violet = (red + blue) = neutral barrier
Green = up only
Yellow = left only
Aqua = right only
White = down only

Code: QB64: [Select]
  1. _TITLE "FluidCraft"
  2. _DELAY .25
  3. SCREEN _NEWIMAGE(1024, 768, 32)
  4.  
  5. TYPE Vector
  6.     x AS DOUBLE
  7.     y AS DOUBLE
  8.  
  9. TYPE ShadeVector
  10.     shadered AS DOUBLE
  11.     shadegreen AS DOUBLE
  12.     shadeblue AS DOUBLE
  13.     shadealpha AS DOUBLE
  14.  
  15. TYPE ShadeElement
  16.     TheName AS STRING
  17.     TheShade AS ShadeVector
  18.  
  19. TYPE Pixel
  20.     position AS Vector
  21.     velocity AS Vector
  22.     acceleration AS Vector
  23.     size AS DOUBLE
  24.     TheShade AS ShadeVector
  25.  
  26. DIM SHARED ShadeData(8) AS ShadeElement
  27. DIM SHARED ActiveShade AS ShadeVector
  28. DIM SHARED PixelCloud(3000) AS Pixel
  29. DIM SHARED ObjectSize AS DOUBLE
  30. DIM SHARED GridSize AS Vector
  31. ObjectSize = 6
  32. GridSize.x = 1 + INT(_WIDTH / ObjectSize)
  33. GridSize.y = 1 + INT(_HEIGHT / ObjectSize)
  34. DIM SHARED Level(GridSize.x, GridSize.y) AS ShadeVector
  35.  
  36. CALL InitializeAll
  37. CALL LoadFile
  38.     CALL UserInput
  39.     CLS
  40.     CALL DrawBorder
  41.     CALL DrawPixels
  42.     CALL DrawLevel
  43.     CALL Dynamics
  44.     CALL DrawOverlay
  45.     _DISPLAY
  46.     _LIMIT 30
  47.  
  48.  
  49. SUB DrawBorder
  50.     DIM k AS INTEGER
  51.     LINE (0, 0)-(_WIDTH, _HEIGHT), _RGB32(255, 0, 255, 255), BF
  52.     FOR k = 6 TO _HEIGHT - 1 - 6
  53.         LINE (6, k)-(_WIDTH - 6, k), _RGB32(255 * k / _HEIGHT, 0, 255 * (1 - k / _HEIGHT), 255)
  54.     NEXT
  55.     LINE (12, 12)-(_WIDTH - 12, _HEIGHT - 12), _RGB32(0, 0, 0, 255), BF
  56.     LINE (12, 12)-(18 * (UBOUND(ShadeData) + 1) - 1 + 6 + 12, 38 + 12), _RGB32(0, 0, 255, 255), BF
  57.     LINE (12, 12)-(18 * (UBOUND(ShadeData) + 1) - 1 + 6 + 6, 38 + 6), _RGB32(255, 0, 255, 255), BF
  58.     LINE (12, 12)-(18 * (UBOUND(ShadeData) + 1) - 1 + 6, 38), _RGB32(0, 0, 0, 255), BF
  59.  
  60. SUB DrawPixels
  61.     DIM k AS INTEGER
  62.     DIM x AS DOUBLE
  63.     DIM y AS DOUBLE
  64.     DIM s AS DOUBLE
  65.     FOR k = 1 TO UBOUND(PixelCloud)
  66.         x = PixelCloud(k).position.x
  67.         y = PixelCloud(k).position.y
  68.         s = PixelCloud(k).size
  69.         CALL clinebf(x - s, y - s, x + s, y + s, _RGBA(PixelCloud(k).TheShade.shadered, PixelCloud(k).TheShade.shadegreen, PixelCloud(k).TheShade.shadeblue, PixelCloud(k).TheShade.shadealpha))
  70.     NEXT
  71.  
  72. SUB DrawLevel
  73.     DIM i AS INTEGER
  74.     DIM j AS INTEGER
  75.     DIM x AS DOUBLE
  76.     DIM y AS DOUBLE
  77.     DIM s AS DOUBLE
  78.     s = ObjectSize
  79.     FOR i = 1 TO GridSize.x
  80.         FOR j = 1 TO GridSize.y
  81.             x = (i - 1) * s
  82.             y = (j - 1) * s
  83.             IF (Level(i, j).shadered > 5) OR (Level(i, j).shadegreen > 5) OR (Level(i, j).shadeblue > 5) THEN
  84.                 CALL slinebf(x - s / 2, y - s / 2, x + s / 2 - 1, y + s / 2 - 1, _RGBA(Level(i, j).shadered, Level(i, j).shadegreen, Level(i, j).shadeblue, Level(i, j).shadealpha))
  85.             END IF
  86.         NEXT
  87.     NEXT
  88.  
  89. SUB DrawOverlay
  90.     DIM k AS INTEGER
  91.     LINE (ObjectSize * INT(_MOUSEX / ObjectSize) - ObjectSize / 2 - 1, ObjectSize * INT(_MOUSEY / ObjectSize) - ObjectSize / 2 - 1)-(ObjectSize * INT(_MOUSEX / ObjectSize) + ObjectSize / 2 - 1 + 1, ObjectSize * INT(_MOUSEY / ObjectSize) + ObjectSize / 2 - 1 + 1), _RGBA(255, 255, 255, 255), B
  92.     LINE (ObjectSize * INT(_MOUSEX / ObjectSize) - ObjectSize / 2, ObjectSize * INT(_MOUSEY / ObjectSize) - ObjectSize / 2)-(ObjectSize * INT(_MOUSEX / ObjectSize) + ObjectSize / 2 - 1, ObjectSize * INT(_MOUSEY / ObjectSize) + ObjectSize / 2 - 1), _RGBA(ActiveShade.shadered, ActiveShade.shadegreen, ActiveShade.shadeblue, ActiveShade.shadealpha), BF
  93.     FOR k = 1 TO UBOUND(ShadeData)
  94.         LINE (18 * k + 1, 18)-(18 * (k + 1) - 1, 32), _RGB32(ShadeData(k).TheShade.shadered, ShadeData(k).TheShade.shadegreen, ShadeData(k).TheShade.shadeblue, ShadeData(k).TheShade.shadealpha), BF
  95.         LINE (18 * k + 1, 18)-(18 * (k + 1) - 1, 32), _RGB32(255, 255, 255, 255), B
  96.     NEXT
  97.  
  98. SUB InitializeAll
  99.     DIM k AS INTEGER
  100.     ShadeData(1).TheName = "Red"
  101.     ShadeData(1).TheShade.shadered = 255
  102.     ShadeData(1).TheShade.shadegreen = 0
  103.     ShadeData(1).TheShade.shadeblue = 0
  104.     ShadeData(1).TheShade.shadealpha = 255
  105.     ShadeData(2).TheName = "Blue"
  106.     ShadeData(2).TheShade.shadered = 0
  107.     ShadeData(2).TheShade.shadegreen = 0
  108.     ShadeData(2).TheShade.shadeblue = 255
  109.     ShadeData(2).TheShade.shadealpha = 255
  110.     ShadeData(3).TheName = "Green"
  111.     ShadeData(3).TheShade.shadered = 0
  112.     ShadeData(3).TheShade.shadegreen = 255
  113.     ShadeData(3).TheShade.shadeblue = 0
  114.     ShadeData(3).TheShade.shadealpha = 255
  115.     ShadeData(4).TheName = "White"
  116.     ShadeData(4).TheShade.shadered = 255
  117.     ShadeData(4).TheShade.shadegreen = 255
  118.     ShadeData(4).TheShade.shadeblue = 255
  119.     ShadeData(4).TheShade.shadealpha = 255
  120.     ShadeData(5).TheName = "Yellow"
  121.     ShadeData(5).TheShade.shadered = 255
  122.     ShadeData(5).TheShade.shadegreen = 255
  123.     ShadeData(5).TheShade.shadeblue = 0
  124.     ShadeData(5).TheShade.shadealpha = 255
  125.     ShadeData(6).TheName = "Aqua"
  126.     ShadeData(6).TheShade.shadered = 0
  127.     ShadeData(6).TheShade.shadegreen = 255
  128.     ShadeData(6).TheShade.shadeblue = 255
  129.     ShadeData(6).TheShade.shadealpha = 255
  130.     ShadeData(7).TheName = "Violet"
  131.     ShadeData(7).TheShade.shadered = 255
  132.     ShadeData(7).TheShade.shadegreen = 0
  133.     ShadeData(7).TheShade.shadeblue = 255
  134.     ShadeData(7).TheShade.shadealpha = 255
  135.     ShadeData(8).TheName = "Black"
  136.     ShadeData(8).TheShade.shadered = 0
  137.     ShadeData(8).TheShade.shadegreen = 0
  138.     ShadeData(8).TheShade.shadeblue = 0
  139.     ShadeData(8).TheShade.shadealpha = 255
  140.  
  141.     FOR k = 1 TO UBOUND(PixelCloud)
  142.         PixelCloud(k).size = 3
  143.         PixelCloud(k).acceleration.x = 0
  144.         PixelCloud(k).acceleration.y = 0
  145.         PixelCloud(k).velocity.x = 0
  146.         PixelCloud(k).velocity.y = 0
  147.         PixelCloud(k).position.x = (RND - .5) * _WIDTH * .8
  148.         PixelCloud(k).position.y = (RND - .5) * _HEIGHT * .8
  149.         CALL SetPixelShade(k, 0, 0, 255, 150)
  150.     NEXT
  151.  
  152.     ActiveShade.shadered = 255
  153.     ActiveShade.shadegreen = 0
  154.     ActiveShade.shadeblue = 0
  155.     ActiveShade.shadealpha = 255
  156.  
  157.  
  158. SUB SetPixelShade (i AS INTEGER, r AS INTEGER, g AS INTEGER, b AS INTEGER, a AS INTEGER)
  159.     PixelCloud(i).TheShade.shadered = r
  160.     PixelCloud(i).TheShade.shadegreen = g
  161.     PixelCloud(i).TheShade.shadeblue = b
  162.     PixelCloud(i).TheShade.shadealpha = a
  163.  
  164. SUB UserInput
  165.     DIM mb1 AS INTEGER
  166.     DIM mb2 AS INTEGER
  167.     DIM mb3 AS INTEGER
  168.     DIM i AS INTEGER
  169.     DIM j AS INTEGER
  170.     DIM k AS INTEGER
  171.     mb1 = 0
  172.     mb2 = 0
  173.     mb3 = 0
  174.         IF (_MOUSEBUTTON(1) = -1) AND (mb1 <> 1) THEN
  175.             mb1 = -1
  176.             i = 1 + INT(_MOUSEX / ObjectSize)
  177.             j = 1 + INT(_MOUSEY / ObjectSize)
  178.             Level(i, j).shadered = ActiveShade.shadered
  179.             Level(i, j).shadegreen = ActiveShade.shadegreen
  180.             Level(i, j).shadeblue = ActiveShade.shadeblue
  181.             Level(i, j).shadealpha = ActiveShade.shadealpha
  182.         END IF
  183.         IF ((_MOUSEBUTTON(2) = -1) AND (mb2 <> -1)) THEN
  184.             mb2 = -1
  185.             i = ObjectSize * INT(_MOUSEX / ObjectSize)
  186.             j = ObjectSize * INT(_MOUSEY / ObjectSize)
  187.             ActiveShade.shadered = _RED32(POINT(i, j))
  188.             ActiveShade.shadegreen = _GREEN32(POINT(i, j))
  189.             ActiveShade.shadeblue = _BLUE32(POINT(i, j))
  190.             ActiveShade.shadealpha = _ALPHA32(POINT(i, j))
  191.         END IF
  192.     LOOP
  193.         CASE ASC("e"), ASC("E")
  194.             CALL Export
  195.         CASE ASC("r"), ASC("R")
  196.             FOR k = 1 TO UBOUND(PixelCloud)
  197.                 PixelCloud(k).TheShade.shadered = 255
  198.                 PixelCloud(k).TheShade.shadegreen = 0
  199.                 PixelCloud(k).TheShade.shadeblue = 0
  200.             NEXT
  201.         CASE ASC("b"), ASC("B")
  202.             FOR k = 1 TO UBOUND(PixelCloud)
  203.                 PixelCloud(k).TheShade.shadered = 0
  204.                 PixelCloud(k).TheShade.shadegreen = 0
  205.                 PixelCloud(k).TheShade.shadeblue = 255
  206.             NEXT
  207.         CASE ASC("0")
  208.             FOR k = 1 TO UBOUND(PixelCloud)
  209.                 PixelCloud(k).position.x = (RND - .5) * _WIDTH * .8
  210.                 PixelCloud(k).position.y = (RND - .5) * _HEIGHT * .8
  211.             NEXT
  212.         CASE 27
  213.             FOR i = 1 TO GridSize.x
  214.                 FOR j = 1 TO GridSize.y
  215.                     Level(i, j).shadered = 0
  216.                     Level(i, j).shadegreen = 0
  217.                     Level(i, j).shadeblue = 0
  218.                     Level(i, j).shadealpha = 0
  219.                 NEXT
  220.             NEXT
  221.     END SELECT
  222.     'DO WHILE _MOUSEINPUT: LOOP
  223.  
  224. SUB Export
  225.     DIM i AS INTEGER
  226.     DIM j AS INTEGER
  227.     OPEN "FluidCraft" + LTRIM$(RTRIM$(STR$(INT(TIMER)))) + ".txt" FOR OUTPUT AS #1
  228.     FOR i = 1 TO UBOUND(Level, 1)
  229.         FOR j = 1 TO UBOUND(Level, 2)
  230.             PRINT #1, i, j, Level(i, j).shadered, Level(i, j).shadegreen, Level(i, j).shadeblue, Level(i, j).shadealpha
  231.         NEXT
  232.     NEXT
  233.     CLOSE #1
  234.  
  235. SUB Dynamics
  236.     DIM k AS INTEGER
  237.     FOR k = 1 TO UBOUND(PixelCloud)
  238.         CALL CalculateInfluence(k)
  239.         CALL UpdatePosition(k)
  240.     NEXT
  241.  
  242. SUB UpdatePosition (i AS INTEGER)
  243.     DIM dt AS DOUBLE
  244.     DIM damp AS DOUBLE
  245.     DIM brownian AS DOUBLE
  246.     dt = 1
  247.     damp = 0.8 '.1 '0.5 '.25
  248.     brownian = .65 '1 'PixelCloud(i).size / 4 '1 '.525
  249.     PixelCloud(i).velocity.x = damp * PixelCloud(i).velocity.x + dt * PixelCloud(i).acceleration.x
  250.     PixelCloud(i).velocity.y = damp * PixelCloud(i).velocity.y + dt * PixelCloud(i).acceleration.y
  251.     PixelCloud(i).position.x = PixelCloud(i).position.x + dt * PixelCloud(i).velocity.x + (RND - .5) * brownian
  252.     PixelCloud(i).position.y = PixelCloud(i).position.y + dt * PixelCloud(i).velocity.y + (RND - .5) * brownian
  253.     IF (PixelCloud(i).position.y <= -_HEIGHT / 2 + 2 * PixelCloud(i).size + 1) THEN
  254.         PixelCloud(i).position.y = _HEIGHT / 2 - 2 * PixelCloud(i).size
  255.     END IF
  256.  
  257. SUB CalculateInfluence (i AS INTEGER)
  258.     DIM x AS DOUBLE
  259.     DIM y AS DOUBLE
  260.     DIM dx AS DOUBLE
  261.     DIM dy AS DOUBLE
  262.     DIM xr AS DOUBLE
  263.     DIM yr AS DOUBLE
  264.     DIM xg AS DOUBLE
  265.     DIM yg AS DOUBLE
  266.     DIM xb AS DOUBLE
  267.     DIM yb AS DOUBLE
  268.     DIM WPoint(9) AS _UNSIGNED LONG
  269.     x = PixelCloud(i).position.x
  270.     y = PixelCloud(i).position.y
  271.     dx = 2 * PixelCloud(i).size
  272.     dy = 2 * PixelCloud(i).size
  273.     WPoint(7) = cpoint(x - dx, y + dy)
  274.     WPoint(8) = cpoint(x, y + dy)
  275.     WPoint(9) = cpoint(x + dx, y + dy)
  276.     WPoint(4) = cpoint(x - dx, y)
  277.     WPoint(6) = cpoint(x + dx, y)
  278.     WPoint(1) = cpoint(x - dx, y - dy)
  279.     WPoint(2) = cpoint(x, y - dy)
  280.     WPoint(3) = cpoint(x + dx, y - dy)
  281.  
  282.     '''
  283.     DIM k AS INTEGER
  284.     DIM WShade(9) AS DOUBLE
  285.     DIM xc AS DOUBLE
  286.     DIM yc AS DOUBLE
  287.     DIM cs AS INTEGER
  288.     cs = 0
  289.     x = 0
  290.     y = 0
  291.  
  292.     ' red
  293.     FOR k = 1 TO 9
  294.         IF (k <> 5) THEN
  295.             IF ((_RED32(WPoint(k)) > 25) AND (_GREEN32(WPoint(k)) < 5) AND (_BLUE32(WPoint(k)) < 25)) THEN
  296.                 WShade(k) = _RED32(WPoint(k)) + _GREEN32(WPoint(k)) + _BLUE32(WPoint(k))
  297.             ELSE
  298.                 WShade(k) = 0
  299.             END IF
  300.         END IF
  301.     NEXT
  302.     xr = (WShade(6) - WShade(4) + (WShade(9) + WShade(3)) / SQR(2) - (WShade(7) + WShade(1)) / SQR(2))
  303.     yr = (WShade(8) - WShade(2) + (WShade(7) + WShade(9)) / SQR(2) - (WShade(1) + WShade(3)) / SQR(2))
  304.     x = x + xr
  305.     y = y + yr
  306.  
  307.     ' blue
  308.     FOR k = 1 TO 9
  309.         IF (k <> 5) THEN
  310.             IF ((_RED32(WPoint(k)) < 25) AND (_GREEN32(WPoint(k)) < 5) AND (_BLUE32(WPoint(k)) > 25)) THEN
  311.                 WShade(k) = _RED32(WPoint(k)) + _GREEN32(WPoint(k)) + _BLUE32(WPoint(k))
  312.             ELSE
  313.                 WShade(k) = 0
  314.             END IF
  315.         END IF
  316.     NEXT
  317.     xb = (WShade(6) - WShade(4) + (WShade(9) + WShade(3)) / SQR(2) - (WShade(7) + WShade(1)) / SQR(2))
  318.     yb = (WShade(8) - WShade(2) + (WShade(7) + WShade(9)) / SQR(2) - (WShade(1) + WShade(3)) / SQR(2))
  319.     x = x + xb
  320.     y = y + yb
  321.  
  322.     ' green
  323.     FOR k = 1 TO 9
  324.         IF (k <> 5) THEN
  325.             IF ((_RED32(WPoint(k)) < 5) AND (_GREEN32(WPoint(k)) > 250) AND (_BLUE32(WPoint(k)) < 5)) THEN
  326.                 WShade(k) = _RED32(WShade(k)) + _GREEN32(WPoint(k)) + _BLUE32(WPoint(k))
  327.                 cs = 1
  328.             ELSE
  329.                 WShade(k) = 0
  330.             END IF
  331.         END IF
  332.     NEXT
  333.     xg = -(WShade(6) - WShade(4) + (WShade(9) + WShade(3)) / SQR(2) - (WShade(7) + WShade(1)) / SQR(2))
  334.     yg = (0 - WShade(2) + (0 + 0) / SQR(2) - (WShade(1) + WShade(3)) / SQR(2))
  335.     x = x + xg
  336.     y = y + yg
  337.  
  338.     ' custom yellow
  339.     FOR k = 1 TO 9
  340.         IF (k <> 5) THEN
  341.             IF ((_RED32(WPoint(k)) > 250) AND (_GREEN32(WPoint(k)) > 250) AND (_BLUE32(WPoint(k)) < 5)) THEN
  342.                 WShade(k) = _RED32(WShade(k)) + _GREEN32(WPoint(k)) + _BLUE32(WPoint(k))
  343.                 cs = 1
  344.             ELSE
  345.                 WShade(k) = 0
  346.             END IF
  347.         END IF
  348.     NEXT
  349.     xc = (WShade(6) - 0 + (WShade(9) + WShade(3)) / SQR(2) - (0 + 0) / SQR(2))
  350.     yc = 0
  351.     x = x + xc
  352.     y = y + yc
  353.  
  354.     ' custom aqua
  355.     FOR k = 1 TO 9
  356.         IF (k <> 5) THEN
  357.             IF ((_RED32(WPoint(k)) < 5) AND (_GREEN32(WPoint(k)) > 250) AND (_BLUE32(WPoint(k)) > 250)) THEN
  358.                 WShade(k) = _RED32(WShade(k)) + _GREEN32(WPoint(k)) + _BLUE32(WPoint(k))
  359.                 cs = 1
  360.             ELSE
  361.                 WShade(k) = 0
  362.             END IF
  363.         END IF
  364.     NEXT
  365.     xc = -(WShade(6) - 0 + (WShade(9) + WShade(3)) / SQR(2) - (0 + 0) / SQR(2))
  366.     yc = 0
  367.     x = x + xc
  368.     y = y + yc
  369.  
  370.     ' custom white
  371.     FOR k = 1 TO 9
  372.         IF (k <> 5) THEN
  373.             IF ((_RED32(WPoint(k)) > 250) AND (_GREEN32(WPoint(k)) > 250) AND (_BLUE32(WPoint(k)) > 250)) THEN
  374.                 WShade(k) = _RED32(WShade(k)) + _GREEN32(WPoint(k)) + _BLUE32(WPoint(k))
  375.                 cs = 1
  376.             ELSE
  377.                 WShade(k) = 0
  378.             END IF
  379.         END IF
  380.     NEXT
  381.     xc = -(WShade(6) - WShade(4) + (WShade(9) + WShade(3)) / SQR(2) - (WShade(7) + WShade(1)) / SQR(2))
  382.     yc = -(0 - WShade(2) + (0 + 0) / SQR(2) - (WShade(1) + WShade(3)) / SQR(2))
  383.     x = x + xc
  384.     y = y + yc
  385.  
  386.     ' custom violet
  387.     FOR k = 1 TO 9
  388.         IF (k <> 5) THEN
  389.             IF ((_RED32(WPoint(k)) > 250) AND (_GREEN32(WPoint(k)) < 5) AND (_BLUE32(WPoint(k)) > 250)) THEN
  390.                 WShade(k) = _RED32(WShade(k)) + _GREEN32(WPoint(k)) + _BLUE32(WPoint(k))
  391.                 cs = 1
  392.             ELSE
  393.                 WShade(k) = 0
  394.             END IF
  395.         END IF
  396.     NEXT
  397.     xc = (WShade(6) - WShade(4) + (WShade(9) + WShade(3)) / SQR(2) - (WShade(7) + WShade(1)) / SQR(2))
  398.     yc = (WShade(8) - WShade(2) + (WShade(7) + WShade(9)) / SQR(2) - (WShade(1) + WShade(3)) / SQR(2))
  399.     x = x + xc
  400.     y = y + yc
  401.  
  402.  
  403.     ' Conductivity
  404.     IF (cs = 0) THEN
  405.         IF ((xr * xr + yr * yr) > (xb * xb + yb * yb)) THEN
  406.             PixelCloud(i).TheShade.shadered = PixelCloud(i).TheShade.shadered + 64
  407.             IF (PixelCloud(i).TheShade.shadered >= 255) THEN PixelCloud(i).TheShade.shadered = 255
  408.             PixelCloud(i).TheShade.shadeblue = PixelCloud(i).TheShade.shadeblue - 64
  409.             IF (PixelCloud(i).TheShade.shadeblue <= 0) THEN PixelCloud(i).TheShade.shadeblue = 0
  410.         END IF
  411.         IF ((xb * xb + yb * yb) > (xr * xr + yr * yr)) THEN
  412.             PixelCloud(i).TheShade.shadered = PixelCloud(i).TheShade.shadered - 64
  413.             IF (PixelCloud(i).TheShade.shadered <= 0) THEN PixelCloud(i).TheShade.shadered = 0
  414.             PixelCloud(i).TheShade.shadeblue = PixelCloud(i).TheShade.shadeblue + 64
  415.             IF (PixelCloud(i).TheShade.shadeblue >= 255) THEN PixelCloud(i).TheShade.shadeblue = 255
  416.         END IF
  417.     END IF
  418.  
  419.     ' Gravity or levity
  420.     IF (cs = 0) THEN
  421.         y = y - (PixelCloud(i).TheShade.shadered - PixelCloud(i).TheShade.shadeblue) / 255
  422.     END IF
  423.  
  424.     ' Normalize acceleration
  425.     IF (ABS(x) < .001) THEN
  426.         PixelCloud(i).acceleration.x = 0
  427.     ELSE
  428.         PixelCloud(i).acceleration.x = -x / SQR(x * x + y * y)
  429.     END IF
  430.     IF (ABS(y) < .001) THEN
  431.         PixelCloud(i).acceleration.y = 0
  432.     ELSE
  433.         PixelCloud(i).acceleration.y = -y / SQR(x * x + y * y)
  434.     END IF
  435.  
  436.     ' Auto-cooling
  437.     IF (cs = 0) THEN
  438.         PixelCloud(i).TheShade.shadered = PixelCloud(i).TheShade.shadered - 2
  439.         IF (PixelCloud(i).TheShade.shadered <= 0) THEN PixelCloud(i).TheShade.shadered = 0
  440.         PixelCloud(i).TheShade.shadeblue = PixelCloud(i).TheShade.shadeblue + 2
  441.         IF (PixelCloud(i).TheShade.shadeblue >= 255) THEN PixelCloud(i).TheShade.shadeblue = 255
  442.     END IF
  443.  
  444. FUNCTION cpoint& (x1 AS DOUBLE, y1 AS DOUBLE)
  445.     DIM TheReturn AS _UNSIGNED LONG
  446.     TheReturn = POINT(_WIDTH / 2 + x1, -y1 + _HEIGHT / 2)
  447.     cpoint = TheReturn
  448.  
  449. SUB clinebf (x1 AS DOUBLE, y1 AS DOUBLE, x2 AS DOUBLE, y2 AS DOUBLE, col AS _UNSIGNED LONG)
  450.     LINE (_WIDTH / 2 + x1, -y1 + _HEIGHT / 2)-(_WIDTH / 2 + x2 - 0, -y2 + _HEIGHT / 2 + 0), col, BF
  451.  
  452. SUB slinebf (x1 AS DOUBLE, y1 AS DOUBLE, x2 AS DOUBLE, y2 AS DOUBLE, col AS _UNSIGNED LONG)
  453.     LINE (x1, y1)-(x2, y2), col, BF
  454.  
  455. SUB cprintstring (y1 AS DOUBLE, a AS STRING)
  456.     _PRINTSTRING (_WIDTH / 2 - (LEN(a) * 8) / 2, -y1 + _HEIGHT / 2), a
  457.  
  458.  
  459. SUB LoadFile
  460.     DIM i AS INTEGER
  461.     DIM j AS INTEGER
  462.     DIM r AS INTEGER
  463.     DIM g AS INTEGER
  464.     DIM b AS INTEGER
  465.     DIM a AS INTEGER
  466.     IF (COMMAND$ <> "") THEN
  467.         PRINT "Loading..."
  468.         OPEN COMMAND$ FOR INPUT AS #1
  469.         DO WHILE NOT EOF(1)
  470.             INPUT #1, i, j, r, g, b, a
  471.             Level(i, j).shadered = r
  472.             Level(i, j).shadegreen = g
  473.             Level(i, j).shadeblue = b
  474.             Level(i, j).shadealpha = a
  475.         LOOP
  476.         CLOSE #1
  477.     END IF
  478.  
« Last Edit: September 05, 2020, 10:56:46 pm by STxAxTIC »
You're not done when it works, you're done when it's right.

Offline Dav

  • Forum Resident
  • Posts: 792
    • View Profile
Re: Emerging game: FluidCraft
« Reply #10 on: September 05, 2020, 10:47:22 pm »
I finally got around to trying this.  Wow - that's some top notch coding there!

- Dav
« Last Edit: September 05, 2020, 10:50:34 pm by Dav »

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: Emerging game: FluidCraft
« Reply #11 on: September 06, 2020, 12:59:05 pm »
Hi STxAxTIC

thanks to share this FluidCraft!
I find it very fine and impressive. Running on my Toshiba i3 4 GB ram I have just an issue on selecting color both using internal mousepad of notebook both using a wireless USB mouse. Rarely it changes color also if I point the color with mouse cursor in the panel of colors and I click right button of mouse.
Moreover I can draw on panel of colors...

Great app.
Programming isn't difficult, only it's  consuming time and coffee

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: Emerging game: FluidCraft
« Reply #12 on: September 06, 2020, 01:35:47 pm »
Thanks for your useful feedback TempodiBasic - the mouse stuff is still clunky and unfinished for sure. For now, I don't mind that we can draw over the borders, because sometimes we want to control what the border does instead rely on the default. What I would want to tackle during the `polishing' stage is the alignment of the border edges with the grid for drawing.

As for performance -  I knew this would be a thing eventually - I'm testing this on my new system, which in all probability is faster than any other machine testing this code, so I get the best view (a first for me). I tried it out on my old rig and it wasn't as impressive. Either knocking the particle number down from 3000 to like 2000 works, or also shrinking the overall window...
You're not done when it works, you're done when it's right.

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: Emerging game: FluidCraft
« Reply #13 on: September 06, 2020, 02:41:20 pm »
Hi STxAxTIC
I have found the glitch for my experience.
Your game starts with a specific dimensions screen that are not fitted into my notebook

adding this line of code before TYPE section I can catch the glitch
Code: QB64: [Select]

so now I can change the color of mouse if the little floating square in front of cursor of mouse is under the wanted color and I click with right button of mouse.

Moreover it is still possible for me to draw on borders of  Color change tool.

Also on my old notebook it runs quickly.
Thanks to share!
Programming isn't difficult, only it's  consuming time and coffee

Offline loudar

  • Newbie
  • Posts: 73
  • improve it bit by bit.
    • View Profile
Re: Emerging game: FluidCraft
« Reply #14 on: September 11, 2020, 08:12:58 am »
Hey @STxAxTIC! Thank you for the update, it's truly amazing...

One little thing again: The directional barriers seem to partly block the direction they should be letting through. If I have a white barrier and a mass on top and below, the particles above don't really push the ones below aside - so more gravity/mass might be interesting? I also thought about having heat particles not specifically move up, but just move faster than cold ones, eventually like molecules. If they would additionally have slight attraction to each other (like water) this could get really interesting. At the moment it's more simulating a gas/fluid state between hot/cold :D Just add air as invisible particles and add mass and density and you're good to go basically (I say "just"; I know this is a lot but if done right, what a simulation that would be!)
Check out what I do besides coding: http://loudar.myportfolio.com/