Applications: Running an application when a specified event occurs

Recently, I saw a video by Jim Wilson on running applications at specific events. He used CeRunAppAtEvent() native api, from managed code, to register an application to run when the device wakes up. Lets look at the API,



BOOL CeRunAppAtEvent(TCHAR *pwszAppName, LONG lWhichEvent);

pwszAppName: string which specifies the name of the application to be started. This string can also specify a named event. In case of a named event, the event will be opened and signaled. The named event should be of the format:



"\\\\.\\Notofications\\NamedEvents\\Event Name"



"Event Name" is the application defined event name



lWhichEvent: Specifies the event at which the application has to be started, it can take the following values,

NOTIFICATION_EVENT_DEVICE_CHANGE

 A PC Card device changed.

NOTIFICATION_EVENT_INTERNET_PROXY_CHANGE

 The Internet Proxy used by the device has changed.

NOTIFICATION_EVENT_IR_DISCOVERED

 The device discovered a server by using infrared communications.

NOTIFICATION_EVENT_NET_CONNECT

 The device connected to a network.

NOTIFICATION_EVENT_NET_DISCONNECT

 The device disconnected from a network.

NOTIFICATION_EVENT_NONE

 No events occurred. Remove all event registrations for this application.

NOTIFICATION_EVENT_OFF_AC_POWER

 The user turned the alternating current (AC) power off.

NOTIFICATION_EVENT_ON_AC_POWER

 The user turned the AC power on.

NOTIFICATION_EVENT_RESTORE_END

 A full device data restore completed.

NOTIFICATION_EVENT_RNDIS_FN_DETECTED

 RNDISFN interface is instantiated.

NOTIFICATION_EVENT_RS232_DETECTED

 An RS232 connection was made.

NOTIFICATION_EVENT_SYNC_END

 Data synchronization finished.

NOTIFICATION_EVENT_TIME_CHANGE

 The system time changed.

NOTIFICATION_EVENT_TZ_CHANGE

 The time zone changed.

NOTIFICATION_EVENT_WAKEUP

 The device woke up.

 

NOTIFICATION_EVENT_NONE unregisters all the events associated with that application.

 

I have the following two functions,



void RegisterApp()

{

    BOOL ret;

    ret = CeRunAppAtEvent(TEXT("\\Windows\\BubbleBreaker.exe"), NOTIFICATION_EVENT_WAKEUP);

    if(!ret)

    {

        printf("RegisterApp:CeRunAppAtEvent failed, err:0x%x\r\n", GetLastError());

    }

}





void UnRegisterApp()

{

    BOOL ret;

    ret = CeRunAppAtEvent(TEXT("\\Windows\\BubbleBreaker.exe"), NOTIFICATION_EVENT_NONE);

    if(!ret)

    {

        printf("UnRegisterApp:CeRunAppAtEvent failed, err:0x%x\r\n", GetLastError());

    }

}

So, whenever the device wakes up from sleep, the BubbleBreaker game will start. To simulate a device sleep and wake up on the emulator, select File -> Save State and Exit from the Emulator menu. To wake the device up, select Tools -> Connect to Device… from Visual Studio (2005).

Here’s a video for you folks,

Skeletons of a game, DirectDraw, Part 12

If you are following this blog then you probably know that I have been itching to do some sort of a simple game. In this post I will explain the bare bones of simple game which I call "Crash Marbles".

 

The objectives of the game are simple,

 

1) Avoid contact with the evil marbles (Currently, the color of both the evil marbles and the protagonist marble is the same, I will change that soon)

 

2) Collect the Blue sapphire which appears randomly on the screen to score points

 

3) Every time you collect the blue sapphire you gain 10 points

 

4) And every time the evil marbles touch you, you lose 10 percent of your points. I initially coded for making you lose 20% of the points but I figured that the penalty is a bit too much and my score never went beyond 150. So I changed it to 10% (:

 

I am not going to explain the code here because there is hardly any new changes/logic in the code. The code is more or less the same as this post. You may also look here. What I am going to show you is, you guessed it, the video. So here comes:

The first video does not have audio, the background noise was too much so I mute the video.

 

 

Windows Mobile: “How Do I?” videos

There is a compilation of quite a few "How Do I?" videos related to windows mobile here. Take a look in your free time, some videos might be of interest to you.


Videos I liked:
How Do I: Use Bing inside a Windows Mobile Application?
How Do I: Create Localized Applications on Windows Mobile Devices?
How Do I: Use the GPS Intermediate Driver to Retrieve Location Information?
How Do I: Associate an Application with the Hardware Buttons on a Windows Mobile Device?
How Do I: Schedule an Application to Run at a Specific Time?
How Do I: Get an Application to Automatically Start When a Mobile Device Wakes Up?

Transparent Blitting, DirectDraw, Part 5

All this while, we have been blitting the spaceship image:

onto a black surface:

giving an image which looks like:

Thus giving an illusion that only the spaceship has been Blt on to the screen. But if our background was anything but black, things would look a lot different. For e.g. if our background was blue:

the resulting Blt() would have looked like this:

which, as you can see, is not very appealing to the eyes. Enter the concept of transparent blitting!

 

With transparent blitting, you can specify any arbitrary color, on the source surface or the destination surface or both, as a transparent color. So for e.g. in the above case we would specify the color BLACK on the source surface (the spaceship) as the transparent color. Therefore, when the spaceship is being Blt onto the destination surface, the color Black will be treated as transparent and the background will be preserved. So in short whenever the color black is encountered while Blting, its not Blt onto the destination surface, instead the Blue background color is displayed.

 

Color keys are used to specify which color you want to be treated as transparent. You can specify a range of colors to be transparent but, color ranges are not supported by HEL (Hardware Emulation Layer). Color keys can be specified:



1) While creating the surface

2) Calling SetColorKey() function explicitely on a surface

3) While Blting the surface

Color Keys are specified using the DDCOLORKEY structure. This structure has two DWORD members, dwColorSpaceLowValue and dwColorSpaceHighValue. Unless you are specifying a range of colors, both these values must be the same. If a surface is in palettized format then the color is specified as an index or a range of indices. If the surface’s pixel format is specified using a code then the color keys have to be specified using appropriate means like RGB(r, g, b) etc.





Color Keys while creating a surface

Assign the appropriate color values to ddckCKSrcBlt or ddckCKDestBlt members of the DDSURFACEDESC structure. Also, the dwFlags member must include DDSD_CKSRCBLT or DDSD_CKDESTBLT or both depending on whther you want to specify source color key, destination color key or both.



Using SetColorKey()

Another way to specify color keys is by calling SetColorKey() function on a surface directly. This function takes a pointer to DDCOLORKEY structure where you specify your color keys. In the dwFlags parameter you set either DDCKEY_SRCBLT or DDCKEY_DESTBLT or both to indicate whether you are setting a source color key or a destination color key or both.



While Bltting the surface

If the color keys for the surfaces you are bltting was already specified using one of the methods above then you just need to set the dwFlags parameter to DDBLT_KEYSRC or DDBLT_KEYDEST or both. Alternatively, if you want to override the color keys while blitting then you can specify the source and destination color keys by setting the ddckDestColorKey and ddckSrcColorKey members of the DDBLTFX structure, you will also need to specify DBLT_KEYSRCOVERRIDE or DBLT_KEYDESTOVERRIDE flags in the dwFlags parameter of the DDBLTFX structure.

 

In our UpdateFrame() function specify the color keys as:



    ddbltfx.ddckSrcColorkey.dwColorSpaceLowValue = RGB(0, 0, 0);

    ddbltfx.ddckSrcColorkey.dwColorSpaceHighValue = RGB(0, 0, 0);

Note that both the values are same. Here, the color black is specified as the source color key.

And the blitting,


        hRet = g_pDDSBack->Blt(&dest, g_pDDSOne, NULL, DDBLT_ROP | DDBLT_KEYSRCOVERRIDE, &ddbltfx);


The DDBLT_KEYSRCOVERRIDE flag is specified to use the color key from the ddbltfx structure.

 

So now when I Blit:

onto the same Blue surface, the resultant image is:

BallOnBlue

For more information on Transparent Blitting, take a look at MSDN.

Fun with menus!

I received a comment on one of my previous posts, correcting me on what I had mentioned. The menu bar resource was defined as below:



IDR_MENU SHMENUBAR DISCARDABLE

BEGIN

    IDR_MENU,

    2,



    I_IMAGENONE, IDM_OK, TBSTATE_ENABLED, TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE,

    IDS_OK, 0, NOMENU,

   

    I_IMAGENONE, IDM_HELP, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,

    IDS_HELP, 0, 0,

END

And I had said, "Everything in between BEGIN and END defines the menu bar. The first line under BEGIN should be the same as the menu bar identifier, IDR_MENU". Well, I was wrong there. The first line under BEGIN could be same as the menu bar identifier but it need not be. Thanks Binary for noticing that! The first line under BEGIN is the identifier of the popup menu that appears when the user clicks on one of the popup menus.  If both the softkeys in your menu bar are buttons then the popup menu identifier could be specified as zero. So the correct way of doing it would be to define the menu bar as:

IDR_MENU SHMENUBAR DISCARDABLE

BEGIN

    IDR_MENU_POPUP,

    2,



    I_IMAGENONE, IDM_OK, TBSTATE_ENABLED, TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE,

    IDS_OK, 0, NOMENU,

   

    I_IMAGENONE, IDM_HELP, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,

    IDS_HELP, 0, 0,

END

and IDR_MENU_POPUP is defined as a popup menu,

IDR_MENU_POPUP MENU

BEGIN

    POPUP ""

    BEGIN

        MENUITEM "System Metric",               IDM_SYSTEM_METRIC

        MENUITEM "About",                              IDM_HELP_ABOUT

    END

END

In the above menu bar, the left softkey is an "OK" button and right softkey is a popup menu with "System Metric" and "About" as its menu items. Just remember that IDR_MENU is the identifier of the softkey bar which is created and IDR_MENU_POPUP is the identifier of the popup menu, which appears when the user clicks on the right softkey "Menu"

 

Binary also raised another interesting point. How do we get popup menus on both right softkey and left softkey? Of course, the first thing I did was to remove the NOMENU option from the part defining the left softkey. You can see the problem there can’t you? Both left softkey and right softkey become popup menus, but both the popup menus show the same menu items because we specified a single popup menu identifier, IDR_MENU_POPUP, and that is why the same popup menu shows up for both the softkeys.

I was looking into how to get different popup menus for the 2 softkeys when Mr (or Ms) Binary replied again. Binary had figured out how.

 

You define the popup menu as usual but with two popup entries,

IDR_MENU_POPUP MENU

BEGIN

    POPUP "Menu L"

    BEGIN

        MENUITEM "Menu Item1",                        0

        MENUITEM "Menu Item2",                        0

    END



    POPUP "Menu R"

    BEGIN

        MENUITEM "System Metric",               IDM_SYSTEM_METRIC

        MENUITEM "About",                              IDM_HELP_ABOUT

    END

END
 

and while creating the menubar in WM_CREATE message, specify the following options,

        case WM_CREATE:

            SHMENUBARINFO mbi;



            memset(&mbi, 0, sizeof(SHMENUBARINFO));

            mbi.cbSize     = sizeof(SHMENUBARINFO);

            mbi.hwndParent = hWnd;

            mbi.nToolBarId = IDR_MENU_POPUP;

            mbi.hInstRes   = g_hInst;

            mbi.dwFlags = SHCMBF_HMENU;



            if (!SHCreateMenuBar(&mbi))

            {

                g_hWndMenuBar = NULL;

            }

            else

            {

                g_hWndMenuBar = mbi.hwndMB;

            }

The only difference is we specify the popup menu identifier for nToolBarId member instead of the menu bar identifier and we also set the SHCMBF_HMENU flag. When SHCMBF_HMENU flag is not specified then the nToolBarId value is treated as a toolbar identifer which creates our usual softkey bar with left and right softkeys. If the flag is set then nToolBarId is treated as a menu identifier. Just a regular menu bar with menus and submenus. So now when you run the application you get,

Be sure to specify the message value if you want to handle these menu clicks. I have specified zero above because I am not really interested in handling these items.

 

So now a question pops up (pun intended), what if I have several popup menus and submenus in the popup identifier. Will it take only the first two and display them or will it do something strange? See for yourself, I used the following popup menu just for the sake of it,

IDR_MENU_POPUP MENU

BEGIN



    POPUP "File"

    BEGIN

        MENUITEM "&Open",               0

        MENUITEM "&Save",                0

        MENUITEM "E&xit",                  0

    END



    POPUP "Edit"

    BEGIN

        MENUITEM "&Copy",               0

        MENUITEM "C&ut",                 0

        MENUITEM "&Paste",              0

    END



    POPUP "View"

    BEGIN

        MENUITEM "&Full Screen",       0

        MENUITEM "&Options",            0

    END



    POPUP "Help"

    BEGIN

        MENUITEM "Abou&t",              0

        MENUITEM "He&lp",                0

    END



END



here’s what is does,

and,

I have never seen that on a ppc! I was surprised that it actually works and creates a full fledged menu bar with several menus. And notice the SIP button has moved to the right. The color of the menu bar has changed as well. A pretty interesting find, I would say.

Update:
You might also be interested in this post, Fun with menus – part II

Lets make the spaceship move! DirectDraw, Part 6

The title of this post might be a little misleading but frankly I haven’t had the motivation to take the Spaceship to the next level. I had a few ideas that I wanted to do but I got lost in nothing. I don’t know. Anyways, I won’t be pasting any code here this time around because there is not much that I have done in the first place (: Just played around a bit with the spaceship and came up with this in about half-hour. Nothing fancy.

 

 


As you can see, the balls pass through each other! I have been trying to get them to bounce off each other but trust me this time around it is really a bit complicated (; I landed up on a few things when I binged around, I am yet to check if those might be useful. Hopefully I can get it done soon enough and if you have any ideas you are more than welcome to comment and guide me.

Bouncing/Colliding marbles, DirectDraw, Part 7

Hi there! The marbles finally collide and collide they do! (: I came across this thread, where Professor Fu-Kwun Hwang has a nice applet on collisions. If you go through the entire thread, professor Hwang explains the equations and mathematics related to elastic two-dimensional collisions.

 

The calculations for a collision is a mathematically involved affair, as I had mentioned in my previous post. I can’t say I fully understand the computations yet, maybe I will look into the details later (: Anyways, the marbles collide and deflect off each other pretty nicely.

 

I’ll let the video do the talking:

 

I will explain the code in my next post, gotta get up early tomorrow (: Goodnight!

 

Bouncing/Colliding marbles, DirectDraw, Part 8

The code for colliding marbles is built on top of earlier changes to the DDEX3 sample. Look here, here and here for more information. There are a few changes I made in the code for making the marbles collide and I hope you have already gone through Prof. Fu-Kwun Hwang post on how to make stuff bounce off each other.



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;

And here are the globals we use in the source file:



#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];

To add more marbles to the program you just need to change the MAX_BALLS macro and recompile the code. Well, the terms balls and marbles are used interchangeably (:

 

We initialize our global data in InitApp() function, we call InitializeData() just before InitApp() returns:



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);

    }

}

Here we initialize all the data related to each marble, its center, velocity and the radius. The switch case makes sure that the balls do not overlap initially, currently I am only checking for three marbles in the switch. So if there are more than 3, there is still some possibility of the balls overlapping. I’ll leave that part for later and lets focus on more important things.

 

The RandInt() function is simple, it returns a random value between the two ranges specified:



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);

            }

        }

    }

}

This is more or less the same as before except that the same things are done for all the three marbles here. Calculate the RECTs for each marble in g_Rect[]. Blt the marbles, update the marbles’ position and check for collisions between marbles. This is the interesting part.

 

Let me digress a bit here. How do you find out if the marbles are colliding? The presence of RECTs tricks your mind into thinking that you can check if the two RECTs overlap, which is what I did initially and which was really dumb, really. I used IntersectRect() api to find out if the two RECTs overlap, and if they did I decided its a collision! The problem here is that the two RECTs may overlap but there might actually be no collision for example when only the corners of the two RECTs intersect. And that happens way too many times, and watching the program run like that leaves you baffled, things dont make sense! It didn’t take me long to figure out a better way, instead of checking for overlapping RECTs, you had to check if the two circles (marbles) overlapped. Let the radius of the two circles be R1 and R2, calculate the distance between the centers of the two marbles, lets call it D. The marbles collide when D <= R1 + R2. Well, they actually collide when D = R1 + R2, but because our program updates the frames by a certain delta everytime we need to check for D <= R1 + R2.

 

The Collision() function takes two BALLINFO structures as input and determines if they collide, returns TRUE if they do and FALSE otherwise:



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;

}

We use the standard formula to calculate the distance between two points, Distance = SQRT((x2-x1)2 + (y2-y1)2). If the marbles do collide then we have to calculate the new velocities for the marbles, and this is how we do it:



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);



}

This function is taken directly from Professor Fu-Kwun Hwang’s explanation on 2D collisions. Changes made to the velocities and positions in CalculateNewVelocities() will be reflected back in the caller.

 

Note: I ran this program quite many times and sometimes it does fail. Maybe something like once in 30 runs. The marbles stick to each other and don’t let go. The problem is in the calculation of ‘dt‘, where it tries to calculate where the balls would have been when they were about to collide (i.e. D = R1 + R2), but since even this is an approximation, it fails sometimes. One fix for this problem is to check if  the balls collide after calculating the new position and velocities. If they do then adjust the position values such that new D > R1 + R2. The problem mentioned above happens when after calculating the new positions and velocities for both marbles they still overlap.