Lets make the spaceship move! DirectDraw, Part 3

Ok, time to get our hands dirty. If you have seen the Donuts sample you would have noticed the tubular spaceship. The donuts sample uses a single image, donuts.bmp, to store all the images used in the game. Well, I just cut off a portion of it to try something out. Just use any image editor and cut out only the spaceship portion of the image. Make sure that the image you cut is 320×384 in size. This will make our calculations easier as you will see later. So the image would look something like this:

Again, make sure the image you cut is 320 pixels wide and 384 pixels high.

Lets move onto some code. Most of the code remains the same as I had modified it here and here to make it work on the emulator. The only changes will be while creating the surfaces and in the UpdateFrame() function.

 

No changes in the way the primary and back buffers were created, just remember to create the back buffer with width as 240 and height as 320. We will need only one extra surface to hold the above image. Create the surface as follows:



    ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;

    ddsd.dwWidth = 320;

    ddsd.dwHeight = 384;

    hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSOne, NULL);

    if (hRet != DD_OK)

        return InitFail(hWnd, hRet, szCreateSurfaceFailMsg);



Notice that the dimensions of the surface match the bitmap size, 320×384. Lets load the bitmap onto the surface now, in InitSurfaces():



    DDCopyBitmap(g_pDDSOne, hbm, 0, 0, 320, 384);



So g_pDDSOne now points to a surface that holds our bitmap. Oh and one more thing, just declare a const variable to hold the number of columns in the image,



static const int            TOTAL_COLS = 5;



Yes, you can go back and count (: Anyways, lets take a look at the UpdateFrame() function now:



static void UpdateFrame(HWND hWnd)

{

    static BYTE                 phase = 0;

    HRESULT                     hRet;

    DDBLTFX                     ddbltfx;

    RECT src, dest;

    int row = 0, col = 0;



    memset(&ddbltfx, 0, sizeof(ddbltfx));

    ddbltfx.dwSize = sizeof(ddbltfx);

    ddbltfx.dwFillColor = 0;



    ddbltfx.dwROP = SRCCOPY;



    //the destination rect is in the center of the screen

    dest.top = 128;

    dest.left = 88;

    dest.bottom = 192;

    dest.right = 152;



    //clear the back buffer (color fill with black)

    g_pDDSBack->Blt(&dest, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAITNOTBUSY, &ddbltfx);



    //calculate the src rect depending on the value of ‘phase’

    row = phase/TOTAL_COLS;

    col = phase%TOTAL_COLS;



    src.top = 64*row;

    src.left = 64*col;

    src.bottom = src.top + 64;

    src.right = src.left + 64;



    while (TRUE)

    {

        hRet = g_pDDSBack->Blt(&dest, g_pDDSOne, &src, DDBLT_ROP, &ddbltfx);

        if (hRet == DD_OK)

            break;

        if (hRet == DDERR_SURFACELOST)

        {

            hRet = RestoreAll();

            if (hRet != DD_OK)

                break;

        }

        if (hRet != DDERR_WASSTILLDRAWING)

            break;

    }



    phase = (phase+1)%30;



}

A few points first, every spaceship image in the bitmap is 64×64 in size. There are a total of 30 spaceship images, so we make the ‘phase‘ variable to run between 0 to 29 in a circular fashion, each time selecting the next image in the bitmap and wrapping around. I decided to place the spaceship in the middle of the screen, as you can see the hard coded values for dest RECT. This is not very elegant and I should really have used GetSystemMetrics() with SM_CXSCREEN and SM_CYSCREEN to calculate the position at run time, but since this is for illustration only, I’ll leave it at that. Next we clear that dest portion of the back buffer, to clear the prevous image, calculate the current image to be loaded using the value of ‘phase‘ and putting the values in the src RECT. Finally we Blt() the image onto the back buffer from g_pDDSOne surface, and this back buffer will then be Blt() onto the primary surface under WM_TIMER message in WindowProc(). Before returning we update the ‘phase‘ variable. Well, thats it! Pretty simple right. If you run this, it will display a rotating spaceship at the center of the emulator screen. You can play around with the timer,



#define TIMER_RATE          80

to control the speed at which the spaceship rotates.

 

Thats it for now! In the next post I’ll explain on how to make the rotating spaceship bounce around the screen edges. It can’t get any simpler (:

I took a small video of the rotating spaceship.

 

Leave a Reply

Your email address will not be published. Required fields are marked *