Author Topic: Boids Remake 2022-03  (Read 918 times)

0 Members and 1 Guest are viewing this topic.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Boids Remake 2022-03
« on: March 19, 2022, 08:47:11 pm »
With some great tips from tsh73 at LB here is a better version of Boids:
Code: QB64: [Select]
  1. _Title "Boids Remake 2022-03" ' b+ 2022-03-19
  2. ' from JB Boids Restart #6 Wings b+ 2022-03-19
  3.  
  4. Const xmax = 1200, ymax = 700, pi = _Pi, nb = 100, no = 7, np = 3
  5. Const green = _RGB32(0, 160, 0), blue = _RGB32(0, 0, 160), black = _RGB32(0, 0, 0), brown = _RGB32(100, 80, 40)
  6. Dim As Long done, headmode, centermode, i, j, testx, testy, iter
  7. Dim As Single hf, cf, t1, s, ao, dist
  8.  
  9. Dim As Single px(np), py(np), pa(np) ' Predator radius is const 10 or so, twice a bird at least
  10. Dim As Single ox(no), oy(no), ord(no) ' obstacle x, y, radius
  11. Dim As Single bx(nb), by(nb), ba(nb), da(nb, nb) ' new  da = distance array
  12. Dim As Long pw(np), bw(nb)
  13. headmode = 1 ' on / off
  14. hf = .3 ' % of 100 pixels distance .1 = 10
  15.  
  16. centermode = 0 ' on / off
  17. cf = .2 'centering factor how strong a pull from 0 to 1  .01 is week .1 pretty strong!
  18.  
  19. Screen _NewImage(xmax, ymax, 32)
  20. _ScreenMove 100, 20
  21.  
  22. For i = 1 To no ' in array for redraw
  23.     ox(i) = rand(90, xmax - 90): oy(i) = rand(90, ymax - 90): ord(i) = rand(25, 90)
  24. For i = 1 To nb
  25.     testAgain: ' don't start a bird inside an obstacle
  26.     testx = rand(20, xmax - 20) ' start random screen x, y away from borders
  27.     testy = rand(20, ymax - 20)
  28.     j = 0
  29.     While j < no ' note get strange results with For loop
  30.         j = j + 1
  31.         If distance(testx, testy, ox(j), oy(j)) < ord(j) + 10 Then GoTo testAgain
  32.     Wend
  33.     j = 0
  34.     While j < i - 1 'no bird crowds please  note get strange results with For loop
  35.         j = j + 1
  36.         If distance(testx, testy, bx(j), by(j)) < 15 Then GoTo testAgain
  37.     Wend
  38.     bx(i) = testx: by(i) = testy: ba(i) = 2 * pi * Rnd: bw(i) = Int(3 * Rnd) ' random headings
  39. For i = 1 To np ' might be smarter to pack the smaller after the larger, ie do predators before birds
  40.     testAgain2: ' don't start a predator inside an obstacle
  41.     testx = rand(40, xmax - 40) ' start random screen x, y away from borders
  42.     testy = rand(40, ymax - 40)
  43.     j = 0
  44.     While j < no ' note get strange results with For loop
  45.         j = j + 1
  46.         If distance(testx, testy, ox(j), oy(j)) < ord(j) + 10 Then GoTo testAgain2
  47.     Wend
  48.     j = 0
  49.     While j < nb ' give birds some space from predators too
  50.         j = j + 1
  51.         If distance(testx, testy, bx(j), by(j)) < 30 Then GoTo testAgain2
  52.     Wend
  53.     px(i) = testx: py(i) = testy: pa(i) = 2 * pi * Rnd: pw(i) = Int(5 * Rnd)
  54. t1 = Timer(.001)
  55. Color , green
  56. While _KeyDown(27) = 0
  57.     Cls
  58.     For i = 1 To no
  59.         fcirc ox(i), oy(i), ord(i), brown
  60.     Next
  61.     For i = 1 To nb - 1 ' find all the distances between birds
  62.         For j = i + 1 To nb ' fix bonehead error of doing this 2x's! thanks tsh73 for catch!
  63.             da(i, j) = distance(bx(i), by(i), bx(j), by(j))
  64.             da(j, i) = da(i, j) ' symetric relationship
  65.         Next
  66.     Next
  67.  
  68.     For i = 1 To np ' Predators are just like a birds
  69.         pw(i) = (1 + pw(i)) Mod 5 ' flapper wings or not
  70.         DrawBird px(i), py(i), 15, pa(i), pw(i), blue
  71.         s = Rnd * 4 + 3 ' get some bird separation here?
  72.         px(i) = px(i) + s * Cos(pa(i)): py(i) = py(i) + s * Sin(pa(i))
  73.         j = 0
  74.         While j < no ' note get strange results with For loop
  75.             j = j + 1
  76.             If distance(px(i), py(i), ox(j), oy(j)) < ord(j) + 23 Then
  77.                 ao = _Atan2(oy(j) - py(i), ox(j) - px(i))
  78.                 pa(i) = AngleAve(pa(i), ao - pi)
  79.             End If
  80.         Wend
  81.         ' JB&LB have better Mod function! tsh73 pointed it to me
  82.         px(i) = Mod2(px(i) + xmax, xmax)
  83.         py(i) = Mod2(py(i) + ymax, ymax)
  84.         ' except predators don't flock
  85.     Next
  86.  
  87.     For i = 1 To nb 'draw then update positions of birds
  88.         ' draw current
  89.         bw(i) = (bw(i) + 1) Mod 4 ' flapper wings or not
  90.         DrawBird bx(i), by(i), 8, ba(i), bw(i), black
  91.         s = rand(3, 7) ' get some bird separation here?
  92.         bx(i) = bx(i) + s * Cos(ba(i)): by(i) = by(i) + s * Sin(ba(i))
  93.         j = 0
  94.         While j < no ' note get strange results with For loop
  95.             j = j + 1
  96.             If distance(bx(i), by(i), ox(j), oy(j)) < ord(j) + 13 Then
  97.                 ao = _Atan2(oy(j) - by(i), ox(j) - bx(i))
  98.                 ba(i) = AngleAve(ba(i), ao - pi)
  99.             End If
  100.         Wend
  101.         j = 0
  102.         While j < np
  103.             j = j + 1
  104.             If distance(bx(i), by(i), px(j), py(j)) < 65 Then
  105.                 ao = _Atan2(py(j) - by(i), px(j) - bx(i))
  106.                 ba(i) = AngleAve(ba(i), ao - pi)
  107.             End If
  108.         Wend
  109.         ' JB&LB have better Mod function! tsh73 pointed it to me
  110.         bx(i) = Mod2(bx(i) + xmax, xmax)
  111.         by(i) = Mod2(by(i) + ymax, ymax)
  112.  
  113.         For j = i + 1 To nb
  114.             dist = da(i, j)
  115.             If dist < 50 Then ' birds are close enough to influence each other by visual
  116.                 'sway the neighbors headings towards each other
  117.                 If headmode And Rnd < hf Then
  118.                     ba(i) = AngleAve(ba(i), AngleAve(ba(i), ba(j)))
  119.                     ba(j) = AngleAve(ba(j), AngleAve(ba(i), ba(j)))
  120.                 End If
  121.             End If
  122.             If dist > 30 And dist < 100 Then
  123.                 'stickiness stay close to neighbors, close distance between
  124.                 If centermode And Rnd < cf Then
  125.                     bx(i) = bx(i) - cf / 10 * (bx(i) - bx(j))
  126.                     bx(j) = bx(j) + cf / 10 * (bx(i) - bx(j))
  127.                     by(i) = by(i) - cf / 10 * (by(i) - by(j))
  128.                     by(j) = by(j) + cf / 10 * (by(i) - by(j))
  129.                 End If
  130.             End If
  131.             If dist < 20 Then ' too close!!!
  132.                 bx(i) = bx(i) + .1 * (bx(i) - bx(j))
  133.                 bx(j) = bx(j) - .1 * (bx(i) - bx(j))
  134.                 by(i) = by(i) + .1 * (by(i) - by(j))
  135.                 by(j) = by(j) - .1 * (by(i) - by(j))
  136.             End If
  137.         Next 'j
  138.     Next ' i
  139.     _Display
  140.     _Limit 10
  141.  
  142. Function rand& (lo As Long, hi As Long) 'rand integer between lo and hi iclusive
  143.     rand& = Int((hi - lo + 1) * Rnd + lo)
  144.  
  145. Function distance (x1, y1, x2, y2) ' default single OK
  146.     distance = Sqr((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2))
  147.  
  148. Function AngleAve (ra1, ra2) ' default single OK
  149.     Dim twoPi, ray1, ray2, rtn
  150.     twoPi = pi * 2
  151.     ray1 = Mod2(ra1 + twoPi, twoPi)
  152.     ray2 = Mod2(ra2 + twoPi, twoPi)
  153.     rtn = (ray1 + ray2) / 2
  154.     If Abs(ray1 - ray2) > pi Then rtn = Mod2(rtn - pi + twoPi, twoPi)
  155.     AngleAve = rtn
  156.  
  157. Sub DrawBird (xc, yc, rr, ra, wings As Integer, c As _Unsigned Long)
  158.     Dim x1, y1, x2, y2, x3, y3
  159.     x1 = xc + rr * Cos(ra)
  160.     y1 = yc + rr * Sin(ra)
  161.     x2 = xc + rr * Cos(ra - .9 * pi)
  162.     y2 = yc + rr * Sin(ra - .9 * pi)
  163.     x3 = xc + rr * Cos(ra + .9 * pi)
  164.     y3 = yc + rr * Sin(ra + .9 * pi)
  165.     ftri x1, y1, xc, yc, x2, y2, c
  166.     ftri x1, y1, xc, yc, x3, y3, c
  167.     If wings Then
  168.         x2 = xc + 2 * rr * Cos(ra - 1.57 * pi)
  169.         y2 = yc + 2 * rr * Sin(ra - 1.57 * pi)
  170.         x3 = xc + 2 * rr * Cos(ra + 1.57 * pi)
  171.         y3 = yc + 2 * rr * Sin(ra + 1.57 * pi)
  172.         ftri xc, yc, x2, y2, x3, y3, c
  173.     End If
  174.  
  175. ' this allows us to do floats including negative floats
  176. Function Mod2# (n As Double, modulus As Double)
  177.     Dim rtn As Double
  178.     rtn = modulus * (Abs(n) / modulus - Int(Abs(n) / modulus))
  179.     If n < 0 Then rtn = -rtn
  180.     Mod2# = rtn
  181.  
  182. Sub fcirc (CX As Long, CY As Long, R As Long, C As _Unsigned Long)
  183.     Dim Radius As Long, RadiusError As Long
  184.     Dim X As Long, Y As Long
  185.     Radius = Abs(R): RadiusError = -Radius: X = Radius: Y = 0
  186.     If Radius = 0 Then PSet (CX, CY), C: Exit Sub
  187.     Line (CX - X, CY)-(CX + X, CY), C, BF
  188.     While X > Y
  189.         RadiusError = RadiusError + Y * 2 + 1
  190.         If RadiusError >= 0 Then
  191.             If X <> Y + 1 Then
  192.                 Line (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  193.                 Line (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  194.             End If
  195.             X = X - 1
  196.             RadiusError = RadiusError - X * 2
  197.         End If
  198.         Y = Y + 1
  199.         Line (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  200.         Line (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  201.     Wend
  202.  
  203. Sub ftri (x1, y1, x2, y2, x3, y3, K As _Unsigned Long)
  204.     Dim D As Long
  205.     Static a&
  206.     D = _Dest
  207.     If a& = 0 Then a& = _NewImage(1, 1, 32)
  208.     _Dest a&
  209.     _DontBlend a& '  '<<<< new 2019-12-16 fix
  210.     PSet (0, 0), K
  211.     _Blend a& '<<<< new 2019-12-16 fix
  212.     _Dest D
  213.     _MapTriangle _Seamless(0, 0)-(0, 0)-(0, 0), a& To(x1, y1)-(x2, y2)-(x3, y3)
  214.  
  215.  
Boids Remake 2022-03.PNG


EDIT: I had an FPS iteration counter but it wasn't working and I don't need it anyway for QB64.
« Last Edit: March 19, 2022, 09:05:19 pm by bplus »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Re: Boids Remake 2022-03
« Reply #1 on: March 19, 2022, 08:52:16 pm »
Thanks to Mod2#(n as double, modulus as double) I can do floats including negative which came in handy for AngleAve(ra1, ra2).

Code: QB64: [Select]
  1. ' this allows us to do floats including negative floats
  2. Function Mod2# (n As Double, modulus As Double)
  3.     Dim rtn As Double
  4.     rtn = modulus * (Abs(n) / modulus - Int(Abs(n) / modulus))
  5.     If n < 0 Then rtn = -rtn
  6.     Mod2# = rtn
  7.  

Turns out Mod of negative numbers is symmetric to 0.