Author Topic: 2 Ball Collision with an itsy-bitsy-teeny-tiny little bit of trig  (Read 4571 times)

0 Members and 1 Guest are viewing this topic.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Code: QB64: [Select]
  1. '  Collision Study Mouse and Ball.bas for QB64 fork (B+=MGA) 2017-08-23
  2. 'updated from: Collision study mouse and ball.bas for QB64 fork (B+=MGA) trans 2017-08-20
  3. 'translated from "collision mouse study.bas"  SmallBASIC version 2017-01-10
  4. 'which was modify the yab version from six posts to one mouse
  5.  
  6. Const xmax = 800
  7. Const ymax = 600
  8. Screen _NewImage(xmax, ymax, 32)
  9. _Title "Collision Study: Mouse versus Ball - bplus"
  10.  
  11. Const RADIUS = 30 ' radius for both ball and angle
  12. Const SPEED = 5
  13. ba = _Pi(1 / 6) 'ball angle in radians
  14. bx = xmax / 2 'ball x
  15. by = ymax / 2 'ball y
  16.  
  17.  
  18.     Cls , _RGB(30, 70, 48)
  19.     If _KeyHit = 27 Then End 'pressed escape goodbye!
  20.  
  21.     'paddle px, py location
  22.     While _MouseInput: Wend  ' <<<<<<<<<< this code so old I had to fix this
  23.     px = _MouseX: py = _MouseY
  24.  
  25.     pbDistance = Sqr((px - bx) ^ 2 + (py - by) ^ 2)
  26.     'LOCATE 1, 1: PRINT px, py, pbDistance  'debug
  27.  
  28.     'show paddle
  29.     For i = RADIUS To 0 Step -1
  30.         Color _RGB(255 - i * 5, 0, 0)
  31.         CircleFill px, py, i
  32.     Next
  33.  
  34.     'update ball hit paddle
  35.     If Sqr((px - bx) ^ 2 + (py - by) ^ 2) < RADIUS * 2 Then ba = _Atan2(by - py, bx - px)
  36.  
  37.     'handle ball hit border
  38.     If bx < 0 + RADIUS Then ba = _Pi(1) - ba: bx = RADIUS
  39.     If bx > xmax - RADIUS Then ba = _Pi(1) - ba: bx = xmax - RADIUS
  40.     If by < 0 + RADIUS Then ba = -ba: by = RADIUS
  41.     If by > ymax - RADIUS Then ba = -ba: by = ymax - RADIUS
  42.  
  43.     'ball angle adjustments to keep between 0 and 2*pi
  44.     If ba > 2 * _Pi(1) Then ba = ba - _Pi(2)
  45.     If ba < 0 Then ba = ba + _Pi(2)
  46.  
  47.     'OK the ball is here
  48.     bx = bx + Cos(ba) * SPEED
  49.     by = by + Sin(ba) * SPEED
  50.  
  51.     'show ball
  52.     For i = RADIUS To 0 Step -1
  53.         Color _RGB(255 - i * 6, 255 - i * 6, 255 - i * 6)
  54.         CircleFill bx, by, i
  55.     Next
  56.  
  57.     'update screen and keep loops under 61 per second
  58.     _Display
  59.     _Limit 60
  60.  
  61. 'Steve McNeil's  copied from his forum
  62. Sub CircleFill (CX As Long, CY As Long, R As Long)
  63.     Dim subRADIUS As Long, RadiusError As Long
  64.     Dim X As Long, Y As Long
  65.  
  66.     subRADIUS = Abs(R)
  67.     RadiusError = -subRADIUS
  68.     X = subRADIUS
  69.     Y = 0
  70.  
  71.     If subRADIUS = 0 Then PSet (CX, CY): Exit Sub
  72.  
  73.     ' Draw the middle span here so we don't draw it twice in the main loop,
  74.     ' which would be a problem with blending turned on.
  75.     Line (CX - X, CY)-(CX + X, CY), , BF
  76.  
  77.     While X > Y
  78.         RadiusError = RadiusError + Y * 2 + 1
  79.         If RadiusError >= 0 Then
  80.             If X <> Y + 1 Then
  81.                 Line (CX - Y, CY - X)-(CX + Y, CY - X), , BF
  82.                 Line (CX - Y, CY + X)-(CX + Y, CY + X), , BF
  83.             End If
  84.             X = X - 1
  85.             RadiusError = RadiusError - X * 2
  86.         End If
  87.         Y = Y + 1
  88.         Line (CX - X, CY - Y)-(CX + X, CY - Y), , BF
  89.         Line (CX - X, CY + Y)-(CX + X, CY + Y), , BF
  90.     Wend
  91.  
  92.  
  93.  

« Last Edit: May 09, 2021, 02:19:42 am by bplus »

Offline johnno56

  • Forum Resident
  • Posts: 1270
  • Live long and prosper.
    • View Profile
Re: 2 Ball Collision with an itsy-bitsy-teeny-tiny little bit of trig
« Reply #1 on: May 09, 2021, 06:39:38 am »
I can prove that you are clairvoyant.... Can you guess my next question? lol
Logic is the beginning of wisdom.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: 2 Ball Collision with an itsy-bitsy-teeny-tiny little bit of trig
« Reply #2 on: May 09, 2021, 09:07:11 am »
I can prove that you are clairvoyant.... Can you guess my next question? lol

Does it come in Blue?
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Abacus

  • Newbie
  • Posts: 12
  • I like programming in QB64, C, & Python
    • View Profile
Re: 2 Ball Collision with an itsy-bitsy-teeny-tiny little bit of trig
« Reply #3 on: May 09, 2021, 10:13:14 am »
Very cool!
If obj1x% > obj2x% And obj1y% > obj2y% Then
    If obj1x% < obj2x% + tilewidth% And obj1y% < obj2y% + tilelength% Then Print: Print "collisoin"
End If

Offline justsomeguy

  • Newbie
  • Posts: 47
    • View Profile
Re: 2 Ball Collision with an itsy-bitsy-teeny-tiny little bit of trig
« Reply #4 on: May 09, 2021, 10:33:37 am »
Edit: http://kishimotostudios.com/articles/circle_collision/ has a very nice explanation on how it works

Very Nice!

May propose a small optimization? If you are looking for circle to circle collisions, there is a faster way and it does not involve square roots which are normally slower.

I borrowed this from my physics engine and it may be useful to you. I'm not sure about the mathamatics behind it but it works great.
Code: QB64: [Select]
  1. FUNCTION circleCircleCollision (cx1 AS SINGLE, cy1 AS SINGLE, radius1 AS SINGLE, cx2 AS SINGLE, cy2 AS SINGLE, radius2 AS SINGLE)
  2.     DIM AS SINGLE dx, dy, vlq, radius
  3.     dx = cx1 - cx2
  4.     dy = cy1 - cy2
  5.     vlq = dx * dx + dy * dy
  6.     radius = radius1 + radius2
  7.     circleCircleCollision = (vlq >= radius * radius)

I even made a little demo so that you can verify that it works.

Code: QB64: [Select]
  1. DIM h$(1): h$(0) = "Hit": h$(1) = "No Hit"
  2. DIM hs$
  3. _TITLE "Circle Collison Example"
  4. SCREEN _NEWIMAGE(800, 600, 32)
  5.  
  6. DIM AS SINGLE cx1, cy1, rad1, cx2, cy2, rad2
  7. cx1 = _WIDTH / 2
  8. cy1 = _HEIGHT / 2
  9. rad1 = 100
  10. rad2 = 50
  11.  
  12.     CLS
  13.         cx2 = _MOUSEX
  14.         cy2 = _MOUSEY
  15.         rad2 = rad2 + _MOUSEWHEEL
  16.     LOOP
  17.  
  18.     CIRCLE (cx1, cy1), rad1
  19.     CIRCLE (cx2, cy2), rad2
  20.  
  21.     hit = circleCircleCollision(cx1, cy1, rad1, cx2, cy2, rad2)
  22.     hs$ = h$(ABS(hit))
  23.     _PRINTSTRING (_WIDTH / 2 - (_PRINTWIDTH(hs$)) / 2, _HEIGHT * .75), hs$
  24.  
  25.     _DISPLAY
  26.     _LIMIT 60
  27.  
  28. FUNCTION circleCircleCollision (cx1 AS SINGLE, cy1 AS SINGLE, radius1 AS SINGLE, cx2 AS SINGLE, cy2 AS SINGLE, radius2 AS SINGLE)
  29.     DIM AS SINGLE dx, dy, vlq, radius
  30.     dx = cx1 - cx2
  31.     dy = cy1 - cy2
  32.     vlq = dx * dx + dy * dy
  33.     radius = radius1 + radius2
  34.     circleCircleCollision = (vlq >= radius * radius)


 
« Last Edit: May 09, 2021, 11:33:21 am by justsomeguy »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: 2 Ball Collision with an itsy-bitsy-teeny-tiny little bit of trig
« Reply #5 on: May 09, 2021, 12:38:17 pm »
Thanks guys,

@johnno56 coffee is ready now :)

@justsomeguy  yes I like loosing the SQR for distance calc, not really needed and I think x*x is better than x^2 as well. This gives me idea for further optimizing, I will experiment a little, thanks again.

PS this isn't really 2 ball collision, I realized after posting, but very handy for a game with a ball and paddle! I went on to Air Hockey after this study and a variation of Break-out with roundish paddle gives one more control of the angle of ball return.
« Last Edit: May 09, 2021, 02:28:11 pm by bplus »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: 2 Ball Collision with an itsy-bitsy-teeny-tiny little bit of trig
« Reply #6 on: May 10, 2021, 09:18:38 pm »
At the moment of collision when the 2 balls are kissing each other, you need the angle the one ball is to the other.

Using  ballRadianAngleBall2ToBall1 = _ATan2(ball2Y - ball1Y, ball2X - ball1X)
and    ballRadianAngleBall1ToBall2 = _ATan2(ball1Y - ball2Y, ball1X - ball2X)

The QB64 functions convert Degree To Radian units:  _D2R(degreeAngle)
           and complementary Radian To Degree units:  _R2D(RadianAngle)

Here is a demo to show ball angles to each other at moment of collision:
Code: QB64: [Select]
  1. _Title "Angle of Ball to each other at moment of collision, press any to move outer ball around inner" 'B+ 2021-05-10
  2. ' 2021-05-10  fixed arrow so points from base x,y To angle
  3.  
  4. Screen _NewImage(800, 600, 32)
  5. _Delay .25
  6. x1 = 400: y1 = 300 'at middle of screen
  7. '
  8. ' now take a known ball angle 45 degree ( so we can check it with the trig calc ) to that point South East
  9. ' lets say add 100 to x1, y1 for x2, y2
  10. x2 = 500: y2 = 400
  11.  
  12. ' now at what = radius will make the 2 balls kiss ( ie like at moment of collision so I can show trig comes up with 45 degrees)
  13. distanceBetweenCenters = Sqr((x1 - x2) ^ 2 + (y1 - y2) ^ 2)
  14. radiusForBothBalls = distanceBetweenCenters / 2
  15. 'now we can draw the balls
  16. Circle (x1, y1), radiusForBothBalls
  17. Circle (x2, y2), radiusForBothBalls
  18.  
  19. angleDegreesB2toB1 = _R2D(_Atan2(y2 - y1, x2 - x1))
  20. Print "angleDegreesB2toB1 "; angleDegreesB2toB1
  21. ArrowTo x1, y1, _D2R(angleDegreesB2toB1), 60, &HFFFFFF00
  22.  
  23.  
  24. angleDegreesB1toB2 = _R2D(_Atan2(y1 - y2, x1 - x2))
  25. Print "angleDegreesB1toB2 "; angleDegreesB1toB2
  26. ArrowTo x2, y2, _D2R(angleDegreesB1toB2), 60, &HFFFFFF00
  27.  
  28. 'OK now lets go around the clock
  29. a = _Pi(.25) ' 45 degrees
  30. radius = Sqr((400 - 500) ^ 2 + (300 - 400) ^ 2) ' move outer circle around inner every 5 degree
  31.     Cls
  32.     Print "Angle of outer ball to center of screen ="; Int(10000 * _R2D(a)) / 10000 mod 360  ' edit: to keep number in ball park
  33.     x2 = 400 + radius * Cos(a)
  34.     y2 = 300 + radius * Sin(a)
  35.     Circle (x1, y1), radiusForBothBalls
  36.     Circle (x2, y2), radiusForBothBalls
  37.  
  38.     angleDegreesB2toB1 = Int(10000 * _R2D(_Atan2(y2 - y1, x2 - x1))) / 10000
  39.     Print "angleDegreesB2toB1 "; angleDegreesB2toB1
  40.     ArrowTo x1, y1, _D2R(angleDegreesB2toB1), 60, &HFFFFFF00
  41.  
  42.     angleDegreesB1toB2 = Int(10000 * _R2D(_Atan2(y1 - y2, x1 - x2))) / 10000
  43.     Print "angleDegreesB1toB2 "; angleDegreesB1toB2
  44.     ArrowTo x2, y2, _D2R(angleDegreesB1toB2), 60, &HFFFFFF00
  45.     Sleep
  46.     a = a + _Pi(5 / 180)
  47.  
  48. Sub ArrowTo (BaseX As Long, BaseY As Long, rAngle As Double, lngth As Long, colr As _Unsigned Long)
  49.     Dim As Long x1, y1, x2, y2, x3, y3
  50.     x1 = BaseX + lngth * Cos(rAngle)
  51.     y1 = BaseY + lngth * Sin(rAngle)
  52.     x2 = BaseX + .8 * lngth * Cos(rAngle - _Pi(.05))
  53.     y2 = BaseY + .8 * lngth * Sin(rAngle - _Pi(.05))
  54.     x3 = BaseX + .8 * lngth * Cos(rAngle + _Pi(.05))
  55.     y3 = BaseY + .8 * lngth * Sin(rAngle + _Pi(.05))
  56.     Line (BaseX, BaseY)-(x1, y1), colr
  57.     Line (x1, y1)-(x2, y2), colr
  58.     Line (x1, y1)-(x3, y3), colr
  59.  

PS all that extra calc for Degree Angle was attempt to print nice numbers without a bunch of decimal junk, just using INT(DegreeAngle) was often 1 off of nice (advancing around circle 5 degrees at so 45, 50, 55,... was what was supposed to be showing).

You can use this method when ever you need to know the angle one point is to another.
« Last Edit: May 10, 2021, 11:32:45 pm by bplus »