Author Topic: Collision Study #4  (Read 3767 times)

0 Members and 1 Guest are viewing this topic.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Collision Study #4
« on: May 09, 2021, 07:55:36 pm »
This version seems to be working better than my last:

Code: QB64: [Select]
  1. _Title "Collision Study #4   press spacebar to toggle tracer" ' b+ 2021-05-09 by bplus
  2. ' from  "Collision Study #3 Brownian Motion 2018-03-31 by bplus (which was terrible idea of Brownian Motion)
  3. ' This time I want to bounce balls with the closest collision first (in case ball is coliidable with 2 or more others)
  4. ' PLUS this time I wont change current arrays of ball data but store into NextArray so all bounces are calc'd
  5. '      before any new drawing takes place.  YES! I think this works better.
  6. ' All radii are const for less calc, need balls different colored
  7.  
  8.  
  9. Const Xmax = 600 ' screen width
  10. Const Ymax = 600 ' screen height
  11. Const R = 50 '     balls radii
  12. Const Balls = 18 ' number of balls
  13. Type Ball
  14.     As Long x, y, rr, gg, bb ' screen location and RGB colors
  15.     As Double dx, dy ' dx, dy = change x, y axis
  16.  
  17. Screen _NewImage(Xmax, Ymax, 32)
  18. _Delay .25
  19. ' these can be static as no balls added or subtracted in closed system
  20. Dim As Ball b(1 To Balls), nf(1 To Balls) ' b() is current frame balls data , nf( ) is for next frame balls data
  21. Dim As Long clrMode, i, rad, j
  22. clrMode = 1
  23. For i = 1 To Balls
  24.     b(i).x = rand(R, Xmax - R)
  25.     b(i).y = rand(R, Ymax - R)
  26.     b(i).dx = Rnd * 4 + 1 * rdir
  27.     b(i).dy = Rnd * 4 + 1 * rdir
  28.     b(i).rr = rand%(180, 255)
  29.     b(i).gg = rand%(180, 255)
  30.     b(i).bb = rand%(180, 255)
  31.  
  32.     k$ = InKey$
  33.     If Len(k$) Then
  34.         If Asc(k$) = 32 Then clrMode = -1 * clrMode
  35.         If Asc(k$) = 27 And Len(k$) = 1 Then End
  36.     End If
  37.     If clrMode > 0 Then Cls
  38.  
  39.     For i = 1 To Balls ' draw balls then  update for next frame
  40.  
  41.         For rad = R To 1 Step -1
  42.             Color _RGB32(b(i).rr - rad / R * 150, b(i).gg - rad / R * 150, b(i).bb - rad / R * 150)
  43.             fcirc b(i).x, b(i).y, rad
  44.         Next
  45.  
  46.         ' check for collision
  47.         cd = 100000: saveJ = 0
  48.         For j = 1 To Balls 'find deepest collision
  49.             If i <> j Then
  50.                 dx = b(i).x - b(j).x: dy = b(i).y - b(j).y
  51.                 If dx * dx + dy * dy < (2 * R) * (2 * R) Then ' collision but is it first or deepest collision
  52.                     If R * R - dx * dx + dy * dy < cd Then cd = (2 * R) * (2 * R) - dx * dx + dy * dy: saveJ = j
  53.                 End If
  54.             End If
  55.         Next
  56.         If cd <> 100000 Then ' found collision change ball i dx, dy   calc new course for ball i
  57.             a = _Atan2(b(i).y - b(saveJ).y, b(i).x - b(saveJ).x)
  58.             power1 = (b(i).dx ^ 2 + b(i).dy ^ 2) ^ .5
  59.             power2 = (b(saveJ).dx ^ 2 + b(saveJ).dy ^ 2) ^ .5
  60.             power = (power1 + power2) / 2
  61.             nf(i).dx = power * Cos(a)
  62.             nf(i).dy = power * Sin(a)
  63.         Else ' no collision
  64.             nf(i).dx = b(i).dx
  65.             nf(i).dy = b(i).dy
  66.         End If
  67.         'update location of ball next frame
  68.         nf(i).x = b(i).x + nf(i).dx
  69.         nf(i).y = b(i).y + nf(i).dy
  70.  
  71.         ' check in bounds next frame
  72.         If nf(i).x < R Then nf(i).dx = -nf(i).dx: nf(i).x = R
  73.         If nf(i).x > Xmax - R Then nf(i).dx = -nf(i).dx: nf(i).x = Xmax - R
  74.         If nf(i).y < R Then nf(i).dy = -nf(i).dy: nf(i).y = R
  75.         If nf(i).y > Ymax - R Then nf(i).dy = -nf(i).dy: nf(i).y = Ymax - R
  76.     Next
  77.  
  78.     'now that we've gone through all old locations update b() with nf() data
  79.     For i = 1 To Balls
  80.         b(i).x = nf(i).x: b(i).y = nf(i).y
  81.         b(i).dx = nf(i).dx: b(i).dy = nf(i).dy
  82.     Next
  83.     ' next frame ready to draw
  84.     _Display
  85.     _Limit 60
  86.  
  87. Function rand% (lo As Integer, hi As Integer)
  88.     rand% = (Rnd * (hi - lo + 1)) \ 1 + lo
  89.  
  90. Function rdir ()
  91.     If Rnd < .5 Then rdir = -1 Else rdir = 1
  92.  
  93. 'Steve McNeil's  copied from his forum   note: Radius is too common a name
  94. Sub fcirc (CX As Long, CY As Long, R As Long)
  95.     Dim subRadius As Long, RadiusError As Long
  96.     Dim X As Long, Y As Long
  97.  
  98.     subRadius = Abs(R)
  99.     RadiusError = -subRadius
  100.     X = subRadius
  101.     Y = 0
  102.  
  103.     If subRadius = 0 Then PSet (CX, CY): Exit Sub
  104.  
  105.     ' Draw the middle span here so we don't draw it twice in the main loop,
  106.     ' which would be a problem with blending turned on.
  107.     Line (CX - X, CY)-(CX + X, CY), , BF
  108.  
  109.     While X > Y
  110.         RadiusError = RadiusError + Y * 2 + 1
  111.         If RadiusError >= 0 Then
  112.             If X <> Y + 1 Then
  113.                 Line (CX - Y, CY - X)-(CX + Y, CY - X), , BF
  114.                 Line (CX - Y, CY + X)-(CX + Y, CY + X), , BF
  115.             End If
  116.             X = X - 1
  117.             RadiusError = RadiusError - X * 2
  118.         End If
  119.         Y = Y + 1
  120.         Line (CX - X, CY - Y)-(CX + X, CY - Y), , BF
  121.         Line (CX - X, CY + Y)-(CX + X, CY + Y), , BF
  122.     Wend
  123.  
  124.  

Offline johnno56

  • Forum Resident
  • Posts: 1270
  • Live long and prosper.
    • View Profile
Re: Collision Study #4
« Reply #1 on: May 09, 2021, 09:06:20 pm »
Well... I am impressed... I think I spotted at least one blue ball in that demo... Well done!

I am curious. The fcirc() routine. Is this routine used, instead of the built-in paint() command, because of the minimal use of memory compared with a flodfill (paint) command or is there something else at play here? Just curious.

J
Logic is the beginning of wisdom.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Collision Study #4
« Reply #2 on: May 09, 2021, 09:16:19 pm »
Seems to work OK:
Code: QB64: [Select]
  1. _Title "Collision Study #4   press spacebar to toggle tracer" ' b+ 2021-05-09 by bplus
  2. ' from  "Collision Study #3 Brownian Motion 2018-03-31 by bplus (which was terrible idea of Brownian Motion)
  3. ' This time I want to bounce balls with the closest collision first (in case ball is coliidable with 2 or more others)
  4. ' PLUS this time I wont change current arrays of ball data but store into NextArray so all bounces are calc'd
  5. '      before any new drawing takes place.  YES! I think this works better.
  6. ' All radii are const for less calc, need balls different colored
  7.  
  8.  
  9. Const Xmax = 600 ' screen width
  10. Const Ymax = 600 ' screen height
  11. Const R = 50 '     balls radii
  12. Const Balls = 18 ' number of balls
  13. Type Ball
  14.     As Long x, y, rr, gg, bb ' screen location and RGB colors
  15.     As Double dx, dy ' dx, dy = change x, y axis
  16.  
  17. Screen _NewImage(Xmax, Ymax, 32)
  18. _Delay .25
  19. ' these can be static as no balls added or subtracted in closed system
  20. Dim As Ball b(1 To Balls), nf(1 To Balls) ' b() is current frame balls data , nf( ) is for next frame balls data
  21. Dim As Long clrMode, i, rad, j
  22. clrMode = 1
  23. For i = 1 To Balls
  24.     b(i).x = rand(R, Xmax - R)
  25.     b(i).y = rand(R, Ymax - R)
  26.     b(i).dx = Rnd * 4 + 1 * rdir
  27.     b(i).dy = Rnd * 4 + 1 * rdir
  28.     b(i).rr = rand%(180, 255)
  29.     b(i).gg = rand%(180, 255)
  30.     b(i).bb = rand%(180, 255)
  31.  
  32.     k$ = InKey$
  33.     If Len(k$) Then
  34.         If Asc(k$) = 32 Then clrMode = -1 * clrMode
  35.         If Asc(k$) = 27 And Len(k$) = 1 Then End
  36.     End If
  37.     If clrMode > 0 Then Cls
  38.  
  39.     For i = 1 To Balls ' draw balls then  update for next frame
  40.  
  41.         For rad = R To 1 Step -1
  42.             Color _RGB32(b(i).rr - rad / R * 150, b(i).gg - rad / R * 150, b(i).bb - rad / R * 150)
  43.             fcirc b(i).x, b(i).y, rad
  44.         Next
  45.  
  46.         ' check for collision
  47.         cd = 100000: saveJ = 0
  48.         For j = 1 To Balls 'find deepest collision
  49.             If i <> j Then
  50.                 dx = b(i).x - b(j).x: dy = b(i).y - b(j).y
  51.                 If dx * dx + dy * dy < (2 * R) * (2 * R) Then ' collision but is it first or deepest collision
  52.                     If R * R - dx * dx + dy * dy < cd Then cd = (2 * R) * (2 * R) - dx * dx + dy * dy: saveJ = j
  53.                 End If
  54.             End If
  55.         Next
  56.         If cd <> 100000 Then ' found collision change ball i dx, dy   calc new course for ball i
  57.             a = _Atan2(b(i).y - b(saveJ).y, b(i).x - b(saveJ).x)
  58.             power1 = (b(i).dx ^ 2 + b(i).dy ^ 2) ^ .5
  59.             power2 = (b(saveJ).dx ^ 2 + b(saveJ).dy ^ 2) ^ .5
  60.             power = (power1 + power2) / 2
  61.             nf(i).dx = power * Cos(a)
  62.             nf(i).dy = power * Sin(a)
  63.         Else ' no collision
  64.             nf(i).dx = b(i).dx
  65.             nf(i).dy = b(i).dy
  66.         End If
  67.         'update location of ball next frame
  68.         nf(i).x = b(i).x + nf(i).dx
  69.         nf(i).y = b(i).y + nf(i).dy
  70.  
  71.         ' check in bounds next frame
  72.         If nf(i).x < R Then nf(i).dx = -nf(i).dx: nf(i).x = R
  73.         If nf(i).x > Xmax - R Then nf(i).dx = -nf(i).dx: nf(i).x = Xmax - R
  74.         If nf(i).y < R Then nf(i).dy = -nf(i).dy: nf(i).y = R
  75.         If nf(i).y > Ymax - R Then nf(i).dy = -nf(i).dy: nf(i).y = Ymax - R
  76.     Next
  77.  
  78.     'now that we've gone through all old locations update b() with nf() data
  79.     For i = 1 To Balls
  80.         b(i).x = nf(i).x: b(i).y = nf(i).y
  81.         b(i).dx = nf(i).dx: b(i).dy = nf(i).dy
  82.     Next
  83.     ' next frame ready to draw
  84.     _Display
  85.     _Limit 60
  86.  
  87. Function rand% (lo As Integer, hi As Integer)
  88.     rand% = (Rnd * (hi - lo + 1)) \ 1 + lo
  89.  
  90. Function rdir ()
  91.     If Rnd < .5 Then rdir = -1 Else rdir = 1
  92.  
  93. Sub fcirc (CX As Long, CY As Long, R As Long)
  94.     Circle (CX, CY), R, _DefaultColor
  95.  

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Collision Study #4
« Reply #3 on: May 09, 2021, 09:28:18 pm »
Oh! change the limit to 200, you will see the difference between Circle Fill methods. The Paint fill wont keep up.

This is the balls when they have too much coffee ;-))
« Last Edit: May 09, 2021, 09:29:35 pm by bplus »

Offline _vince

  • Seasoned Forum Regular
  • Posts: 422
    • View Profile
Re: Collision Study #4
« Reply #4 on: May 09, 2021, 09:56:37 pm »
yes, that is the gold standard

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Collision Study #4
« Reply #5 on: May 09, 2021, 10:22:02 pm »
Found error in Collision detection and added constant to fix error and reduce Collision calculations a little:
Code: QB64: [Select]
  1. _Title "Collision Study #4   press spacebar to toggle tracer" ' b+ 2021-05-09 by bplus
  2. ' from  "Collision Study #3 Brownian Motion 2018-03-31 by bplus (which was terrible idea of Brownian Motion)
  3. ' This time I want to bounce balls with the closest collision first (in case ball is coliidable with 2 or more others)
  4. ' PLUS this time I wont change current arrays of ball data but store into NextArray so all bounces are calc'd
  5. '      before any new drawing takes place.  YES! I think this works better.
  6. ' All radii are const for less calc, need balls different colored
  7.  
  8.  
  9. Const Xmax = 1200 ' screen width
  10. Const Ymax = 600 ' screen height
  11. Const R = 50 '     balls radii
  12. Const R22 = R * R * 4 ' save some time with (2 * R) * (2 * R)
  13. Const Balls = 18 ' number of balls
  14. Type Ball
  15.     As Long x, y, rr, gg, bb ' screen location and RGB colors
  16.     As Double dx, dy ' dx, dy = change x, y axis
  17.  
  18. Screen _NewImage(Xmax, Ymax, 32)
  19. _Delay .25
  20. ' these can be static as no balls added or subtracted in closed system
  21. Dim As Ball b(1 To Balls), nf(1 To Balls) ' b() is current frame balls data , nf( ) is for next frame balls data
  22. Dim As Long clrMode, i, rad, j
  23. clrMode = 1
  24. For i = 1 To Balls
  25.     b(i).x = rand(R, Xmax - R)
  26.     b(i).y = rand(R, Ymax - R)
  27.     b(i).dx = Rnd * 4 + 1 * rdir
  28.     b(i).dy = Rnd * 4 + 1 * rdir
  29.     b(i).rr = rand%(180, 255)
  30.     b(i).gg = rand%(180, 255)
  31.     b(i).bb = rand%(180, 255)
  32.  
  33.     k$ = InKey$
  34.     If Len(k$) Then
  35.         If Asc(k$) = 32 Then clrMode = -1 * clrMode
  36.         If Asc(k$) = 27 And Len(k$) = 1 Then End
  37.     End If
  38.     If clrMode > 0 Then Cls
  39.  
  40.     For i = 1 To Balls ' draw balls then  update for next frame
  41.  
  42.         For rad = R To 1 Step -1
  43.             Color _RGB32(b(i).rr - rad / R * 150, b(i).gg - rad / R * 150, b(i).bb - rad / R * 150)
  44.             fcirc b(i).x, b(i).y, rad
  45.         Next
  46.  
  47.         ' check for collision
  48.         cd = 100000: saveJ = 0
  49.         For j = 1 To Balls 'find deepest collision
  50.             If i <> j Then
  51.                 dx = b(i).x - b(j).x: dy = b(i).y - b(j).y
  52.                 If dx * dx + dy * dy < R22 Then ' collision but is it first or deepest collision
  53.                     If R22 - dx * dx + dy * dy < cd Then cd = R22 - dx * dx + dy * dy: saveJ = j
  54.                 End If
  55.             End If
  56.         Next
  57.         If cd <> 100000 Then ' found collision change ball i dx, dy   calc new course for ball i
  58.             a = _Atan2(b(i).y - b(saveJ).y, b(i).x - b(saveJ).x)
  59.             power1 = (b(i).dx ^ 2 + b(i).dy ^ 2) ^ .5
  60.             power2 = (b(saveJ).dx ^ 2 + b(saveJ).dy ^ 2) ^ .5
  61.             power = (power1 + power2) / 2
  62.             nf(i).dx = power * Cos(a)
  63.             nf(i).dy = power * Sin(a)
  64.         Else ' no collision
  65.             nf(i).dx = b(i).dx
  66.             nf(i).dy = b(i).dy
  67.         End If
  68.         'update location of ball next frame
  69.         nf(i).x = b(i).x + nf(i).dx
  70.         nf(i).y = b(i).y + nf(i).dy
  71.  
  72.         ' check in bounds next frame
  73.         If nf(i).x < R Then nf(i).dx = -nf(i).dx: nf(i).x = R
  74.         If nf(i).x > Xmax - R Then nf(i).dx = -nf(i).dx: nf(i).x = Xmax - R
  75.         If nf(i).y < R Then nf(i).dy = -nf(i).dy: nf(i).y = R
  76.         If nf(i).y > Ymax - R Then nf(i).dy = -nf(i).dy: nf(i).y = Ymax - R
  77.     Next
  78.  
  79.     'now that we've gone through all old locations update b() with nf() data
  80.     For i = 1 To Balls
  81.         b(i).x = nf(i).x: b(i).y = nf(i).y
  82.         b(i).dx = nf(i).dx: b(i).dy = nf(i).dy
  83.     Next
  84.     ' next frame ready to draw
  85.     _Display
  86.     _Limit 60
  87.  
  88. Function rand% (lo As Integer, hi As Integer)
  89.     rand% = (Rnd * (hi - lo + 1)) \ 1 + lo
  90.  
  91. Function rdir ()
  92.     If Rnd < .5 Then rdir = -1 Else rdir = 1
  93.  
  94. 'Steve McNeil's  copied from his forum   note: Radius is too common a name
  95. Sub fcirc (CX As Long, CY As Long, R As Long)
  96.     Dim subRadius As Long, RadiusError As Long
  97.     Dim X As Long, Y As Long
  98.  
  99.     subRadius = Abs(R)
  100.     RadiusError = -subRadius
  101.     X = subRadius
  102.     Y = 0
  103.  
  104.     If subRadius = 0 Then PSet (CX, CY): Exit Sub
  105.  
  106.     ' Draw the middle span here so we don't draw it twice in the main loop,
  107.     ' which would be a problem with blending turned on.
  108.     Line (CX - X, CY)-(CX + X, CY), , BF
  109.  
  110.     While X > Y
  111.         RadiusError = RadiusError + Y * 2 + 1
  112.         If RadiusError >= 0 Then
  113.             If X <> Y + 1 Then
  114.                 Line (CX - Y, CY - X)-(CX + Y, CY - X), , BF
  115.                 Line (CX - Y, CY + X)-(CX + Y, CY + X), , BF
  116.             End If
  117.             X = X - 1
  118.             RadiusError = RadiusError - X * 2
  119.         End If
  120.         Y = Y + 1
  121.         Line (CX - X, CY - Y)-(CX + X, CY - Y), , BF
  122.         Line (CX - X, CY + Y)-(CX + X, CY + Y), , BF
  123.     Wend
  124.  
  125.