So you want to make a 2d game for the Pocket PC &/| Zaurus?
by Tim Newell · in General Discussion · 06/22/2003 (5:02 pm) · 9 replies
So you want to make a 2d game for the Pocket PC and/or the Zaurus?
Part 1
You may have thought that it was a good idea to make a game for a handheld device or your PC. I thought I would write up some pointers in helping you get started. First thing we need to do is choose a language. I am going to cover C++ here because it is my language of choice and it will give you the best performance from your device and with some helper libraries I am going to talk about, it will do it in a simple manner. These hints will be broken up into sections with the other parts posted later.
Next lets start with a little background information on the structure of the 2d APIs we will be using. Both APIs that I have used on the Pocket PC and the Zaurus work in a similar way. In your 2d game you are going to want to be able to load and display images (whether they are .bmp, .jpg, .gif, or .png and whether you want straight blitting, alpha blending (you specify a transparency value and it blends your image with the background depending on how much transparency is set too), or keyed transparency (you specify a specific color in the image to be transparent)), Load a font (system or custom) and display text with it, Ability to draw rectangles, filled rectangles, lines, etc., use a double buffer (double buffer is simply a surface in memory that you render everything to first then you render the buffer to screen in 1 command. This removes flicker as without double buffering you can see stuff being drawn.), process input from the mouse/stylus and keyboard/hardware button keys, process events from the Operating System and the window, able to create a basic window for your application (although in most cases your going to want full screen access which can be difficult on some platforms) and various other things your game might require. And you want to be able to do all of this while maintaining compatibility across all the devices you want to support and to avoid bugs in the hardware/software of the devices.
The APIs are setup where you have a Surface class. In the Zaurus API I will be talking about (ZSurface) the surfaces are called Zsurface. In the Pocket PC API (GapiDraw) they are called CGapiSurface. A surface has the ability to load the image from disk (technically that's not true with Zsurface because you need to use QT to load the surface but we will get more into that later), basically holds the information for your image, and has the ability to perform blitting to it, draw lines, rectangles, etc onto it. As you might have guessed our back buffer is simply one of these surfaces that is the same size as the screen we want to draw on. The way the buffer gets drawn onto the screen is handled a bit different in each API and we will get to that in a bit. Each API also has a Font Class, Zfont for Zaurus and CGapiBitmapFont for the Pocket PC. Basically you use these classes to load a font (Custom fonts are simply special bitmaps which both APIs can load the same bitmap since the guy who wrote Zsurface modeled ZFont after the font classes in GapiDraw ), but the Surfaces are the actual classes that draw the text (After all they handle all of the drawing code onto themselves and fonts are just another thing to be drawn onto the screen.).
On the Zaurus your going to have to actually use QT to handle everything except the ZSurface and ZFont since ZSurface is just a blitting library. However on the PocketPC side, GapiDraw handles everything mentioned above but sound and music. (I will cover sound and music later) Now its time to take a closer look at the platforms themselves and see what it takes to get the tools needed to make your killer puzzle game or killer 2d action game.
Part 1
You may have thought that it was a good idea to make a game for a handheld device or your PC. I thought I would write up some pointers in helping you get started. First thing we need to do is choose a language. I am going to cover C++ here because it is my language of choice and it will give you the best performance from your device and with some helper libraries I am going to talk about, it will do it in a simple manner. These hints will be broken up into sections with the other parts posted later.
Next lets start with a little background information on the structure of the 2d APIs we will be using. Both APIs that I have used on the Pocket PC and the Zaurus work in a similar way. In your 2d game you are going to want to be able to load and display images (whether they are .bmp, .jpg, .gif, or .png and whether you want straight blitting, alpha blending (you specify a transparency value and it blends your image with the background depending on how much transparency is set too), or keyed transparency (you specify a specific color in the image to be transparent)), Load a font (system or custom) and display text with it, Ability to draw rectangles, filled rectangles, lines, etc., use a double buffer (double buffer is simply a surface in memory that you render everything to first then you render the buffer to screen in 1 command. This removes flicker as without double buffering you can see stuff being drawn.), process input from the mouse/stylus and keyboard/hardware button keys, process events from the Operating System and the window, able to create a basic window for your application (although in most cases your going to want full screen access which can be difficult on some platforms) and various other things your game might require. And you want to be able to do all of this while maintaining compatibility across all the devices you want to support and to avoid bugs in the hardware/software of the devices.
The APIs are setup where you have a Surface class. In the Zaurus API I will be talking about (ZSurface) the surfaces are called Zsurface. In the Pocket PC API (GapiDraw) they are called CGapiSurface. A surface has the ability to load the image from disk (technically that's not true with Zsurface because you need to use QT to load the surface but we will get more into that later), basically holds the information for your image, and has the ability to perform blitting to it, draw lines, rectangles, etc onto it. As you might have guessed our back buffer is simply one of these surfaces that is the same size as the screen we want to draw on. The way the buffer gets drawn onto the screen is handled a bit different in each API and we will get to that in a bit. Each API also has a Font Class, Zfont for Zaurus and CGapiBitmapFont for the Pocket PC. Basically you use these classes to load a font (Custom fonts are simply special bitmaps which both APIs can load the same bitmap since the guy who wrote Zsurface modeled ZFont after the font classes in GapiDraw ), but the Surfaces are the actual classes that draw the text (After all they handle all of the drawing code onto themselves and fonts are just another thing to be drawn onto the screen.).
On the Zaurus your going to have to actually use QT to handle everything except the ZSurface and ZFont since ZSurface is just a blitting library. However on the PocketPC side, GapiDraw handles everything mentioned above but sound and music. (I will cover sound and music later) Now its time to take a closer look at the platforms themselves and see what it takes to get the tools needed to make your killer puzzle game or killer 2d action game.
About the author
Recent Threads
#2
Ok now that you have seen some code and some tricks, I'll end the first Part here. If you have any questions or comments fill free to post them below.
[Edit]I had to split this up into post.. didnt realize the forum had max lengths[/Edit]
You can find GapiDraw located at: www.gapidraw.com
You can find ZSurface (while will be covered in a future feature) located at: www.warmi.net/zaurus/blits.shtml
-Tim aka Spock
06/22/2003 (5:03 pm)
Now lets take a look at a simple MyApplication class definition that does nothing.#include "GapiDraw.h"
#include "GapiApplication.h"
class MyApplication : public CGapiApplication {
public:
MyApplication(const GDAPPCONFIG& config); //Constructor
virtual ~MyApplication(); //Deconstructor
protected:
virtual HRESULT InitInstance();
virtual HRESULT ExitInstance();
virtual HRESULT ProcessNextFrame(CGapiSurface& backbuffer, DWORD dwFlags);
virtual HRESULT StylusDown(POINT p);
virtual HRESULT StylusUp(POINT p);
virtual HRESULT WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
private:
};If you look in the public section you can see that it contains the constructor you used in the main.cpp file above. Now if you look in the protected section you will see all of the virtual functions we want to override. Any variables you want to clear out, creation of surfaces, etc need to be done in the InitInstance() function instead of the constructor. Also any deletion of variables, etc needs to be in the ExitInstance() instead of the deconstructor. ProcessNextFrame is our render function, as you can see it passes in a reference to the backbuffer. Anything you draw onto this backbuffer will be displayed on the screen. You can also see the StylusDown and StylusUp methods and they both pass in the point the stylus was pressed or released at. (There are other methods too for dragging etc. all defined on the GapiDraw homepage) You may notice that there are no Key functions listed here even though they are available. Well those functions are for returning the 8 defined keys of GAPI which are suppose to be the 8 keys on the front face of all Pocket PCs. But guess what? They are not on all models. Some Compaq ipaq models are missing 2 of those buttons. So those are no good too us since we want to support all keys on all hardware. So what I have done is list WindowProc. If your unfamiliar with windows programming, windowProc is the function where you receive all of the messages from the OS and your window, including all mouse and keyboard activity. So what we want to do is create a system in the options of your game so you can bind whatever key they press and map it to a function in your game. So we capture the Key down and Key Up events in windowProc and feed them into our own function. (You can name it whatever you want) Now we also need to make sure all non-processed stuff by us gets filtered down so that CGapiApplication can do processing otherwise functions like StylusUp and StylusDown will not work. You may ask yourself why does GAPI have its own keys. Well one reason is some ghost keys can appear. (They actually mean something but what I don't know) I have only seen 1 ghost key and it can be easily filtered out as it happens every time you press a key, so just ignore it in WindowProc or in the function you filter the keys into. It's keycode is 91. In my function the keys are filtered too I simply do:if (dwKey == 91) //dwKey is a DWORD and is what is passed into my function
return;Ok now that you have seen some code and some tricks, I'll end the first Part here. If you have any questions or comments fill free to post them below.
[Edit]I had to split this up into post.. didnt realize the forum had max lengths[/Edit]
You can find GapiDraw located at: www.gapidraw.com
You can find ZSurface (while will be covered in a future feature) located at: www.warmi.net/zaurus/blits.shtml
-Tim aka Spock
#3
06/22/2003 (7:01 pm)
Hey, this looks really useful. You may want to clean it up a little a submit it as a resource.
#4
But the 2nd and the 3rd post looks pretty useful (if a bit over my head for casual reading), I'll be bookmarking this for further study later.
@Yacine has a point about cleaning it up and submitting it as a resource though, wouldn't want this piece to get lost in the jungle that is the GG forums.
06/24/2003 (12:22 am)
It's kind of hard to follow in the first post when you're jumping between the Pocket PC and Zaurus. Perhaps you might want to consider seperating them into two, one focussed completely on the Pocket PC and another completely on the Zaurus?But the 2nd and the 3rd post looks pretty useful (if a bit over my head for casual reading), I'll be bookmarking this for further study later.
@Yacine has a point about cleaning it up and submitting it as a resource though, wouldn't want this piece to get lost in the jungle that is the GG forums.
#5
06/24/2003 (8:22 am)
The beginning was more of an introduction, I plan to over time go in more depth on both systems.
#6
Your work in this area is getting better and better. I think a lot of people in the community would be interested in having this be a full resource. In fact, we should think about having an entire section of the sit dedicated to this. Maybe a forum section,a news sectoin, etc. If you are interested, send me an email.
-Jeff Tunnell GG
06/24/2003 (9:37 am)
Tim,Your work in this area is getting better and better. I think a lot of people in the community would be interested in having this be a full resource. In fact, we should think about having an entire section of the sit dedicated to this. Maybe a forum section,a news sectoin, etc. If you are interested, send me an email.
-Jeff Tunnell GG
#7
www.discordstudios.com/temp/newbguide.htm
[edit] if you have any problems with the link today, check it again tomorrow as we just transfered our dns yesterday so it may not be synced all over the net yet.
-Tim aka Spock
06/24/2003 (1:09 pm)
I am working on a cleaner version more geared toward newbies. You can checkout the introduction here and let me know if you think its simple enough to understand or any other comments:www.discordstudios.com/temp/newbguide.htm
[edit] if you have any problems with the link today, check it again tomorrow as we just transfered our dns yesterday so it may not be synced all over the net yet.
-Tim aka Spock
#9
-Tim aka Spock
07/31/2003 (10:33 am)
I havn't had time to work on it with getting our latest game out and working on the major update to the game before that... I'll get back to it when I get a chance.-Tim aka Spock
Associate Tim Newell
Max Gaming Technologies
Here is an example main.cpp:
int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPTSTR pCmdLine, int nCmdShow) { GDAPPCONFIG config; ::ZeroMemory(&config, sizeof(GDAPPCONFIG)); config.hInstance = hInst; config.pAppTitle = TEXT("App Name"); config.dwTargetFPS = 30; config.dwDisplayWidth = 240; config.dwDisplayHeight = 320; // Create the application MyApplication simple(config); // Start main loop return simple.Run(); }In the above code as you can see you create your child class of CGapiApplication and you construct it with a GDAPPCONFIG structure that sets the window handle, the text to be displayed in the window's title bar, the target Frames per second, the width of the window, and height of the window. (There are other options you can set as well that are defined on the Gapidraw homepage) Then you call its Run() member function which runs the application till the user shuts it down. This ran on your Pocket PC will be full screen while it will be in a window on your PC.