PocketPC Asteroids using Pocket Frog Library

Environment: [eg VC6 SP4, embeddedVC3, winCE 3.0/PocketPC2000/2002

Asteroids is an implementation of the classic game of the same name. The game was developed out of a curiosity to see just how difficult it was to develop a graphical application on a PocketPC system. As it turned out, I found an excellent, GPL licensed, graphics library that allowed the development of graphical applications using Visual C++ 6 on a desktop computer. The Pocket Frog library, located at http://frog.flipcode.com comes complete with quality source code and documentation.

Asteroids

The Asteroids game is fairly straight-forward the real interest is in the Pocket Frog library itself. Below is a description of the library by its creator Thierry Tremblay.

Pocketfrog Functions

PocketFrog also provide you with some functions: Display* FrogDisplay(); POINT FrogButtonLocation( int button ); void FrogShutdown(); Pixel FrogColor( int red, int green, int blue ); Surface* FrogLoadImage( const TCHAR* szFilename ); Surface* FrogLoadImageResource( unsigned resourceID, const TCHAR* szClass = RT_BITMAP, HINSTANCE hModule = 0 ); As with callbacks, continue reading to learn about the different functions and their usage.

Game Initialization

All the windows (and GAPI) initialization is done for you by PocketFrog. But before it start initializing everything it needs, PocketFrog will call you to let you have the chance to configure things. This is done through a callback called "GameInit":
void GameInit( FrogConfig& config );
PocketFrog will provide you with a FrogConfig structure filled with default values. Here is the definition of this structure:
struct FrogConfig
{
  enum Screen
  {
    SCREEN_FASTEST,      // Select the fastest screen 
                         // mode available
    SCREEN_PORTRAIT,     // Select a 240x320 screen
    SCREEN_LANDSCAPE     // Select a 320x240 screen
  };

  LPCTSTR  szWindowClass; // Window class name used
                          // for registration
  LPCTSTR  szWindowTitle; // Window title
  int      iconID;        // Icon resource ID
  bool     bSplashScreen; // Show the "PocketFrog" 
                          // splash screen?
  Screen   screen;        // Screen orientation 
                          // (default = portrait)
  bool     bGDISupport;   // GDI support wanted 
                          // for backbuffer?
};

The default values provided by PocketFrog have been chosen as to ease the life of less (or not so less) experienced developpers. For example, GDI support is disabled by default. If a user doesn't know how (or doesn't want to) use GDI, there is no reason to enable it and incur a speed overhead.

The first three fields deal with Windows specific stuff that you can safely ignore, although it is nice to have something else then the default icon for your game. To change the game's icon, you need to add an icon in the resources and set the "iconID" field to it's resource ID. If this doesn't make sense, forget about all that. The samples provide examples on how to do this.

Here is a simple example of providing the GameInit() callback, where we want to enable GDI support:

void GameInit( FrogConfig& config )
{
   // We want GDI support to output text
   config.bGDISupport = true;
}

Note that you don't need to do anything if you are happy with the default values provided by PocketFrog.

The default value for the "screen" is set to SCREEN_PORTRAIT, meaning that a 240x320 pixels screen. If you want a 320x240 screen, change the "screen" value to SCREEN_LANDSCAPE. The last possible value is "SCREEN_FASTEST" and will create a back buffer with the same orientation as the display buffer. This is for more experienced developers, as there is no way to know if a 240x320 or a 320x240 screen will be returned.

Warning: the PocketFrog initialization process has not started yet! This means that all the API functions are not safe to call (don't do it!).

Game Start

Once PocketFrog has asked you your preferences through GameInit(), it will proceed to initialize the display and everything else that needs it. When this is done, another of your callback will be called to notify you that the game is starting:

bool GameStart();

This is where the bulk of your own initialization must take place. This is where you load your bitmaps, this is where you allocate memory and gain access to all the resources you need. This is the last callback that is called before that game loop starts.

Since everything has been initialized on the PocketFrog side, you can safely call API functions such as FrogDisplay() to access the display.

The return value specifies whether initialization was successfull or not. If this value is false, the game will exit. If it is true, the game will start.

The Game Loop

The internal game loop will make sure that all Windows messages are processed as needed. Some of these messages will trigger events (example: a button is pressed, the screen is tapped, and so on). These events translate to calls to some callback. When there is no event to handle (ie: idle time is available), a special but very important callback is called:

void GameLoop();

This is where the bulk of your game processing time should be spent. In this callback you compute physics, do some AI and update the display. This is where your game code is.

This callback will be called as often as possible, meaning that no timing is done for you. If you want to limit your frame rate to a fixed number, you have to do it yourself (at the beginning of this callback).

Ending The Game

The game is running, everything is nice, but one needs to stop the fun at some point. This is done by calling the FrogShutdown() function. By doing so, you ask PocketFrog to exit the game loop and free all allocated resources.

Of course, the library can't free the resource you allocated yourself since it doesn't know about them. So just before PocketFrog shuts down itself, it will call one last callback:

void GameEnd();

In this callback, do all the cleaning that needs to be done. An alternative is to do nothing and let Windows sort it out! (I never wrote that).

Button Callbacks

The following callbacks are called when a button is pressed (down) or when it is released (up):

void ButtonDown( int button );
void ButtonUp( int button );

The parameter specifies which button is pressed. See the PocketFrog.h file for button definitions.

The following function is related to button and is used to get the position of buttons:

POINT FrogButtonLocation( int button );

The returned POINT structure contain the location (in pixels) of the specified button. Of course, the coordinates will fall outside the range of the display. The position of the buttons are taken from GAPI and I am not sure they are properly set for all devices. In any case, it works well on my Casio E-125.

Stylus Callbacks

The last three callbacks deal with stylus events:

void StylusDown( int x, int y );
void StylusMove( int x, int y );
void StylusUp( int x, int y );

StylusDown() is called when the stylus is put on the screen, the second one when it is dragged over the screen surface, and the last one when the stylus is lifted from the screen. In all cases, the x and y parameters report the location of the stylus on the screen.

Note that PocketFrog will transform the stylus coordinates returned by GAPI to screen coordinates for you.

Surfaces

A surface is the basic entity used to handle graphics. To create a surface, you must specify it's dimensions (width and height) in pixel. For example, to create a 128x64 pixels surface, you could use:

Surface* pSurface = new Surface( 128, 64 );

class Surface provides different methods to draw on the surface. Suppose you wanted to clear the above surface with the color blue and then draw a red rectangle on it. You would use:

pSurface->Clear( FrogColor(0,0,255) );
pSurface->FillRect( Rect(100,10,150,30), FrogColor(255,0,0) );

The "Rect" class is a helper that wraps Window's own RECT structure. Finally, the FrogColor() function is used to map the usual r,g,b color components to a Pixel color.

Direct access to the surface's memory is possible using the GetPixels() and GetPitch() methods. Here we are not using the GAPI convention to return the surface pointer. Instead, the pointer to the beginning of the surface is returned. This means that there is no need for two "pitch" values, only one will suffice and the value returned by GetPitch() is the usual "y" pitch.

The Display And The Backbuffer

Access to the display is gained by calling FrogDisplay() which will return a pointer to the Display object. This in turn can be used to access the back-buffer, which happens to be of class Surface. So if you wanted to clear the screen in green, you would do:

FrogDisplay()->GetBackBuffer()->Clear( FrogColor(0,255,0) );
FrogDisplay->Update();

Note the call to Update(), it is really important. This call will update the screen (what the user sees) with the content of the backbuffer. It should be called each time you finish rendering a frame. The concept of Update() is really similar to the concept of a "flip".

GDI Support

It is possible to create a surface with GDI support. To do so, simply create your surface using the GDISurface class instead of Surface:

GDISurface* pGDISurface = new GDISurface( 128, 64 );

Accessing and releasing the surface's DC is simple:

HDC hdc = pGDISurface->GetDC();
//... do some drawing ...
pGDISurface->ReleaseDC( hdc );

Note that each time you call GetDC(), a new DC is created for the surface. This can have a major impact on your performances, so be carefull when using GDI.

Finally, if you want your backbuffer to have GDI support, you have to ask for it in the callback GameInit(). The reason to do so is that PocketFrog always create the backbuffer for you and there is no way to change it.

Sound Support

The sound module design is not yet finish as music and repeating sounds have not been included yet. For this reason, no documentation is yet available. For more information about sound support, look at the "Sound" sample.

Hints And A Few Pointers

In this section I will provide advice to get the most out of PocketFrog.

  1. Always use surfaces that have multiple-of-8 dimensions (both width and height) for optimal performances. Lot of primitives are (or will be) optimized for multiple-of-8 surfaces. Some of the optimizations that are possibles are multiple pixels read/write instructions and loop unrolling.

  2. Some PocketPC are faster when using a 240x320 screen, and others are faster with a 320x240 display. To get the best performance possible, you should select "SCREEN_FASTEST" as the screen orientation in GameInit(). Unfortunately, doing so means that you have to handle screen orientation yourself.

  3. GDI support on the backbuffer might be nice, but it may be doing more harm then goods as you frame rate will drop considerably, even more on devices that already provide buffering such as the Casio E-125. If you really want to use GDI for fonts and text rendering, my advice is to create a GDISurface to do the GDI rendering, and the blit this surface to the backbuffer. Of course, the backbuffer should not have GDI support enabled.

Downloads

ARM exe - 180 Kb
MIPS exe - 180 Kb
SH3 exe - 180 Kb
Download source - 1.2 Mb


Comments

  • First times to find this program

    Posted by lyll on 09/12/2004 04:05am

    I have not download it. Can you mail this source to ch1d@sohu.com

    Reply
  • First times to find this program

    Posted by lyll on 09/12/2004 04:02am

    This Game is very interesting. I'd like to download it and have a study.

    Reply
  • ERROR: Program can not be executed; all the components (Libraries, etc.) where not loaded

    Posted by Legacy on 07/24/2002 12:00am

    Originally posted by: Daniel I. Kelley

    Could you help? I tried compiling (via embeddedVC3) the source for Asteroids program. When I try to execute the program on my Pocket PC 2000 received an error indicating that the program could not be run. Further the message suggests that all the components where not loaded (Libraries, etc.). Is there a compiler option for embeddedVC3 that would fix this? Any help is appreciated.

    I have a Cassiopeia E-125 with MIPS architecture running WINCE.

    Reply
  • Downloading source

    Posted by Legacy on 03/15/2002 12:00am

    Originally posted by: Tom

    As my quota is close to being exceed please download from
    frog.flipcode.com

    • The source

      Posted by Java-Guru on 12/27/2006 08:26am

      downloading

      Reply
    • Downloading source

      Posted by AlessandroFi on 01/01/2006 06:48am

      They are much onlooker.....

      Reply
    • First times to find this program

      Posted by lyll on 09/12/2004 04:06am

      I want to download it, the wonderful time is coming.

      Reply
    Reply
  • What about assembly optimization?

    Posted by Legacy on 03/13/2002 12:00am

    Originally posted by: FP

    Hi!

    All we need about all those GAPI interfaces available (also EasyCE, GapiTools) is assemlber optimization of blitting, drawing routines, etc. For now there's no such thing freely available.

    regards,
    FP

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: September 10, 2014 Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild." This loop of continuous delivery and continuous feedback is how the best mobile …

  • On-demand Event Event Date: September 17, 2014 Another day, another end-of-support deadline. You've heard enough about the hazards of not migrating to Windows Server 2008 or 2012. What you may not know is that there's plenty in it for you and your business, like increased automation and performance, time-saving technical features, and a lower total cost of ownership. Check out this webcast and join Rich Holmes, Pomeroy's practice director of virtualization, as he discusses the future state of your servers, …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds