Making games using the Win32 api
This is an complete tutorial on how to make a game using the Win32 api. The pictures wouldn't work so download the zip. Please leave a comment to tell me what you think of it.
Original Author: Dennis Meelker
Code
style='font-size:24.0pt;mso-bidi-font-size:12.0pt'>Making games using the Win32 style='font-size:16.0pt;mso-bidi-font-size:12.0pt'>By Dennis Meelker style='font-size:16.0pt;mso-bidi-font-size:12.0pt'>Meelkertje@hotmail.com In this tutorial I will show you how to make a game that So why should we use the Win32 API instead of using DirectX, First we will make a new project just create a standard exe, When Autoredraw property is set to true the things that our Now that we have our form ready create a new module and call Public Declare Function BitBlt Lib Public Const SRCAND = &H8800C6 style="mso-spacerun: yes"> ' (DWORD) dest = source AND dest Public Const SRCCOPY = &HCC0020 ' (DWORD) dest Public Const SRCPAINT = &HEE0086 style="mso-spacerun: yes"> ' (DWORD) dest = source OR dest As you can see, we just added the Bitblt api function to our hDestDC - This x - y - nWidth - nheight - hSrcDC - xSrc - ySrc - dwRop - When you see this you will probably say, “Dennis? What is a So I will explain that right now, DC stands for device If we are making a good game, we want the area surrounding
api.
clear=all style='mso-special-character:line-break;page-break-before:always'>
runs fast using the Win32 Api. I will try to explain everything as good as
possible, so if you don't understand something read it over and over until you
get it, got it? If you really can't understand it you can always e-mail me.Now
lets get started.
I personally think DirectX is way to hard to learn if you just want to make a
flat type game. I you want to make a 3D shooter with all effects like anti
alias and stuff, you will need to learn DirectX for sure, there is just no way
you can do this in VB using only API's. But if you want to make a flat game
like Pacman or some kind of Platform I prefer using the API. But this is just
my opinion so if you want to use DirectX go ahead.
now name the form frmMain or something like that. This will be the game form. Now,
the next two things are really important, set the AutoRedraw property to True
and set The Scalemode to Pixel.
game drew on the form won't just disappear when the form is refreshed. We set
the Scalemode to pixel because the API's all need pixels as parameter and not
twips, if we hadn't changed it we had to turn the twips into pixels all the
time witch would cause trouble for sure.
it something like modInvaders orso. Now add these api Declaration's to the
module:
"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
= source
project, the bitlbt function will be the core of our game, it is used to draw
all the graphics on the screen. I will explain all the parameters here:
is the DC of the form/control to draw to.
This is the x position to draw to
This is the y position to draw to
This is the width of the picture or a part of a picture to copy
This is the height of the picture or a part of a picture to copy
This is the DC of the form/control that containt the picture we want to copy
The source x coordinate
The source y coordinate
This specifies how the graphic should be drawn
DC?”.
context, it's just a place inside the memory of your PC where the picture of a
form or any anther control is stored. Now if you didn't know what a DC was you
probably won't know what the dwRop property is, well, as I said above it tells
the BitBlt functions how to draw, “Are there different way's to draw??”, yes
there are, you noticed the three constants below the BitBlt function that we
added to our module those are three ways to draw, you can just set the dwRop to
SRCCOPY or any of them. The SRCAND and SRCPAINT are almost always used
together, I don't know what they do exactly but I do know that when you use the
SRCAND first and the SRCPAINT after that you can get a transparent picture, you
probably don't understand what I just said, never mind, I will explain this
later on. The SRCCOPY constant is nothing special, it just copies the part of a
picture you specified to the specified DC.
our characters to be transparent, if it would not be transparent, below are two
examples of a character, the first one has a transparent background, the second
one doesn't.
src="./Making%20games%20using%20the%20Win32%20api_files/image003.jpg"
v:shapes="_x0000_s1027">
src="./Making%20games%20using%20the%20Win32%20api_files/image004.jpg"
v:shapes="_x0000_s1026">
style='mso-ignore:vglayout' clear=ALL>
src="./Making%20games%20using%20the%20Win32%20api_files/image006.jpg"
align=left hspace=12 v:shapes="_x0000_s1028">I think you will now
understand why we want the background of our character transparent. To make the
background of our pictures transparent we have to create a mask. On the right
you can see a picture that is ready to be drawn with a transparent background.
The first picture has a black background, the black will be transparent, now
you will probably think: “But his arms have black stripes, wont he get
transparent arms?”, to solve that problem I created a “Mask” a mask is a
picture with everything that should be transparent white, and the rest black.
With these two images and the BitBlt function we are ready to draw the
character with a transparent background.
Before we go on, make sure you have a picture like the one
above, you can also use the one above
if you want to.
Now add a Command button and a picturebox to the form set
the picturebox's autoredraw property to true, the scalemode to Pixel, the
borderstyle to zero and set the Autosize property to true. Now load your
picture in the picturebox by setting the picture property.
Doubleclick on the button you just inserted and add the
following code:
BitBlt me.hDc, 0 , Me.Refresh lang=EN-US style='mso-ansi-language:EN-US'> |
If your
picture has other sizes you must change them, but watch out, you have to use
the sizes of one part of the picture, the picture I showed you has a width of
40 pixels and a height of 20, it consists of two pictures that are put together
so the sizes of one picture are 20x20.
If you
start the program and you press the button you will see you character with a
black background. Now that you know how to use the SRCCOPY constant we will go
on with the other two. Add another Command button and set it's code to:
BitBlt me.hDc, 0 , BitBlt me.hDc, 0 , Me.Refresh lang=EN-US style='mso-ansi-language:EN-US'> |
When you
press this button you will see your character with a transparent background!!
The first thing you should now when making a game is that
you should use as less timers as possible , timers are really bad things to use
in a game. Now I hear you thinking things like: “But how can I move the bullet
my spaceship just fired without a timer?”, the solution is:… Loops!. “Loops??”,
yes loops, because a game usual needs to time a lot using timers will only make
your game run slow, and that is the most worst thing to have, imagine you made
a great looking game with killer graphics, but it runs soooooo slow because you
used about two dozen timers. We wont have this kind of trouble, cause we are
using loops!!
Well, with the most games you will have a main loop, a main
loop is a loop that runs your game, when the loop stops.. the game stops. In
this loop we will check for keypresses and we will move our characters, we will
move bullets, draw the players and powerups and so on. A simple loop would look
like this:
Do ‘Game DoEvents Loop |
But if we put all the stuff I mentioned above in here and
start our loop you will notice it goes way to fast, we will need to slow our
loop a bit down. Now I will change the loop like this:
Const Dim LastTick = Do style="mso-spacerun: yes"> Curtick = GetTickCount() style="mso-spacerun: yes"> If style="mso-spacerun: yes"> ‘Game Stuff style="mso-spacerun: yes"> End if style="mso-spacerun: yes"> DoEvents Loop |
The first thing you will probably see is the GetTickCount
function, if you never worked with the API before you will probably don't know
what it does. So I will tell you, the function GetTickCount returns the amount
of milliseconds that elapsed since windows has started. So if you look at the
rest of our loop you will see that we first get the current tick and store it
in the LastTick variable. Then we start the loop and we store the current tick
in the CurTick variable. Now comes the important part, we check if the
difference between CurTick and LastTick is ten, if it is the game stuff will be
executed. So if we make our loop this way, every ten milliseconds the game
stuff will be executed, this gives you game a speed of 100 Fps!! The
declaration of the GetTickCount is so:
Public |
For the people that don't know the DoEvents command, I will
explain it here. The DoEvents command is really important in our main loop, the
DoEvents command lets the pc do things like updating the screen, if we let it
out of our loop you would not see anything happen because the pc hasn't any
time to redraw the screen, so it stays empty.
I will now tell you how to obtain keypresses. If you ever
used the keydown event with a game you probably noticed that if you hold a key
down, your character first goes forward one step, then it pauses and then it
goes on. It's very simple…”We don't want that!” so we won't use any event, we
will use the GetKeyState API, it's declaration is as followed:
Public Declare Function GetKeyState Lib Public Const KEY_DOWN As Integer = &H1000 style='font-size:10.0pt;mso-bidi-font-size:12.0pt;font-family:"Courier New"; |
The only parameter this functions has is the nVirtKey, this
is the key you want to check. I've included the KEY_DOWN constant witch is
needed to check for a keypress, if you want to check if the space bar is
pressed you simply use this code
If GetKeyState(vbKeySpace) and KEY_DOWN then End If |
When creating a game you should make a function called
something like: GetUserInput or something like that, it would also be handy if
you declared a Boolean variable for every key so you can use it inside your
whole game, the sub would look like this:
Public Function GetUserInput() End Function |
If you call the newly created function inside our main loop
we can check for keypresses everywhere in our game.
If you want the keys to customisable you could also declare
a long for every key, then you should also make something like a InitKeys sub
in witch the variables will be loaded with the right keycodes, you can then let
the user choose his own configuration, the code would look like this:
Public Sub InitKeys() UpKey = DownKey LeftKey RightKey End Sub Public Function GetUserInput() End Function |
On to the next subject, Sound, without sound, a game is
usual boring, so you need sound. You can download sounds from various websites,
you can also record the yourself using a microphone, if I need a simple sound
like a beng, I just put my mirophone near my desk and punch on the table. If
you have your sound saved as a .wav file you can play it two ways, you can use
the mci control Microsoft made. And you can use the sndPlaySound api, we will
use the sndPlaySound api, because using the control only makes your game slower
and bigger because you will need to include a ocx of 150 kb. De declaration of
the sndPlaySound stands below:
Public Declare Function sndPlaySound Lib Public Const SND_ASYNC = &H1 Public Const SND_LOOP = &H8 Public Const SND_NODEFAULT = &H2 |
As you can see the sndPlaySound function has two parameters,
ipszSoundName and uFlags. The ipszSoundName is the filename of the .wav file to
play, uFlags can be set to various settings. I explain the setting below:
SND_ASYC – The file is played and the program continues, if
you don't use this one the program waits until the sound is done.
SND_LOOP – The sound will be looped, if you want to stop the
sound just call the sndPlaySound function again, with no file specified.
SND_NODEFAULT – When this flag is not set, the system
default beep will sound if the given file can't be found. When you set it there
just won't be sound. It's smart to always use this flag when creating a game.
In most games you will only use the SND_ASYNC and the
SND_NODEFAULT flags, therefore I always create a function called PlaySound,
like this:
Public Function PlaySound(sFileName as string) End Function |
To play a sound just call the PlaySound function. Because
the sound is usual in the map of the game I always create a function to add a
to the app.path variable if necessary, I do so because else, if I always add a
the path can become something like c:\, and that wont work. The new code
will then be.
Public Function FixPath(sPath as string) as string If Else End If End Function Public Function PlaySound(sFileName as string) End Function |
This way you only need to specify the filename, the program
will then automatically add the directory in witch the game is installed.
Okay, now that you now the basics ( if you don't know the
basics, just read it again ) we will make a small game in witch you can walk
around a character. Create a new project, make a button that says “new game” on
the first form. Add a new form, set up the form as we did earlier. Make a
module with all the declarations and constants we talked about, they are below:
Public Declare Function BitBlt Lib "gdi32" Public Declare Function GetKeyState Lib Public Declare Function sndPlaySound Lib Public Declare Function GetTickCount Lib Public Const SRCAND = &H8800C6 Public Const SRCCOPY = &HCC0020 Public Const SRCPAINT = &HEE0086 Public Const KEY_DOWN As Integer = &H1000 Public Const SND_ASYNC = &H1 Public Const SND_NODEFAULT = &H2 |
Also add some declaration to the module, just put them at
the bottom:
Public UpKey as long Public DownKey as long Public LeftKey as long Public RightKey as long Public UpPressed as boolean Public DownPressed as boolean Public LeftPressed as boolean Public RightPressed as Boolean Public PlayerX as integer Public PlayerY as integer Public TimeToEnd as boolean |
Now create a new sub in the module called MainLoop, you can
also copy it from below
Public Sub MainLoop() Const Dim PlayerX PlayerY InitKeys LastTick Do until If If If If If If If If If End ‘Let Loop End Sub |
Add the two subs InitKeys and GetUserInput to the module:
Public Sub InitKeys() UpKey = DownKey LeftKey RightKey End Sub Public Function GetUserInput() End Function |
src="./Making%20games%20using%20the%20Win32%20api_files/image008.jpg"
align=left hspace=12 v:shapes="_x0000_s1029">Now, for the drawing
I've created a new sub, in the sub the BitBlt function is called twice, create
a Picturebox on the game-form, set the scalemode to true, borderstyle to zero,
autosize to true and autoredraw to true. Finally, set the visible property to
false. Now add your graphic. I used this one. Now copy the DrawPlayer sub into
the module.
Public Sub DrawPlayer() FrmMain.Cls BitBlt BitBlt End Sub |
The last thing you need to do is add this to the click event
of the command button on the first form:
FrmMain.Show DoEvents MainLoop |
That's it, you have created a small game in witch you can
move around a smile, off course this isn't a fun game, but this game includes
all the basics, now you can add things like a background, you can just set the
picture property of the form to any picture you like. You can turn this into an
RPG or into a pacman type game. You can add sound.
For more practise with this way of making games, search for
“My Pacman” at http://www.Planet-Source-Code.com , you will find a pacman game
I made, it uses the same techniques as I explained on this tutorial. I hope you
find this document , useful. You can send all questions and other things to
Meelkertje@hotmail.com.