Geeks With Blogs

As I had mentioned in my previous post, we'll make the spaceship move around on the screen and bounce off when it hits the screen edges.

I would like to diverge a bit here. When I got the spaceship to rotate at the center of the screen, I was wondering how I can make it move around in the screen and bounce off the edges. I thought motion would be much more complicated and difficult and it would involve line equations along a particular direction, and then use geometrical concepts involving things like "The law of reflection states that the angle of incidence equals the angle of reflection." and much more. I had a discussion with a few of my colleagues about this same topic and our discussion pretty much went along the same lines. It made me apprehensive. And when I looked at Donuts' code in detail, well, it seemed like we were trying to boil the ocean to make tea, not that you can't do it (: I could not have ever imagined that moving an object around the screen and making it bounce off the edges perfectly could be more simpler!

Here is how the concept works in brief. You decide on the velocity along the x-axis and the velocity along the y-axis.  Generally, it will be the number of pixels the object moves along each axis per frame. The objects new position is calculated by adding to it the velocity along the X and Y axis. And when ever the object reaches the edges, you just negate the velocity along that direction. That's it. So if the object is about to hit the top or bottom of the screen, just negate the velocity along the Y axis and if its about to hit the left or right edges, you negate the velocity along the X axis. The object bounces around perfectly.

I will be building on the code from my previous post. So I would hope that you have already read it. If you remember, each image of the spaceship in the bitmap was 64x64 in size. To keep things simple, we would make a point move along the X and Y axis and then draw our 64x64 square containing the spaceship around that point, such that the point is at the center of the image always. So our image would be about to hit a screen edge when the point is actually 32 pixels away from it.

Define the velocity globals,

//these are the objects velocities along the x and y axis
int                            dwVelX = 4;
int                            dwVelY = 5;

I have just hard coded the values, it would be better to use the Random() function to get the values, in case of a game. Keeps it a bit unpredictable.

The next change is to calculate the position of the dest RECT at run time, unlike the center of the screen, which we did last time. Here is the code for UpdateFrame():

static void UpdateFrame(HWND hWnd)
{
HRESULT                     hRet;
DDBLTFX                     ddbltfx;
RECT src;
int row = 0, col = 0;

static BYTE                 phase = 0;
static RECT dest;

//the destination rect's position will be calculated around a point (xPos, yPos), initially its the center of the screen
static int xPos = 120;
static int yPos = 160;
static BOOL first = TRUE;

memset(&ddbltfx, 0, sizeof(ddbltfx));
ddbltfx.dwSize = sizeof(ddbltfx);
ddbltfx.dwFillColor = 0;

ddbltfx.dwROP = SRCCOPY;

if(!first)
{
//clear the back buffer (color fill with black)
g_pDDSBack->Blt(&dest, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAITNOTBUSY, &ddbltfx);
}

//calculate the destination rect's position (+-32 coz the image is 64 pixels wide and high)
dest.top = yPos - 32;
dest.left = xPos - 32;
dest.bottom = yPos + 32;
dest.right = xPos + 32;

if(first)
{
//clear the back buffer (color fill with black)
g_pDDSBack->Blt(&dest, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAITNOTBUSY, &ddbltfx);
first = FALSE;
}

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

//now update xPos, yPos depending on the velocities
xPos = xPos + dwVelX;
yPos = yPos + dwVelY;

//if any of the four boundaries is reached reset xPos or yPos and negate the velocity along that direction
if(xPos <= 32)
{
xPos = 32;
dwVelX = -dwVelX;
}

if(xPos >= (240-32))
{
xPos = 240-32;
dwVelX = -dwVelX;
}

if(yPos <= 32)
{
yPos = 32;
dwVelY = -dwVelY;
}

if(yPos >= (320-32))
{
yPos = 320-32;
dwVelY = -dwVelY;
}
}

The first thing to notice is that the dest RECT is now static. This is, of course, because we are updating the destination position relative to its previous value. Two new static variables xPos and yPos are added. These will store the co-oridnates of the point around which we will draw our image. xPos and yPos are initialized to the center of the screen. We then calculate the dest RECT using xPos and yPos by adding and subracting 32 from it. Calculate the src RECT just like before and Blt() it onto the back buffer. The next part is updating the xPos and yPos values. The values are updated by just adding the X velocity to xPos and Y velocity to yPos. Next we do bounds checking to see if our image is about to go off the screen or put in other words, about to hit a edge. If so, then we reset the position and negate the velocity along that axis. This negating has a bouncing effect. I know that I should have used GetSystemMetrics() rather than hard coding values like 240, 320 etc, but I again I am just plain lazy to do it (: And I hope you are not.

Here is a video of the bouncing spaceship.