FB II Compiler

PG PRO

Debugging

Memory

System

Mathematics

Resources

Disk I/O

Windows

Controls

Menus

Mouse

Keyboard

Text

Fonts

Drawing

Sound

Clipboard

Printing

Communication

ASM

Made with FB

MATHEMATICS

Calculate a rebound trajectory


FN BounceOnCollide below shows exactly how.

The program is optimised for accuracy, not speed. It could be greatly improved by replacing the slow floating point arithmetic by fixed point.

In many bouncing ball simulations you can get away with a quick and dirty bounce algorithm (just swap the velocity vectors), and this is also demonstrated.
COMPILE ,_dimmedvarsOnly
DIM RECORD ballRec
 DIM xP!, yP!, xV!, yV! ' position and velocity
DIM END RECORD .ballRec
DIM gRect.8, gCollideDistSq!
_bSize=170
END GLOBALS

LOCAL FN BounceOnCollide(b1Ptr&, b2Ptr&)
 'A bounce conserves x- and y-momentum, and also
 '  the energy (sum of the square of all velocity components)
 DIM sine!, cosine!, dV!, dVx!, dVy!, distSq!, dX!, dY!, hypotenuse!
 dX!=b1Ptr&.xP! - b2Ptr&.xP!
 dY!=b1Ptr&.yP! - b2Ptr&.yP!
 distSq!=dX!*dX!+dY!*dY!
 LONG IF distSq!< GCOLLIDEDISTSQ! ' collided
  LONG IF FN BUTTON
   hypotenuse!=SQR(dX!*dX! + dY!*dY!)
   ' calculate sin and cos of angle of the line between centres
   cosine!=dX!/hypotenuse!
   sine!=dY!/hypotenuse!
   dV!=(b1Ptr&.xV!-b2Ptr&.xV!)*cosine!+(b1Ptr&.yV!-b2Ptr&.yV!)*sine!
   dVx!=dV!*cosine!             ' x velocity change
   dVy!=dV!*sine!               ' y velocity change
   b1Ptr&.xV!=b1Ptr&.xV!-dVx!
   b2Ptr&.xV!=b2Ptr&.xV!+dVx!
   b1Ptr&.yV!=b1Ptr&.yV!-dVy!
   b2Ptr&.yV!=b2Ptr&.yV!+dVy!
  XELSE       ' quick and dirty
   SWAP b1Ptr&.xV!,b2Ptr&.xV!
   SWAP b1Ptr&.yV!,b2Ptr&.yV!
  END IF
  DIM energy!
  energy!=b1Ptr&.xV!^2+b2Ptr&.xV!^2+b1Ptr&.yV!^2+b2Ptr&.yV!^2
  CALL TEXTMODE(_srcCopy): COLOR=_zBlack: PRINT @(0,0) energy!
 END IF
END FN

LOCAL FN DrawBall(bPtr&,colour)
 DIM rect.8
 CALL SETRECT(rect,bPtr&.xP!,bPtr&.yP!,bPtr&.xP!+_bSize,bPtr&.yP!+_bSize)
 COLOR=colour: CALL FRAMEOVAL(rect)
END FN

LOCAL FN MoveBall(bPtr&,colour,otherBPtr&)
 FN DrawBall(bPtr&,_zWhite)     'erase
 bPtr&.xP!=bPtr&.xP!+bPtr&.xV!  ' new position
 bPtr&.yP!=bPtr&.yP!+bPtr&.yV!
 LONG IF bPtr&.xP! < gRect.left    'hit left wall
  bPtr&.xP!=gRect.left: bPtr&.xV!=-bPtr&.xV!
 END IF
 LONG IF bPtr&.xP! > gRect.right   'hit right
  bPtr&.xP!=gRect.right: bPtr&.xV!=-bPtr&.xV!
 END IF
 LONG IF bPtr&.yP! < GRECT.TOP     'hit top
  bPtr&.yP!=gRect.top: bPtr&.yV!=-bPtr&.yV!
 END IF
 LONG IF bPtr&.yP!>gRect.bottom  'hit bottom
  bPtr&.yP!=gRect.bottom: bPtr&.yV!=-bPtr&.yV!
 END IF
 FN BounceOnCollide(bPtr&, otherBPtr&)
 FN DrawBall(bPtr&,colour)      'redraw
END FN

WINDOW 1,"Bouncers (Cmd-. to end)",(0,0)-(630,420),_docNoGrow
DIM ball1.ballRec, ball2.ballRec, ticks&
gCollideDistSq!=_bSize*_bSize
CALL SETRECT(gRect,10,20,620,410)
CALL FRAMERECT (gRect)
PRINT@(20,0) "Press mouse button for best physics"
CALL INSETRECT(gRect,_bSize/2+1,_bSize/2+1)
CALL OFFSETRECT(gRect,-_bSize/2,-_bSize/2)
ball1.xP!=40:  ball1.yP!=50       ' initial positions
ball2.xP!=40+_bSize: ball2.yP!=50+15*_bSize/16
ball1.xV!=0.7 : ball1.yV!=3.7     'initial velocities
ball2.xV!=4.7: ball2.yV!=2.9
FN DrawBall(@ball1,_zRed)
FN DrawBall(@ball2,_zBlue)
DO
 CALL PENSIZE(4,4)
 ticks&=FN TICKCOUNT
 FN MoveBall(@ball1,_zRed,@ball2)
 FN MoveBall(@ball2,_zBlue,@ball1)
 HANDLEEVENTS
 DO
 UNTIL FN TICKCOUNT> ticks&
UNTIL 0
Robert