TGC Codebase Backup



Snooker / Pool / Billiards Physics by Hamish McHaggis

28th Jan 2004 15:59
Summary

Shows how to do realistic collision between billiard balls.



Description

Uses triganometry to bounce and speed up and slow down the balls as they fly around the table. Also works with the balls in close range like in a break. Turn the variable "numSteps" up if you find the balls dancing around each other (this would happen if you turned the speed up too much).



Code
                                    ` This code was downloaded from The Game Creators
                                    ` It is reproduced here with full permission
                                    ` http://www.thegamecreators.com
                                    
                                    `===================
` Pool Physics Demo
` By Joseph Thomson
` 24/01/04
`===================
`If you use any of this code in any way please give
`credit to me for the original code.


`Position data for balls
DATA 100,240
DATA 400,240
DATA 421,230,421,250
DATA 442,220,442,240,442,260
DATA 463,210,463,230,463,250,463,270
DATA 484,200,484,220,484,240,484,260,484,280
DATA 505,190,505,210,505,230,505,250,505,270,505,290

`Ball type with velocity and position
TYPE ballType
	xPos AS FLOAT
	yPos AS FLOAT
	
	xVel AS FLOAT
	yVel AS FLOAT
ENDTYPE

`Number of balls and ball radius
numBalls AS INTEGER = 16
ballRad AS INTEGER = 10

DIM balls(numBalls) AS ballType

GOSUB placeBalls

`Walls
topWall = 10
bottomWall = 470
leftWall = 10
rightWall = 630

`Increase for increased accuracy
numSteps AS INTEGER = 30
tableFriction AS FLOAT = 0.025
wallDecay AS FLOAT = 1.0

shotAng AS FLOAT
shotPower AS FLOAT
mouseHold AS INTEGER
mouseHoldX AS FLOAT
mouseHoldY AS FLOAT

dist AS FLOAT
angleBetween AS FLOAT
ang1 AS FLOAT
ang2 AS FLOAT
vel1 AS FLOAT
vel2 AS FLOAT
velX1 AS FLOAT
velX2 AS FLOAT
velY1 AS FLOAT
velY2 AS FLOAT
totalVel AS FLOAT

SYNC ON
SYNC RATE 60

DO
	`Draw walls
	INK RGB(255,255,255),0
	BOX leftWall-1,topWall-1,rightWall+1,bottomwall+1
	INK RGB(0,0,0),0
	BOX leftWall,topWall,rightWall,bottomwall

	`Do the movement of the balls and collision detection in steps, for increased accuracy
	FOR l=1 TO numSteps
		`Loop through all balls
		FOR x=1 TO numBalls
			`Move the ball
			INC balls(x).xPos,balls(x).xVel/numSteps
			INC balls(x).yPos,balls(x).yVel/numSteps
	
			`Control the shooting of the ball
			IF MOUSECLICK()=1
				IF mouseHold = 0
					mouseHold = 1
					mouseHoldX = MOUSEX()
					mouseHoldY = MOUSEY()
				ELSE
					shotPower = SQRT((mouseHoldX-MOUSEX())^2+(mouseHoldY-MOUSEY())^2)*0.2
					IF shotPower > 100.0 THEN shotPower = 100.0
					shotAng = 360-(180-ATANFULL(mouseHoldX-MOUSEX(),mouseHoldY-MOUSEY()))
				ENDIF
			ELSE
				IF MOUSECLICK()=0 AND mouseHold = 1
					mouseHold = 0
					balls(1).xVel=SIN(shotAng)*shotPower
					balls(1).yVel=COS(shotAng)*shotPower
				ENDIF
			ENDIF
	
			`Replace the balls if space is pressed
			IF SPACEKEY()=1
				GOSUB placeBalls
			ENDIF
	
			`Control balls' collision with walls (rebounding and energy loss)
			IF balls(x).xPos-ballRad < leftWall
				balls(x).xPos = leftWall+ballRad
				balls(x).xVel = -balls(x).xVel*wallDecay
			ENDIF
		
			IF balls(x).xPos+ballRad > rightWall
				balls(x).xPos = rightWall-ballRad
				balls(x).xVel = -balls(x).xVel*wallDecay
			ENDIF
		
			IF balls(x).yPos-ballRad < topWall
				balls(x).yPos = topWall+ballRad
				balls(x).yVel = -balls(x).yVel*wallDecay
			ENDIF
	
			IF balls(x).yPos+ballRad > bottomWall
				balls(x).yPos = bottomWall-ballRad
				balls(x).yVel = -balls(x).yVel*wallDecay
			ENDIF
	
			`Loop through all balls
			FOR y=1 TO numBalls
				`Don't check collision between the same ball
				IF y<>x
					`Get distance of balls from each other
					dist = SQRT((balls(x).xPos-balls(y).xPos)^2+(balls(x).yPos-balls(y).yPos)^2)
					
					`If they are touching
					IF dist < ballRad*2
						`Get the angle between them
						angleBetween = ATANFULL(balls(x).xPos-balls(y).xPos,balls(x).yPos-balls(y).yPos)
						
						`Move the first ball back where it was
						DEC balls(x).xPos,balls(x).xVel/numSteps
						DEC balls(x).yPos,balls(x).yVel/numSteps
	
						`Get the angles of the balls velocities
						ang1 = ATANFULL(balls(x).xVel,balls(x).yVel)
						ang2 = ATANFULL(balls(y).xVel,balls(y).yVel)
						`Get the speed of the balls velocities
						vel1 = SQRT(balls(x).xVel^2+balls(x).yVel^2)*0.9
						vel2 = SQRT(balls(y).xVel^2+balls(y).yVel^2)*0.9
						
						`Work out the new velocities of the balls using trig
						velX1 = SIN(angleBetween+90)*SIN(360-(angleBetween-ang1))*vel1+SIN(angleBetween)*COS(angleBetween-ang2)*vel2
						velY1 = COS(angleBetween+90)*SIN(360-(angleBetween-ang1))*vel1+COS(angleBetween)*COS(angleBetween-ang2)*vel2
						velX2 = SIN(angleBetween)*COS(angleBetween-ang1)*vel1+SIN(angleBetween+90)*SIN(360-(angleBetween-ang2))*vel2
						velY2 = COS(angleBetween)*COS(angleBetween-ang1)*vel1+COS(angleBetween+90)*SIN(360-(angleBetween-ang2))*vel2
						
						`Set the balls' velocities
						balls(x).xVel = velX1
						balls(x).yVel = velY1
						balls(y).xVel = velX2
						balls(y).yVel = velY2
					ENDIF
				ENDIF
			NEXT y

			`If the loop is on the last step...			
			IF l=numSteps
				`Draw graphics
				IF x=1
					INK RGB(255,255,0),0	
				ELSE
					INK RGB(255,255,255),0	
				ENDIF
	
				CIRCLE balls(x).xPos,balls(x).yPos,ballRad
				IF MOUSECLICK()=1 THEN LINE balls(1).xPos,balls(1).yPos,balls(1).xPos+SIN(shotAng)*shotPower*3,balls(1).yPos+COS(shotAng)*shotPower*3
	
				`Control ball friction
				totalVel = SQRT(balls(x).xVel^2+balls(x).xVel^2)
				DEC balls(x).xVel,tableFriction*totalVel*(balls(x).xVel/totalVel)
				DEC balls(x).yVel,tableFriction*totalVel*(balls(x).yVel/totalVel)
			ENDIF
		NEXT x
	NEXT l
		
	SYNC
	CLS
LOOP

`Replace the balls
placeBalls:
	RESTORE
	FOR p=1 TO numBalls
		READ balls(p).xPos
		READ balls(p).yPos
		balls(p).xVel = 0.0
		balls(p).yVel = 0.0
	NEXT p
RETURN