Sponsored By

Games to Go: Le Voyage Dans La Lune:(Re)Making Games for Windows CE

In latest installment of the Games to Go series, Jim begins part to show you what's involved in creating the basis for a platform/Sierra-style game for Windows CE.

Jim Williams, Blogger

May 28, 1999

15 Min Read

In my previous columns, I've explained the nuts and bolts of handheld computers, and given evidence that worthwhile games are possible, and even profitable, to write for them. My view was most happily supported yesterday when I viewed packaged, commercial games for Windows CE on the shelf of my local Comp(body-cavity-search-before-exit)USA. In this two-part tutorial, I plan to show you what's involved in creating the basis for a platform/Sierra-style game for Windows CE. Note that I won't be handing over to you a finish product, but I do hope to do enough to guide you on the way. What I do intend to show you is how Windows CE differs from the other flavors of Windows, the basics of using the tools, some simple graphics effects, and some storage advice. I’ve included sample code and a demonstration game, which is part of an archive that accompanies this article.

Same Stuff, Different Day

First I must explain the title of this tutorial. Recently, I received a very special birthday present; the boxed set of the HBO miniseries "From the Earth to the Moon." In the final episode, Tom Hanks shares the tale of the first George Lucas; a Frenchman named George Melies. He was the first to do complex special effects, 70 years before there was anything known as Star Wars. With the current release of Episode 1 of that more recent saga, I felt the reference appropriate. For, in developing for handheld computers, we return to the early days of computer entertainment. Thus far, the most advanced of these machines are the 640x480 by 256 color and 16MB RAM HPC/Pro machines. In other words, machines about as advanced as the 386s that were state-of-the-art on desktops almost a decade ago. Once again developers face the joys and troubles faced by early game developers, such as limited memory, slow displays, limited graphics capabilities, but also the one-man development "team" who does it all. But, unlike the 386 era, the handheld developer will also have access to the same tools used by developers of games for Pentium systems. And before you pooh-pooh the idea of being able to make revolutionary, ground-breaking, or even simply profitable games for Windows CE, keep in mind that you still have more computing power in the palm of your hand than the entire multi-billion dollar computer systems which made possible a voyage... from the Earth to the Moon.

Getting Started

The basic tool of designing games for Windows CE is still the Visual C++ IDE. Add to this the Handheld and/or PalmPC SDK. The SDK is in two parts; one part downloadable and upgradable from the Microsoft developer web site, and the other you have to pay for, which includes the actual compilers for each cpu supported. Installation of the SDKs is rather straightforward and simple; just be sure of the directories you wish to use. You’ll probably require the standard Win32 directories, combined with the x86, mips, sh3, and other cpu-specific include and library directories, possibly the DirectX directories (if you do Windows 9x development), and the emulation environment. As you can see, specifying the directories to find the include files, libraries and source files can become confused.

To developer for Windows CE using the Visual C++ IDE, you'll also want to be running Windows NT, if possible, rather than Win9x. The reason for this is that the Windows CE emulation requires Windows NT to run, because Windows CE is more compatible with Windows NT than Windows 9x. For example, Windows CE only supports Unicode strings. Even though Windows 9x doesn't support the emulation environment, you can still develop for Windows CE on a Windows 9x machine – you just have to export your executable to a Windows CE device to test.

Once you have the IDE and SDKs installed, it's time to organize the project. Visual C++ allows you to organize multiple projects into a single workspace, which works out conveniently for handheld development. It also includes a "wizard", which takes you through the steps require to create a skeleton on which you will hang your program.

To MFC or Not to MFC

There are certain constraints imposed by the execution environment of Windows CE programs, which I'll be repeating throughout this tutorial. Primary among these is storage. Microsoft has created a set of classes to ease the creation of applications, the well-known Microsoft Foundation Classes (MFC). Designed for database-style applications, MFC is generally spurned by game developers. One of the accusations is code-bloat. Why include the MFC .dll which takes up storage space on the Windows CE device, when much of it will remain unused? Well, for one thing, in all but the oldest Windows CE machines, the MFC .dll occupies rom, not ram. So there's no storage overhead. And if you plan on creating a suite of games, or series, they can all use the MFC and save some small amount of storage. Or they can devote space to data which would otherwise go to custom routines. Developing for Windows CE devices largely restricts you to using the GDI; the slow refresh rate of most small lcd displays means that you don’t have to "bang on the hardware", or writing custom draw routines, for your games.

MFC also offers two other advantages for some programmers. First is the C++ class structure it imposes on you. MFC was a great help for me in the transition from C to C++. It provided a logical framework to guide me until I could understand the concepts behind classes and object-oriented programming. It also shielded me somewhat from the difficulties involved in event-handling code. But MFC also provides another advantage: fast prototyping. Using the Visual C++ IDE, you can create a fully functioning Windows CE program without writing one single line of code. The drawback to this is that you must use the MFC document/view class system. For most games, the document class isn't particularly necessary, but it can be used to organize and access the data for a Windows CE game. While I personally wouldn't bother with MFC for Win9x games, I've chosen to go with it for Windows CE games.

Creating the Framework

We're going to create the basics of a Sierra-style pseudo-platform game. I decided to call it Wizkid. This will require placing a graphic backdrop, with foreground elements, on the display, along with a number of sprites (the basic engine behind any platform style game). So fire up the Visual C++ IDE, and create a new project, as shown in Figure 1. Choose to create a WCE MFC Application (exe). In the lower right corner, select the x86 configuration; this is not a permanent limitation, but as we're going to be targeting the emulator first for testing purposes, you might as well select it now. In the upper right, title the project "WizCE" and tell it to create a new workspace. Move on to the next dialog, as shown in Figure 2. Here it will ask whether you want a single-document or dialog-based interface; there's no such thing as a multi-document Windows CE program (another difference between Windows CE and Windows 9x). The single window of a Windows CE application occupies the entire display.

figure1_small.gif

figure2_small.gif

Figure 1
[zoom]

Figure 2
[zoom]

The next dialog, shown in Figure 3, is pretty much irrelevant. You'll want to specify whether or not you wish help file support or a toolbar-style command bar buttons. In Windows CE, the titlebar and taskbar have been combined into a single toolbar called the CommandBar. You may not use a command bar at all, so deselect the toolbar button option. As for help support, help files use the HTML format, not the standard Windows format, and so they’re fairly easy to create. Choose to support help; since you will most likely be distributing your game via the Internet, you'll be including text- or html-based documentation anyway, so you might as well incorporate them into online help. You should have no need for ActiveX, Winsock, or database support, so make sure all of these are deselected.

figure3_small.gif

Figure 3
[zoom]

The following dialog, shown in Figure 4, has an important element for later. You should include source file comments (just because you can,) and be certain to select "As a shared DLL" for how you wish to use the MFC library; otherwise the entire thing will be statically linked into your code, bloating the hell out of it.

figure4_small.gif

Figure 4
[zoom]

The final dialog, seen in Figure 5, merely gives you a summary of what you've chosen. Make sure all the settings are correct, choose OK, and let the compiler create a program for you. Once it has finished, check to make sure that you're targeting the right platform, as shown in Figure 6 (in this case, H/PC version 2.00). This is the version of the operating system that the emulator runs.

figure5_small.jpg

figure6_small.jpg

Figure 5
[zoom]

Figure 6

Go Fever

At this point, you can look over the class hierarchy, and try to get familiar with it if you're not already. You might also try a test compile. It should compile and run, (first build all, then select execute WizCE.exe from the menu.) If you get an error during the compile or link stages that has to do with files or libraries that it can't find, check your directories options. If you get an error during execution regarding files or libraries it can't find, first get the name of the file it's looking for, then search your system for the file. If the file doesn't exist, something went wrong during the compile/link stage. If you find it (and in this case it's usually a .dll file), copy it over to your emulation environment’s "windows" directory (I've run into this problem with MFCCE20d.dll.) When you're confident you have a working program, move on to adding the code which will create our game

Single Operating-System Portability

This phrase might like an oxymoron, but when creating a game for Windows CE, you have to take into account the different platforms you may have to, or choose to, support in the future. The older Windows CE machines, running Windows CE 1.00, are limited to 2-bit displays, a custom bitmap format (.2bp) and can have as small as 480x240 displays. Now, the SDK will automatically convert .bmp files to .2bp format for you, when you target version 1.0 or 1.01 of Windows CE (as I discovered to my pleasant surprise.) But, you still must know how and where you're going to display those bitmap images. The latest and greatest devices range from 240x320, four gray-scale displays to 640x480 8-bit displays, with 800x600x16-bit supported by the H/PC Pro. Therefore, the first thing we want to do is find out what display environment we're working in. The way we find this out is with GetSystemMetrics(). Where you make this call is up to you, just so long as you do it before you draw to the display. I chose to place it in the constructor for the CWizCEView class.

Setting Up the Display

Add four int variables to the CWizCEView class: CScreenWidth, CScreenHeight, CViewOffsetX, CViewOffsetY. We'll use these to retrieve the width and height of the screen, and to calculate the offset required to center the view on the display. The first thing we do is get the width and height of our display.

// get the width of the
// screen and save it for later
CScreenWidth = ::GetSystemMetrics(SM_CXSCREEN); CScreenHeight = ::GetSystemMetrics(SM_CYSCREEN);

// determine what display we're using so we can
//tell which .BMP to display
If(CScreenWidth > CScreenHeight) {
COrientation = HPC;
if(CScreenHeight > 240)

COrientation = PROPC;
}
else {
COrientation = PALMPC;
}

 

We also need to add an enum for which display orientation we're using:

enum { HPC, PALMPC, PROPC };
int COrientation;

Depending upon the orientation, we'll use either a bitmap that is 320x200, or 240x240. The display orientation would not determine what bitmap we use, because we'd be using a tilemap to draw the display. But for now we're just pasting a .bmp to the screen. Try to compile this; there should be no noticeable difference in the application, but now is a good time to test this part of the code before we go on.

Showing the Backdrop

Now it's time to add the .bmps we'll be using. We'll add them right into the project for now, rather than having them accessed as files later. That prevents some headaches and saves the overhead of writing the file access routines. Later we won't do this, because we'll want the ability to change bitmaps without recompiling the application (for developing a sequel, for example.)

How to include bitmap resources in a Visual C++ project is beyond the scope of this article, so I'll just say that you should add two bitmap resources for Hall1.bmp and Hall2.bmp, and name them Hall1 and Hall2. Hall1 is the landscape orientation of the background bitmap for HPCs, and Hall2 is the portrait orientation for PalmPCs. Create a CBitmap class object as part of the CWizCEView class called "Background". Insert the following code into the CWizCEView() constructor after the code we've just added:

 

if(COrientation == PALMPC){

 

CViewOffsetX = (CScreenWidth - WPORTRAIT)/2;
CViewOffsetY = (CScreenHeight - HPORTRAIT)/2;
CViewWidth = WPORTRAIT;
CViewHeight = HPORTRAIT;
Bitmap.LoadBitmap(TEXT("Hall2"));
}
else {
CViewOffsetX = (CScreenWidth - WLANDSCAPE)/2;
CViewOffsetY = (CScreenHeight - WLANDSCAPE)/2;
CViewWidth = WLANDSCAPE;
CViewHeight = HLANDSCAPE;
Bitmap.LoadBitmap(TEXT("Hall1"));

 

}

What we do here is straightforward, preparing for the future. Depending upon the orientation of the display (landscape for HPCs, portrait for PalmPCs), we set the view offset with this formula, which centers the bitmap in the display. We'll have to use these offsets for all of our drawing, to keep the backdrop, sprites and foreground objects all displayed in the same screen area. The Loadbitmap calls load the appropriate bitmap from which to get the backdrop imagery, again dependent upon the display orientation. For HPCs or HPC Pros, it selects Hall1.bmp, the landscape orientation. For PalmPCs, it selects the portrait orientation.

The TEXT macro is one of those Windows CE gotchas you need to watch out for. For Windows 9x, the LoadBitmap call uses a LPCSTR pointer; in MFC, they use the _T() function to convert to Unicode; in Windows CE, we have the TEXT macro. Basically all this does is convert a 1 byte/character ANSI string into a 2-byte/character Unicode string.

On Draw

The OnDraw() function within the CWizCEView class is the document/view architecture's equivalent of the standard Windows OnPaint() call. It is here that we use the standard GDI calls to blit the background bitmap to the screen:

CDC memDC;
memDC.CreateCompatibleDC(pDC);

//Select Bitmap into Memory DC
memDC.SelectObject(&Background);

pDC->
BitBlt(CViewOffsetX,CViewOffsetY,
CViewWidth,ViewHeight,&memDC,0,0,
SRCCOPY);

The background is a lot easier to blit than the sprites will be. Windows CE supports a subset of the ROP calls that Windows 9x and Windows NT support. pDC represents the PaintDC pointer that is passed to OnDraw. The memDC allows us to prepare the Background bitmap before blitting it to the screen. SRCCOPY does a straight copy, overwriting everything underneath. Later, when we piece together the foreground and background imagery from separate bitmaps, we'll use other ROPcodes to create a stencil.

With the variables we've set up, we can use a bitmap of whatever size we choose, and automatically adjust display for PalmPCs, H/PCs, and even the newer Pro machines with the higher resolution display. If more display types become available, it might be preferable to change the if/else statements into a switch/case procedure.

What you should see in your desktop emulation if everything went right is shown in Figure 7. I have my emulation environment set to dimensions of 480x240, a remnant of another project.

figure7_small.jpg

Figure 7
[zoom]

Conclusion of Episode I

In this half of the tutorial, we examined the development environment, learned a couple of differences between Windows CE and Windows 9x, judged the pros and cons of MFC for use in Windows CE game development, and set up the basics for the display functions of a Windows CE game. In the second half, we'll really get busy. I'll go into the animation requirements for sprite images (including the required bitmasks,) discuss the unique control system involved in a pen-based interface, examine the "object store", and suggest a technique for storing image data in a reusable, extensible form.

Jim has been involved in developing software since 1980, and has developed a taste for operating systems as esoteric as AmigaDOS and PalmOS. He's currently working on an RPG engine for Windows CE. His only advice for someone trying to program Windows is, "Punching the monitor hurts you more than Microsoft". He can be reached as [email protected].

Read more about:

Features

About the Author(s)

Jim Williams

Blogger

Jim has been involved in developing software since 1980, and has developed a taste for operating systems as esoteric as AmigaDOS and PalmOS. He's currently working on an RPG engine for Windows CE. His only advice for someone trying to program Windows is, "Punching the monitor hurts you more than Microsoft". He can be reached as [email protected].

Daily news, dev blogs, and stories from Game Developer straight to your inbox

You May Also Like