Create a structure to store the information about a marble:
/*
This structure stores the info related to a ball.
Its center (xPos, yPos)
Its velocity along both axes (dwVelX, dwVelY)
Its radius in pixels
*/
typedef struct _ballinfo
{
int xPos;
int yPos;
int dwVelX;
int dwVelY;
int radius;
} BALLINFO;
#define MAX_BALLS 3
//we’ll be bouncing 3 balls around here.
BALLINFO g_BallInfo[MAX_BALLS];
//to store the rects of each ball
RECT g_Rect[MAX_BALLS];
void InitializeData()
{
int radius = 22;
for (int i=0; i < MAX_BALLS; i++)
{
g_BallInfo[i].xPos = RandInt(radius, 216);
//switch on i to decide on yPos so that the balls dont overlap when they are created
switch(i)
{
//dividing the screen into 3 horizontal sections with one ball in each
case 0:
g_BallInfo[i].yPos = RandInt(radius, 100-radius);
break;
case 1:
g_BallInfo[i].yPos = RandInt(100+radius, 200-radius);
break;
case 2:
g_BallInfo[i].yPos = RandInt(200+radius, 300-radius);
break;
default:
g_BallInfo[i].yPos = RandInt(radius, 320-radius);
}
g_BallInfo[i].dwVelX = RandInt(-6, 6);
g_BallInfo[i].dwVelY = RandInt(-6, 6);
g_BallInfo[i].radius = radius;
printf("Ball %d details:\n", i+1);
printf("X=%d Y=%d VelX=%d VelY=%d\r\n", g_BallInfo[i].xPos, g_BallInfo[i].yPos,
g_BallInfo[i].dwVelX, g_BallInfo[i].dwVelY);
}
}
DWORD RandInt(DWORD low, DWORD high)
{
DWORD range = high – low;
DWORD num = Random() % range;
return (num + low);
}
Next, we look at the UpdateFrame() function:
static void UpdateFrame(HWND hWnd)
{
HRESULT hRet;
DDBLTFX ddbltfx;
int i = 0, j = 0;
memset(&ddbltfx, 0, sizeof(ddbltfx));
ddbltfx.dwSize = sizeof(ddbltfx);
ddbltfx.dwFillColor = 0;
ddbltfx.dwROP = SRCCOPY;
//clear the back buffer (color fil with black)
g_pDDSBack->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAITNOTBUSY, &ddbltfx);
for (i = 0; i < MAX_BALLS; i++)
{
g_Rect[i].top = g_BallInfo[i].yPos – 24;
g_Rect[i].left = g_BallInfo[i].xPos – 24;
g_Rect[i].bottom = g_BallInfo[i].yPos + 24;
g_Rect[i].right = g_BallInfo[i].xPos + 24;
}
ddbltfx.ddckSrcColorkey.dwColorSpaceLowValue = RGB(0, 0, 0);
ddbltfx.ddckSrcColorkey.dwColorSpaceHighValue = RGB(0, 0, 0);
//blt all the balls on the screen
for (i = 0; i<MAX_BALLS; i++)
{
while (TRUE)
{
hRet = g_pDDSBack->Blt(&g_Rect[i], g_pDDSOne, NULL, DDBLT_ROP | DDBLT_KEYSRCOVERRIDE, &ddbltfx);
if (hRet == DD_OK)
break;
if (hRet == DDERR_SURFACELOST)
{
hRet = RestoreAll();
if (hRet != DD_OK)
break;
}
if (hRet != DDERR_WASSTILLDRAWING)
break;
}
}
//update the balls positions and check for bounds
for (i = 0; i<MAX_BALLS; i++)
{
g_BallInfo[i].xPos = g_BallInfo[i].xPos + g_BallInfo[i].dwVelX;
g_BallInfo[i].yPos = g_BallInfo[i].yPos + g_BallInfo[i].dwVelY;
if(g_BallInfo[i].xPos <= 24)
{
g_BallInfo[i].xPos = 24;
g_BallInfo[i].dwVelX = -g_BallInfo[i].dwVelX;
}
if(g_BallInfo[i].xPos >= (240 – 24))
{
g_BallInfo[i].xPos = 240 – 24;
g_BallInfo[i].dwVelX = -g_BallInfo[i].dwVelX;
}
if(g_BallInfo[i].yPos <= 24)
{
g_BallInfo[i].yPos = 24;
g_BallInfo[i].dwVelY = -g_BallInfo[i].dwVelY;
}
if (g_BallInfo[i].yPos >= (320 – 24))
{
g_BallInfo[i].yPos = 320 – 24;
g_BallInfo[i].dwVelY = -g_BallInfo[i].dwVelY;
}
}
//check for collisions between all the balls
for (i = 0; i < MAX_BALLS-1; i++)
{
for (j = i+1; j < MAX_BALLS; j++)
{
if(Collision(&g_BallInfo[i], &g_BallInfo[j]))
{
printf("Balls HIT!\n");
CalculateNewVelocities(&g_BallInfo[i], &g_BallInfo[j]);
MessageBeep(MB_OK);
}
}
}
}
BOOL Collision(const BALLINFO *ball1, const BALLINFO *ball2)
{
int distance = 0, temp = 0;
int MinDistance = ball1->radius + ball2->radius;
//calculate the distance between the centers of the two balls
int dx = ball2->xPos – ball1->xPos;
int dy = ball2->yPos – ball1->yPos;
temp = dx*dx + dy*dy;
distance = sqrt(temp);
//printf("COLLISION: distance=%d, 2*R=%d\n", distance, MinDistance);
if(distance <= MinDistance)
{
return TRUE;
}
return FALSE;
}
void CalculateNewVelocities(BALLINFO *ball1, BALLINFO *ball2)
{
int ed = 1, mass1 = 20, mass2 = 20;
double velX1, velY1, velX2, velY2;
double dx = ball2->xPos – ball1->xPos;
double dy = ball2->yPos – ball1->yPos;
//calculate the distance between their centers
double distance = sqrt(dx*dx+dy*dy);
double vp1 = ball1->dwVelX*dx/distance + ball1->dwVelY*dy/distance;
double vp2 = ball2->dwVelX*dx/distance + ball2->dwVelY*dy/distance;
double dt = (ball1->radius + ball2->radius – distance)/(vp1 – vp2);
//printf("CENTERS BEFORE: X1=%d, Y1=%d X2=%d, Y2=%d\n", xPos1, yPos1, xPos2, yPos2);
//the centers of the ball when they actually collided
ball1->xPos = ball1->xPos – floor(ball1->dwVelX*dt + 0.5);
ball1->yPos = ball1->yPos – floor(ball1->dwVelY*dt + 0.5);
ball2->xPos = ball2->xPos – floor(ball2->dwVelX*dt + 0.5);
ball2->yPos = ball2->yPos – floor(ball2->dwVelY*dt + 0.5);
//now calulate the distance between centers (this should be very close to the sum of their radii)
dx = ball2->xPos – ball1->xPos;
dy = ball2->yPos – ball1->yPos;
distance = sqrt(dx*dx+dy*dy);
// Unit vector in the direction of the collision
double ax = dx/distance, ay=dy/distance;
// Projection of the velocities in these axes
double va1 = (ball1->dwVelX*ax + ball1->dwVelY*ay);
double vb1 = (-ball1->dwVelX*ay + ball1->dwVelY*ax);
double va2 = (ball2->dwVelX*ax + ball2->dwVelY*ay);
double vb2 = (-ball2->dwVelX*ay + ball2->dwVelY*ax);
// New velocities in these axes (after collision): ed<=1, for elastic collision ed=1
double vaP1 = va1 + (1+ed)*(va2-va1)/(1 + mass1/mass2);
double vaP2 = va2 + (1+ed)*(va1-va2)/(1 + mass2/mass1);
// Undo the projections
velX1 = vaP1*ax-vb1*ay; velY1 = vaP1*ay+vb1*ax;// new vx,vy for ball 1 after collision
velX2 = vaP2*ax-vb2*ay; velY2 = vaP2*ay+vb2*ax;// new vx,vy for ball 2 after collision
//printf("CENTERS AFTER: X1=%d, Y1=%d X2=%d, Y2=%d\n", xPos1, yPos1, xPos2, yPos2);
//printf("Old Vel: velX1=%d, velY1=%d velX2=%d, velY2=%d\n", dwVelX1, dwVelY1, dwVelX2, dwVelY2);
//new velocities of the balls
ball1->dwVelX = floor(velX1 + 0.5);
ball1->dwVelY = floor(velY1 + 0.5);
ball2->dwVelX = floor(velX2 + 0.5);
ball2->dwVelY = floor(velY2 + 0.5);
//undo the correction done before
ball1->xPos = ball1->xPos + floor(ball1->dwVelX*dt + 0.5);
ball1->yPos = ball1->yPos + floor(ball1->dwVelY*dt + 0.5);
ball2->xPos = ball2->xPos + floor(ball2->dwVelX*dt + 0.5);
ball2->yPos = ball2->yPos + floor(ball2->dwVelY*dt + 0.5);
//printf("New Vel: velX1=%d, velY1=%d velX2=%d, velY2=%d\n", dwVelX1, dwVelY1, dwVelX2, dwVelY2);
}