Collisions between circles, velocity, mass questions

David Janik-Jones forums at artspin.com
Sun Nov 14 22:24:21 EST 2004


I'm looking to finish a small game my son suggested but I'm stumped on  
code that will produce the effects I need. The two player game  
basically involves trying to knock the opponents "marble" out of the  
(square) playing area. This means I need to script each marble (WASD or  
arrow keys) to have a radius, mass and velocity. The collisions between  
marbles must be like billiard balls on a nearly frictionless surface.  
Mass means that the marbles can transfer energy and increase/decrease  
speed not only with a direction key held down, but also through the  
collisions.

Has anyone written any scripts like this?

I can code this in Basic as follows, but need to know the best way to  
do it in Revolution Dreamcard.

Here's how it might look in Basic (but with only one ball the player  
can control) ...

int numOfBalls=2  // Change to add marbles.  Just be sure to specify  
the starting position, mass, and radius for each marble.
int elasticity=0.5  // Elasticity is a value from 0 to 1: 0 will result  
in perfectly INELASTIC collisions (masses stick together), and a value  
of 1 will result in perfectly ELASTIC collisions

float X[numOfBalls],Y[numOfBalls]
float Vx[numOfBalls],Vy[numOfBalls]
float M[numOfBalls]
float radius[numOfBalls]

// INITIAL VALUES SECTION -- Make sure to add more for each ball you add

radius[0]=28    // Marble size
M[0]=25		// Marble mass
X[0]=100		// X coordinate
Y[0]=370		// Y coordinate

radius[1]=28
M[1]=25
X[1]=660
Y[1]=370

// GAME LOOP SECTION

int control
repeat
	int key=raw key scancode(keyboard raw key)
	
	// Controls
	if up then Vy[control]=Vy[control]-0.5 'all values started at 0.5
	if down then Vy[control]=Vy[control]+0.5
	if left then Vx[control]=Vx[control]-0.5
	if right then Vx[control]=Vx[control]+0.5
	
	if pressed(6) // z key slows down the velocities each frame
		int stopCount
		for stopCount=0 to numOfBalls-1
			Vx[stopCount]=Vx[stopCount]/1.1
			Vy[stopCount]=Vy[stopCount]/1.1
		next stopCount
	end if
	
	int a,b
	for a=0 to numOfBalls-1
		for b=0 to numOfBalls-1
			if b>a  // only check combinations that haven't been checked yet;  
for example, there's no need to check (0,1) and then (1,0).
				float xDiff=X[b]-X[a]
				float yDiff=-(Y[b]-Y[a])
				float distance=sqrt(xDiff^2+yDiff^2)
				
				if distance<radius[a]+radius[b]  'if marbles a and b are touching

					// find angle between marbles
					if xdiff>=0 then float diffdir= invtan(ydiff/xdiff)
					if xdiff<0 then float diffdir= invtan(ydiff/xdiff)+180
					
					float dVx=Vx[a]-Vx[b]
					float dVy=-(Vy[a]-Vy[b])
		
					float totVel=sqrt(dVx^2+dVy^2)
					
				if totVel>0
					if dVx>=0 then float veldir =invtan(dVy/dVx)
					if dVx<0 then float veldir = invtan(dVy/dVx)+180
					
					// the impulse is the amount of transferred momentum.  The impulse  
can only be transferred along the point of contact.
					float  
impulse=(1+elasticity)*(M[a]*M[b])/(M[a]+M[b])*totVel*cos(veldir- 
diffdir)
					
					float VxfA=-impulse*cos(diffdir)/M[a]+Vx[a]
					float VyfA=impulse*sin(diffdir)/M[a]+Vy[a]
					float VxfB=impulse*cos(diffdir)/M[b]+Vx[b]
					float VyfB=-impulse*sin(diffdir)/M[b]+Vy[b]

					Vx[a]=VxfA
					Vy[a]=VyfA
					Vx[b]=VxfB
					Vy[b]=VyfB
				end if
				
					float dX=(radius[a]+radius[b]-distance)/2*cos(diffdir)
					float dY=-((radius[a]+radius[b]-distance)/2*sin(diffdir))										
					X[a]=X[a]-dX
					Y[a]=Y[a]-dY
					X[b]=X[b]+dX
					Y[b]=Y[b]+dY
				end if
			end if
		next b
	next a
	
	float totalEnergy=0,totalMomentumX=0,totalMomentumY=0
	for a=0 to numOfBalls-1
		totalEnergy=totalEnergy+M[a]*(Vx[a]^2+Vy[a]^2)/2  //calculate the  
kinetic energy per ball, (1/2)*mass*velocity
		totalMomentumX=totalMomentumX+M[a]*Vx[a]   //momentum is mass*velocity
		totalMomentumY=totalMomentumY+M[a]*Vy[a]   //x momentum and y  
momentum can be calculated separately
		
		X[a]=X[a]+Vx[a]
		Y[a]=Y[a]+Vy[a]
		if X[a]>740  //768 field width - ball width
			X[a]=740
			Vx[a]=-abs(Vx[a])
		else if X[a]<28
			X[a]=28
			Vx[a]=abs(Vx[a])
		end if
		
		if Y[a]>740   //768 field width - ball width
			Y[a]=740
			Vy[a]=-abs(Vy[a])
		else if Y[a]<28
			Y[a]=28
			Vy[a]=abs(Vy[a])
		end if
		
		if a=control
			set pen color blue   //player controlled ball blue
		else
			set pen color yellow   //other balls yellow
		end if
		fill oval X[a]-radius[a],Y[a]-radius[a] to  
X[a]+radius[a],Y[a]+radius[a]
	next a
	
	draw frame
	
	// Clear the screen for the next frame
	int erase
	for erase=0 to numOfBalls-1
		set pen color white
		fill oval X[erase]-radius[erase],Y[erase]-radius[erase] to  
X[erase]+radius[erase],Y[erase]+radius[erase]
	next erase
until pressed(12)

All help appreciated,

David JJ

in my humble opinion | forums at artspin.com


More information about the use-livecode mailing list