As a programmer at Overloaded, a Dutch developer and distributor of games for mobile devices, I have developed several games for Pocket PC and Symbian, like Fantom Overdrive, a 3D arcade racer, and Resistance, a voxel-based shoot-'em-up. Overloaded launched at the end of 2001, initially developing games for Pocket PCs. Shortly after that, we switched to Symbian-based smartphones. Now we primarily target the Symbian OS (series 60) and J2ME. Overloaded games are small -- typically less than 300KB -- as we distribute them "over the air". This makes it challenging to create fun titles, complete with state-of-the-art technology like Bluetooth, multiplayer, and textured 3D graphics. To support 3D graphics of our games, I developed a 3D engine, "NGine3D," specifically designed to be used in small games.
Having developed several games for mobile devices, I understand that the market for mobile games is a tough. There are several advanced platforms, like Microsoft's Pocket PC and Smartphone, and the Symbian OS. However, the individual markets for these platforms are small, and the only way to make profitable quality games is by porting early PC games - work that's typically outsourced to countries where labor is cheap.
Another option is to develop a game for multiple devices simultaneously. Unfortunately, this option requires technical knowledge of multiple operating systems, which (especially in the case of Symbian) can be problematic. But there is a solution to this: using a library that hides platform differences and offers a common application development base. Such a library would help build a multiple platforms and frees the developer of OS specific issues. In this article I explain how to build such a library.
Brothers in ARMs
devices that Overloaded has developed for so far have much in common.
The Pocket PC, Smartphone, and Symbian series 60 and 70 all use
ARM or ARM-based processors, clocked somewhere between 100-400MHz.
As the devices with smaller screens tend to use the lower clock
speeds, the performance levels of the devices are comparable. Most
devices use portrait displays. All displays are capable of high-color
graphics (12- or 16-bit color), none of them has an FPU, and of
course, there's no hard drive, limiting available storage.
Table 1: ARM-based handheld devices with similar capabilities.
There are differences too. Most notable are the varying resolutions: e.g., 176x208 for Symbian, 240x320 for the Pocket PC and 176x220 for Microsoft Smartphones. Pocket PCs use a stylus in addition to the buttons, whereas the Sony P800 (Symbian series 70) also uses a stylus but has virtually no buttons. The most important difference, of course, is the operating system. The Pocket PC operating system closely resembles Windows, but the Symbian OS is quite different.
I included the GP32 in the list because it is quite close to the other devices, although its screen is oriented in the landscape direction. The Zodiac has hardware-accelerated 2D functions, which makes it slightly different from the other devices.
If we ignore the operating system differences for a moment, what we have is an extensive list of devices with similar capabilities. And this represents lots of small markets with consumers waiting for cool games. If you could serve Symbian users, Pocket PC users, and Palm Tungsten-T users the same game, and get the same title working on the GP32 with minimal effort, that would expand your game's market without too much porting effort required.
Before I started working for Overloaded, I created games for the Pocket PC in my spare time. As I was struggling to get easy access to the frame buffer and other hardware of the devices, I developed a small library called EasyCE. This library served as an abstraction layer on top of the operating system: It initialized the OS, prepared a linear 16-bit frame buffer, and after starting the game, it passed mouse positions and button states to it. To be able to develop and debug under Windows, I also implemented the HAL for windows, using the same API.
EasyCE became quite popular among Pocket PC developers. Since the library and its source code are free, it served as a "knowledge base" for Pocket PC issues, as it was frequently updated to cope with various quirks of newly released devices. These days there are better libraries for the Pocket PC, especially since Pocket PC coders are more frequently coding in assembler to achieve faster screen rotation (not all Pocket PC displays are oriented in portrait mode internally) and direct access to the LCD controller. Nobody dared to follow my "business model" though.
When Overloaded started developing for Symbian, I followed the same approach. The new library, "Easym-b", again allows us to develop for Windows CE and Symbian simultaneously. With it we bypass the ugly Symbian emulator, improve debugging, and generally cut down development time tremendously. Theoretically, you could develop a game for Symbian without actually owning the device.
Obviously, it would be nice if this could be taken a couple of steps further. First, it must be possible to write a game for Symbian and Pocket PC simultaneously. Second, there are some other new devices that look promising as mobile game platforms. The Zodiac, the GP32, and some of the latest Palm devices also happen to use ARM or ARM-based processors. So, ideally, the new library should not only support Symbian and Pocket PC, but also allow new platforms to be plugged in. Once the "OS abstraction layer" for the new device is written, existing games built on the library will at the very least compile without modifications. The bottom line is that game coders can concentrate on what they do best: Game coding, without spending endless hours researching the OS and device vagaries.
"Mobilecore" is a library that aims to do just that. It does nothing more than abstract the absolute core of each supported OS: it initializes the OS (WinMain), and handling hardware (mouse/stylus, buttons, vibration, sound, and perhaps communications). Currently, Mobilecore supports Win32, Pocket PC, and Symbian.
Mobilecore consists of a small set of sources: One source and one header for each supported platform, plus a surface class. The platform-specific source implements a class named Core, from which a game can be derived. The Core class is the interface for the game to the OS, and vice versa.
Abstracting the Symbian OS
As the Symbian OS is the most limiting of the supported operating systems so far, I will use it to describe the structure of the library.
Tapwave's Zodiac with hardware-accelerated 2D functions
When developing an application for Symbian, you can choose between an "exe" and an "app." The "exe" form is used to build applications that do not need a user interface, so it is primarily used for services. Exe programs do not appear in the menu of the phone, although you could start them using a small launcher app. They also have limited access to other processes and to the Symbian's GUI. It is hard to get to system events such as incoming phone calls. As we want a game to behave as nicely as possible when running on a phone, the preferred type of application is the "app" form.
The "app" is basically a DLL. The "app" must supply a method named NewApplication that returns a pointer to a CEikApplication. From here, a typical Symbian application instantiates a "document" (derived from CEikDocument) which has one or more "controls" (derived from CCoeControl). To behave nicely under the Symbian OS, we will implement our game as a control.
you are beginning to understand what the main problem is with Symbian:
It's a bit strange Symbian series 60 is notorious for its large
number of frameworks, classes, and templates and general unforgiving
nature to programmers. Debugging is hard, while information is sparse
and often inaccurate or incomplete. And the OS simply does not appear
to be made for games. If you thought Windows was terrible after
you coded in mode 13h for years, prepare for your next nightmare.
Here lies a great task for Mobilecore: Let's get it over with once
and for all.
Listing 1: Setting up the core control under Symbian
Listing 1 shows the main part of the control initialization. The control creates a window for itself (CreateWindowL), tells the OS how much screen real estate it will be using (SetRect), and activates itself for drawing (ActivateL). It then creates a bitmap and starts a timer that calls a callback function 40 times a second. The timer is an odd thing by the way: Symbian does not let you time things with more accuracy than 1/64th of a second, yet you specify timer intervals in microseconds. This timer issue is nasty: It makes it virtually impossible to determine the frame rate of a 3D game, for example.
The ARM processor has some onboard high-precision timers, so it's possible to get more accurate timing. This requires some assembly coding though.
Since our Symbian application is now heavily based upon this timer ticking 40 times a second (or any other interval), the Mobilecore library does the same. Therefore, the game class that we derive from the Core class must at least implement a Tick() method (see code listing 2). A game based on this is going to be state-driven.
Listing 2: Symbian version of the Core class declaration
The Mobilecore library tries to stick to its core task as much as possible: Hiding OS specifics. Therefore, the other methods in the Core class are all very simple. There are some methods for retrieving the stylus position and whether or not it touches the screen, and there are two callback functions for handling button state changes.
Two methods are more noteworthy, however: GetSurface and FullPath.
The Symbian OS does not use relative paths. That means that opening ERROR.LOG opens a file in the root of the file system, not a file in the directory of the executable. FullPath fixes this problem: It simply expands a given file name so that it includes a full path.
The GetSurface method returns a pointer to a surface, which is a simple class that manages a pixel buffer. Strictly speaking, everything but the creation of the bitmap is platform independent, so the surface class is not absolutely needed. However, I decided not to be extremist here: Symbian uses a 12bit frame buffer, while the Pocket PC uses a 16-bit buffer, and then there's the resolution issue. The surface class is therefore the only piece of code that is going to need a lot of OS-specific code: Loading images and other graphics operations need to be able to handle the vagaries of the devices.
That's pretty much all there is to it. It's a simple frame, and it can easily be ported to the Pocket PC.
can load the Symbian version of Mobilecore in Visual C++ 6.0; it's
included in the workspace file. You cannot build a final version
from the Visual Studio IDE this way, but you can check for errors.
Just hit F7, and the external compiler will be used to check for
problems, which can be clicked in the usual manner. Compiling the
final package must be done from the command line. (Check the relevant
documentation for details.) Note that we used the 0.9 SDK; later
revisions only add support for specific features of newer devices
so it is not necessary to upgrade.