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.

Draggin the marbles around, DirectDraw, Part 9

You could sure use some mouse input with the marbles. Remove the timer stuff from the DDEX3 program that we modified and add handling for WM_LBUTTONDOWN, WM_LBUTTONUP and WM_MOUSEMOVE messages in the WindowProc() function. You will need to add some code to find out if WM_LBUTTONDOWN was on the marble and then move the position of the marble relative to its last position whenever you get WM_MOUSEMOVE message.

 

Here is a video of it:

 

 

If you run this in debug mode you can notice considerable lag because it runs over the debugger. The video here shows the application running normally, i.e. I select the program to "Start Without Debugging" (ctrl + F5).

Combining the pieces, DirectDraw, Part 10

Hi there! What do get when you combine this and this? Well, maybe a game called Crash Marbles? ;)

 

Anyways, game is still pretty far off but here is a video of the result:

 

 

Well, the basic concept of the "would-be" game revolves around the player having to dodge the evil marbles and also collect the powers that show up randomly on the screen. I am still thinking about how to make the game more interesting and entertaining. Don’t bother about the score that shows in the top left, its still work in progress ;)

A glitch corrected, DirectDraw, Part 11

In part 8 of this series of posts on DirectDraw, I had mentioned that there still seems to be a minor problem with the program. Read the "Note" section at the end of the post. The problem now has been solved.



Recap

The problem was that even after calculating the new positions for the marbles, the marbles would still be overlapping because of the approximations that we use. And this would sometimes repeat many times over which creates the problem.



Solution

The fix that I’d said in the "Note" section works well. After calculating the new position for the marbles you check again if they collide. And if they do then adjust their positions so that they don’t overlap anymore. Every time I move the marbles 2 pixels away from each other and check the distance again. And repeat this until they are no more overlapping. Here is the code:

     MinDistance = ball1->radius + ball2->radius;

    dxx = ball1->xPos – ball2->xPos;

    dyy = ball1->yPos – ball2->yPos;



    //calculate new distance between marbles

    distance = sqrt(dxx*dxx + dyy*dyy);

    printf("COLLISION: New Distance:%d \r\n", (int)distance);



    //this part makes sure that the new positions of the marbles are not overlapping

    //sometimes the new position itself overlaps and that leads to weird behaviour

    //check if the marbles are overlapping

    if ((int)distance <= MinDistance)

    {

        //adjust their positions

        do

        {

            if (ball1->xPos > ball2->xPos)

            {

                ball1->xPos += 1;

                ball2->xPos -= 1;

            }

            else

            {

                ball1->xPos -= 1;

                ball2->xPos += 1;

            }



            if (ball1->yPos > ball2->yPos)

            {

                ball1->yPos += 1;

                ball2->yPos -= 1;

            }

            else

            {

                ball1->yPos -= 1;

                ball2->yPos += 1;

            }



            dxx = ball1->xPos – ball2->xPos;

            dyy = ball1->yPos – ball2->yPos;



            distance = sqrt(dxx*dxx + dyy*dyy);



        }while((int)distance <= MinDistance);

    }

 

So the same set of values for xPos and yPos which used to create the problem before, now work fine.

Tools: Cellular Emulator and Fake RIL

Today I had the chance to fiddle with the cellular emulator and try a few things with it. Its a very useful tool to test out all your radio related applications (which use RIL directly or indirectly) without having the actual hardware.

Cellular emulator  is very well documented so I don’t want to repeat the same things here, for more information visit the following link:
http://msdn.microsoft.com/en-us/library/bb158495.aspx

In short, you can simulate MO/MT calls, send and receive sms’s and do data sessions as well.

And that is when I came across Fake RIL. Well, I had heard about fake ril before and had a fairly good idea about what it was but never truly had the chance to play with it. I dug down a little deeper today and found it amazing. Basically, as the name suggests, it is a fake ril driver which simulates the network too.  It is so well documented (it ships with AKU so I cannot shell out the docs here bacause of the NDA) and I really appreciate the idea and the brains that went behind designing it. Fake ril simulates the network and all the clients above can work as is, well, that was the whole idea in the first place (:

I had a windows mobile professional device so I thought I might try to make the device use Fake RIL instead of our customised ril which it was using. I built it into a dll and made the device load fakeril instead of the OEM ril driver that it was loading before.  When the device booted up it came up with full signal strength and that is when I noticed that there was no SIM in the device! It worked. I tried making calls and sending a few sms’s and it worked perfectly. When you make a call the call is automatically answered, and there are some special numbers which simulate busy, unanswered, reject etc. If you’ve read the above link you know already.This is a great way for some of our sibling teams to test their applications as there is no dependency on the radio hardware, waiting for the radio code to stabilize et al. I couldn’t try data session though. Will try it out next week.

Applications: Process Viewer update

I noticed that I hadn’t added the filename associated with the process in the Process Info section last time. It struck me when looked at the PViewCE sample, which I mentioned about in this post.

So I thought why not add the filename label, could anything else be simpler!

I edited the dialog to include another static text control and added the code in AllignComponents() to beautify the control. But a small hiccup, when I ran the program just to test if it was displayed correctly, it wasn’t to be seen. And then I remembered that the group box hides it. Darn, not again! So I went back removed the group control, added the static text and then added the group control back on. The control displayed correctly. Use GetModuleFileName() api to get the filename associated with the process.

WINAPI DWORD GetModuleFileName(HMODULE hModule, LPWSTR lpFileName, DWORD nSize);


The api takes the module handle for which the filename is requested, a buffer to hold the filename and finally the size of the buffer.

For hModule, you can pass the th32ProcessID member of the PROCESSENTRY32 structure after casting it to HMODULE.

Here is how I called the function in ShowProcInfo():

TCHAR filename[256] = TEXT("Unknown");

if(GetModuleFileName((HMODULE)pProcess->th32ProcessID, filename, sizeof(filename)/sizeof(TCHAR)))

{..}

Here are a few screen shots:

Cellular emulator, COM3 in use please verify

I was trying to set up the cellular emulator with the windows mobile emulator on my laptop when the cellular emulator spat out "COM3 in use, please verify". I knew it was another classic case of some application holding a port and another application failing because of it. Such problems are usually solved by changing the order of installing those application. To find a solution I binged around (yes! I bing :) and found this msdn forum link.



No surprise that many people had already gone through this. Had a hunch that one of my bluetooth services was holding down on that port. I had to find a way to make the cellular emulator use another port, so I went about searching the registry. While the search was going on, I was reading through the forum thread and it mentioned about bluetooth services holding down on a number of ports. I disabled my bluetooth device and then re-enabled it. And then when I opened Cellular Emulator, it came up on COM3. How in the world!



I guess my disabling and re-enabling of the bluetooth device must have somehow freed COM3. By that time I had reached the end of the thread and there was a solution suggested which involved changing your registry keys. Well, I didn’t have to do that.

Update: Next post.

Cellular emulator and Device Emulator, COM port issues

Well, it looks like the magic that made the cellular emulator come up on COM3 in my previous post was not long lived. Once the cellular emulator came up, I started the device emulator and tried to set the "Serial Port 0" of the emulator to COM3, so that the device and the cellular emulator can talk to each other and that is where it went boom! Threw a message saying something like, "Unable to open COM3, cannot find the file specified". All my efforts to fiddle with disabling and enabling the bluetooth services went in vain. I tried for about an hour scouring the net to find some info that could help me. I knew that uninstalling the bluetooth software from my laptop (WIDCOMM bluetooth stack) might solve the problem. But I was looking for a work around and saving me the trouble of a re-install. I tried to change the registry settings for the cellular emulator to make it use another port like COM8, COM9, COM10 etc but all failed. I either got "Access denied" or "cannot open file specified" error. And when I finally ran out of options I did uninstall the bluetooth software from my machine. Tried the device emulator, cellular emulator thingy and it worked. I could make incoming calls and send recieve sms’s. Then I installed the bluetooth software back on. Success! Both BT and emulators are working in harmony (: