Website Design United States, Website Design California, Website Designing United States, Website Designing California

theraje's VB6 Game Tutorial Series I

Drawing with Bitblt

Greetings, fellow game developers, and welcome to this installment of theraje's VB6 Game Tutorial Series, "Drawing with Bitblt!" Today we'll learn not only how to draw pictures on the screen, but how to animate them, give them shape, and apply them to a game demo. Rock on!

So, what exactly is Bitblt, you ask? Simple! It's short for "Bit Block Transfer." It's another name for how your computer draws pictures to the screen. Blitting is another name for drawing to the screen. I'll be using that word here a lot, so just chant, "to blit is to draw" during this tutorial, and you should be just fine (although anyone who may be around you may think otherwise...).

Ready? Well then, let's get moving! First thing we ought to do is rev up Visual Basic 6.0 and create a new project, and get the API text viewer going, too. In the API text viewer, load the WIN32API file, and search for Bitblt. If you don't have the API viewer handy, here's the declaration:

Public Declare Function BitBlt Lib "gdi32" Alias "BitBlt" _
(ByVal hDestDC As Long, _
ByVal x As Long, ByVal y As Long, _
ByVal nWidth As Long, ByVal nHeight As Long, _
ByVal hSrcDC As Long, _
ByVal xSrc As Long, ByVal ySrc As Long, _
ByVal dwRop As Long) As Long

Copy the declaration to your form (declare it as Private) or a module (Public), and we're all set! Well, almost...

Before we do any coding, we need to set up our form a bit. For now, we'll use Picture boxes (NOT images) to learn Bitblt. We could use another API functions to create memory chunks to store our images, but that's a little off-topic for this tutorial. If you're interested though, we'll get into that in another tutorial.

All right, we'll need a "Source" picturebox and a "Destination" picturebox. Name one picSource, and the other picDest. Now that you have that done, change their AutoRedraw properties to True using the properties viewer, as well as change their ScaleMode properties to 3 - Pixel.

The reason we changed AutoRedraw to True is simply because it keeps the picture inside intact. Normally, if your source picturebox was invisible or smaller than the bitmap contained inside, it would draw part of the screen or only a portion of the bitmap to our destination. Also, we set it to our destination picturebox so that if someone dragged the form off the screen and back or moved another window on top of it, our destination picture wouldn't be erased. We set the ScaleMode to pixels as well, because that's what pictures are measured in - pixels. In case you don't know what a pixel is, it's just a fancy name for one of those little square dots that make up a picture.

Now that we're done setting up our form, we can start doing fun stuff. Let's add a bitmap to our source picturebox. This will be the picture we blit to our destination picturebox. It can be anything you want, but I'll provide a picture for you to use if you have nothing else. Check it out:

This is a PNG, which isn't really compatible with VB 6.0, so if you need, press the PrintScreen key, open up MS Paint (or your favorite graphics editor), and use the paste command to paste the screen capture into your editor. Adjust your image so that you only have the black box with the heroine inside (64 wide by 64 high, by the way), save it, and add it to your source picturebox. Or, if you prefer, you can download the source for this project - it includes all the bitmaps used for this tutorial.

One important note - be sure to create your character image with a black background. Why? Later on, we'll be using black-colored areas for transparency. We'll be getting to that in a few.

Now that we have something ready to go, we'll get acquainted with the Bitblt command. Add a command button to your form, name it cmdBlit, and add the following code into the Click method of the button:

picDest.Cls

BitBlt picDest.hDC, _
0, 0, _
64, 64, _
picSource.hDC, _
0, 0, _
vbSrcCopy

Save your work, run the program, and click the Blit button. Your results should look something like this:

Now, let's go over what we did to make that happen. First thing we did was use the destination picturebox's Cls method, which clears the destination, preparing it for blitting. The next thing we wrote was a line for the Bitblt command and its arguments. The first argument, hDestDC, is your destination device context. A device context is basically a portion of memory alloted to a certain control, such as a form or picturebox, that we can blit to. The next two arguments, x and y, are positioning coordinates. So, if you wanted to draw something 10 pixels to the right and 50 pixels from the top of the destination, you could change these to 10 and 50, respectively. Remember - X is how far from the left something is, and Y is how far from the top something is.

Next, we have nWidth and nHeight. These are set to 64 and 64 here, since the image we want to draw is 64 pixels by 64 pixels. If we wanted to draw a wider picture, we could increase the value of nWidth, or decrease it to draw a smaller picture. nHeight works the same way. After that, there's hSrcDC, which is the same as hDestDC, except hSrcDC is the device context we're drawing from instead of to. Then there's xSrc and ySrc, which work the same as x and y, except that these tell the program where to start copying from. Why would we want to do this, you ask? Hang on, we'll get to that later on. The next and final argument is dwRop, or "Raster Operation." That's just geek speak for how we want to blend the source picture's pixels to the pixels on our destination. In this case, we used vbSrcCopy, which draws the source picture exactly as it is, without regard to pixels already on our destination picture. More on raster operations and how they work in a bit.

Whew, that's enough theory for now. Let's have some fun, and see what this baby really can do!

So, I know what you're thinking. That black box around our heroine is ugly. Well, we can easily fix that, my friend! All we have to do is create a "mask" and play with our raster operations a little.

"But," you ask, "what's a mask?" Simply put, it is a sort of "canvas" used to blend pixels in a manner that makes certain parts of an image that is blended on top of it opaque, and the rest transparent. It's basically just a black-and-white copy of your picture, where the black parts are the shape of the picture, and the white parts are the transparent areas.

Tip: I've found that the easiest way to create masks is to use the "Threshold" tool in Paint Shop Pro. Simply color the areas that you want transparent white using the flood fill tool, and go to the Colors menu, then Adjust > Threshold. Crank it up to 255, and everything that isn't completely white is turned black. Making a mask couldn't be much easier!

Once you have your mask, double the height of your character's picture, and add the mask to the bottom, like so:

Remember earlier when we talked about the Bitblt arguments xSrc and ySrc? This is the part where these two arguments come into play. nWidth and nHeight tell us how much to draw, right? And xSrc and ySrc tell us where to get the source picture from. So, if we want to store multiple character pictures in the same bitmap, for animation, or as we're using it now - for a mask - you can use xSrc and ySrc to tell your program where to find each individual picture. Cool, huh?

Once we add our new picture with mask to the project, add another button, name it cmdBlitTransparent, and save the project again. Then, let's add some code to that new button we just created. It should go something like this:

picDest.Cls

BitBlt picDest.hDC, _
0, 0, _
64, 64, _
picSource.hDC, _
0, 64, _
vbSrcAnd

BitBlt picDest.hDC, _
0, 0, _
64, 64, _
picSource.hDC, _
0, 0, _
vbSrcPaint

Save the project again, and run it. Give the cmdBlitTransparent button a good clicking, and check out the results - no more black box!

What we did here was much like what we did the first time. The only things that really changed were that we called bitblt twice, and changed some of the arguments.

First thing we did, as always, was call the Cls method for the destination picturebox. Then we used Bitblt to draw our mask. We changed the argument ySrc because our mask is 64 pixels from the top of the picture (which would be 0). We changed our dwRop to vbSrcAnd. What does that do? Well, in this case, it draws black pixels to the destination, but not white pixels. That sets up our canvas for the sprite ("sprite" is another word for a collection of pixels that make up a single picture - it's not a soft drink, nor is it a mythical spook. Not here, at least).

The second time we called Bitblt, we left ySrc at 0, since our sprite picture starts at the top of the bitmap. Our raster operation this time was vbSrcPaint, which painted our picture onto the canvas we created by using vbSrcAnd on our mask. With this killer combination of raster operations, we produce a sprite with transparent areas for a more realistic look. I mean, come on, how many people do you see roaming the streets surrounded by black boxes?

So now we can properly blit a sprite to our program's destination picturebox. Woohoo! Now let's do some other fun stuff, like animation!

The idea of animation in a game is no different from animating a cartoon or a movie. We simply have a bunch of still images, but when they are a bit different from each other, and you show them quickly and in succession, you get animation - the illusion that something is moving, when it actually isn't. Now we're going to apply this in our program.

Well, obviously, we first need to create more images. We'll need to draw a character, and at least two other frames to get it to walk. Then we have to create masks for each frame (a single picture that makes up an animation). Being an artist sure is a lot of work when you're a programmer! Here's a sample image for you:

Put that in your source picturebox and save the project. Now, we'll make another button, cmdAnimate, and a timer, tmrAnimate. Set the timer's Enabled property to False, and its Interval property to 150. Put the following code in your cmdAnimate command button:

tmrAnimate.Enabled = Not tmrAnimate.Enabled

What this does is simply toggle the animation timer on and off. Now, as for the timer itself, put the following code inside:

Static animFrame As Integer

picDest.Cls

BitBlt picDest.hDC, _
0, 0, _
64, 64, _
picSource.hDC, _
animFrame * 64, 64, _
vbSrcAnd

BitBlt picDest.hDC, _
0, 0, _
64, 64, _
picSource.hDC, _
animFrame * 64, 0, _
vbSrcPaint

animFrame = animFrame + 1
If animFrame = 5 Then animFrame = 1

That's all it takes, folks! We declared one static variable (a static variable is declared locally, but keeps its value even after the end of the procedure it is called in) to store what frame we want to draw. Then, for xSrc, we multiply the frame number times the width of what we want to draw, which is 64 pixels. We do the same in our second Bitblt call as well, but we use our normal positions for ySrc since we only have two rows of pictures - the top for sprites, the bottom for masks. After that, we increment our frame, make sure it doesn't try to go past how many frames we have, and set the frame to 1 if it does (we could go back to zero if we needed - in this example, I set it to 1 since the first frame (frame zero) is a standing image, not a walking frame).

So, now we have one walking-in-place heroine. All that's left to do is get her to move while she's walking. Well, doing that is very simple. All we have to do is adjust the x and y coordinates before drawing her to the destination picturebox. We could do this by adding the following code to the animation timer, just before calling Bitblt:

Static HeroineY As Integer
HeroineY = HeroineY + 8

And modify the y argument to both Bitblt calls so that they refer back to our HeroineY variable, like so:

BitBlt picDest.hDC, _
0, HeroineY, _
64, 64, _
picSource.hDC, _
animFrame * 64, 64, _
vbSrcAnd

BitBlt picDest.hDC, _
0, HeroineY, _
64, 64, _
picSource.hDC, _
animFrame * 64, 0, _
vbSrcPaint

Save your project, and run it. Click cmdAnimate, and voilá! A walking heroine!

There you have it, folks, this game programming tutorial is about to come to a close. I hope you enjoyed it - but not nearly as much as I hope you'll enjoy making your own game creations in Visual Basic! If you would like to have this project and all related bitmaps, you can download the source by clicking here!

Here are a few things to remember when using Bitblt.

If an image isn't drawn...

Make sure you didn't mix up the destination and source device contexts
Try using the Cls method of the destination picturebox before blitting
Make sure your AutoRedraw properties are set to True
Ensure that your source actually has a bitmap in it (silly, I know, but it happens to the best of us)

If things don't look quite right...

See if you're using the proper raster operations (vbSrcAnd for the mask, vbSrcPaint for the sprite)
Be sure you're drawing a mask before you draw a sprite
Always make sure to draw a mask and its sprite in the same place on the destination

That's it for this tutorial. I hope it was a good one, and that you'll try out my other game programming tutorials!

Author Information:

Clint V Franklin

http://theraje.programmers-corner.com

Comments:

Add your comments here.

Name

Comment

You can also send feedback to feedback@programmers-corner.com

Mike Winger - January 11, 2005 7:55 PM

This works until you try to make the background in the buffer too. then you get an invert of your background that you blitted to the screen, which looks bad. How do i make it so that it works when putting the background in the buffer as well?

Clint - January 12, 2005 3:11 PM

Hey Mike, which rasterop are you using to draw your background? If it's not meant to have any transparency, just draw that once using the rasterop VBSrcCopy.

Rick - February 26, 2005 6:09 AM

Looks great

Igor - May 2, 2005 4:17 PM

How do you add a mask when you use pain shop pro?

justin leighton - May 28, 2005 4:19 PM

sweet, thanks a lot, this cleared up my confusion. i even used this code plus lots more, to animate an array of 2d tiles with crappy physics to move around the player, mario styles. lots of fun!!

tom - June 9, 2005 8:26 AM

just what I've been looking for, easy to follow but very usefull! cheers

OCEAN - July 8, 2005 11:35 AM

Quite GOOD !!!!! Great ! Nice Tut

Diego Verdecchia - July 19, 2005 2:44 PM

It´s the easiest and best game programming explanaition that i ever see.

Angeloks - July 24, 2005 1:43 PM

For ppl who really intend to make a game, here's 2 little tips : you can load source pictures in memory and for to prevent the blinking dont use picDest.cls, make you drawing on a virtual image and copy the content of this virtual image in your picturebox.

Rizar - August 29, 2005 3:27 PM

Just great for what I wanted to do, I was using bitblt with Delphi few years ago but I forgot almost everything by always working with database.

karan - December 14, 2005 10:10 PM

good

Bhaskar Rabha - January 9, 2006 9:45 AM

It is nice web site. I really want to tell thanks

Jeff - January 9, 2006 12:00 PM

This is so confusing.

Dave - January 29, 2006 7:24 PM

geez finally ive been wanting a simple bitblt tutorial that explains what its doing for a long long time. All i could find were bitblt tuts that had every freaking thing else in it too and no explanation

Mike - February 6, 2006 12:26 AM

i tried bliting a pic of a tank and it came up with a white square on the screen

 















 


© 2008-2009 dotnet4all.com