symbian os workshop
TRANSCRIPT
-
8/6/2019 Symbian OS Workshop
1/48
-
8/6/2019 Symbian OS Workshop
2/48
Symbian OS Workshop
2005 Mopius Page 2/48
Introduction
In this tutorial you will get to know some of the basics of developing for mobile
phones using C++. All the examples target Symbian OS and the Series 60 UI platform.
Instead of long, theoretical explanations, a more practical approach is used.
First, you will learn how to create your own mobile project. Then, you will add the
prewritten game logic of a small Arkanoid-like game called Mopoid. This provides an
interesting way to get to know important aspects of developing for Symbian OS,
including:
defining and using menus, handling and displaying text, loading and showing images, writing and reading data to/from files, using a timer for periodic events, ... and many more smaller, but equally important topics.
You will see the results of your actions right away. Whenever some Symbian OSspecifics comes into sight (like memory handling), a short explanation will give you a
brief overview of why it is this way and how to work with it.
Of course, only the surface of all those topics can be scratched, as each of them would
easily fill a tutorial of their own of this size. However, this tutorial will give you a basic
understanding of how developing for mobile phones using C++ works, and it is a good
starting point for your own projects.
I hope that you have fun working your way through the tutorial and that you will get a
nice game out of it!
- Andreas Jakl
-
8/6/2019 Symbian OS Workshop
3/48
Symbian OS Workshop
2005 Mopius Page 3/48
Contents
Step 0 - Preparation........................................................................................................... 5Getting started ................................................................................................................ 5Choosing an IDE ........................................................................................................... 6Choice of the Series 60 SDK........................................................................................ 7
Step 1 - Defining the Symbian OS SDK........................................................................ 8Step 2 - Creating a new project........................................................................................ 8Step 3 - Testing the project .............................................................................................. 9
Troubleshooting: .......................................................................................................... 10Step 4 - Defining strings ................................................................................................. 11Step 5 - Defining the menu ............................................................................................ 12Step 6 - Displaying the about box ................................................................................. 14
If something doesnt work... ....................................................................................... 16Step 7 - Getting the application to the mobile phone! ............................................... 17Step 8 - Adding the game engine to your project........................................................ 18
Unzipping the file......................................................................................................... 18Distributing the game data.......................................................................................... 18
Adding the source files to your project..................................................................... 18Adding additional libraries to the project definition file......................................... 19Defining new text......................................................................................................... 20New game...................................................................................................................... 20
Adding graphic and sound files.................................................................................. 20Testing............................................................................................................................ 22Troubleshooting ........................................................................................................... 22
Step 9 - Loading images .................................................................................................. 22C and T classes ............................................................................................................. 23ConstructL..................................................................................................................... 23Loading bitmaps........................................................................................................... 24Deleting images ............................................................................................................ 26
Step 10 - Displaying the graphics..................................................................................... 27Handling transparency................................................................................................. 28Drawing a bitmap......................................................................................................... 28
Step 11 - Handling keys..................................................................................................... 29
-
8/6/2019 Symbian OS Workshop
4/48
Symbian OS Workshop
2005 Mopius Page 4/48
Step 12 - Displaying text ................................................................................................... 31Setting a font ................................................................................................................. 31Reading text from the resource file ........................................................................... 32Formatting and displaying the text ............................................................................ 32 Aligning text .................................................................................................................. 32
Step 13 - Reading and writing files.................................................................................. 34Preparation .................................................................................................................... 34Setting the file name..................................................................................................... 34Opening the file ............................................................................................................ 35Creating the stream ...................................................................................................... 35
Writing the data ............................................................................................................ 35Closing the file .............................................................................................................. 36
The Cleanup Stack ....................................................................................................... 36Loading .......................................................................................................................... 37Cleanup when your application is uninstalled.......................................................... 38Building from the command line ............................................................................... 40
Step 14 - Setting the application icon.............................................................................. 40Step 15 - Handling being in the background ................................................................. 42Step 16 - Periodic Events.................................................................................................. 44
Keeping the backlight on ............................................................................................ 44Using a timer................................................................................................................. 45Stopping the timer........................................................................................................ 45
Step 17 - Final notes .......................................................................................................... 46About the author.......................................................................................................... 46Contact........................................................................................................................... 46Copyright....................................................................................................................... 47
Step 18 - Exercises ............................................................................................................. 48Alternative key handling.............................................................................................. 48Define more levels ....................................................................................................... 48Saving the game progress............................................................................................ 48
-
8/6/2019 Symbian OS Workshop
5/48
Symbian OS Workshop
2005 Mopius Page 5/48
Step 0 - Preparation
Download the following components:
ActivePerl: needed by the Symbian OS tool chain to compile your project http://www.activestate.com/
Symbian OS SDK: this tutorial uses the Series 60 SDK 1.2 for Symbian OS,Nokia Edition to provide the best compatibility with older Series 60 devices
http://www.symbian.com/developer/sdks_series60.asp
Microsoft Debugging Tools: needed to debug applications in the emulatorthrough Borlands C++BuilderX
http://www.microsoft.com/whdc/devtools/debugging/
Visual C++ Toolkit: only needed if you dont have Visual Studio 6 or .netinstalled. Its free and needed to compile the projects for the emulator. Go to
http://www.microsoft.com/downloads/and search for Visual C++ Toolkit to
download it.
Borland C++BuilderX Mobile Edition (v1.5): get it for free by filling out theshort survey at http://info.borland.com/survey/cbx15_mobile_edition.html
Install the components in the order listed above. Allow all installations to add the
programs to the systems path variable, in case they ask! Its recommended that you
install the Series 60 SDK to its default location at C:\Symbian\ !
Getting started
Should your application crash in the emulator, there is a way to make it display a more
helpful error message. To activate this feature, create an empty file called ErrRd
inthe C:\Symbian\6.1\Series60\Epoc32\Wins\c\system\Bootdata directory of
your Series 60 SDK. Thats it.
When you first start your copy of C++BuilderX Mobile Edition, it needs to be
registered. Choose the activation file option, and locate the file that Borland sent you
after you filled out its survey and registered for its development network.
http://www.activestate.com/http://www.symbian.com/developer/sdks_series60.asphttp://www.microsoft.com/whdc/devtools/debugging/http://www.microsoft.com/downloads/http://info.borland.com/survey/cbx15_mobile_edition.htmlhttp://info.borland.com/survey/cbx15_mobile_edition.htmlhttp://www.microsoft.com/downloads/http://www.microsoft.com/whdc/devtools/debugging/http://www.symbian.com/developer/sdks_series60.asphttp://www.activestate.com/ -
8/6/2019 Symbian OS Workshop
6/48
Symbian OS Workshop
2005 Mopius Page 6/48
Choosing an IDE
The Symbian OS build tools are actually command line-based and would work without
any IDE. However, development is more comfortable if you use one. There are severalchoices, each with advantages and disadvantages1:
Fast; efficient compilation and debugging;some tools for Symbian OS available
Microsoft Visual C++ 6
Old; no real support for Symbian OS codedevelopment
Fast; modern and good IDE; WidespreadMicrosoft Visual Studio .net
Not directly supported by the Symbian OSSDKs makes development for Symbian OSeven more complicated; expensive
Symbian OS at least partially integratedMetrowerks CodeWarrior
Not so cheap; IDE more difficult to masterat the beginning
Supports visual design of menus anddialogues; Symbian OS related features;currently free!
Borland C++BuilderX MobileEdition 2
Slow and clumsy IDE; Symbian OSintegration should go farther.
Very good IDE; free!Eclipse
No support for debugging; Symbian OS notreally integrated yet.
As you can see, there is no obvious best way to develop Symbian OS C++
applications. For this tutorial, Borlands C++BuilderX was chosen, because it is free
and it takes away much of the initial complexity when starting with Symbian OS, even
though the IDE itself still needs a lot of improvement.
Please note: The list above is based on personal impressions. CodeWarrior could also
be a very good choice, especially now that its mobile edition was bought by Nokia and
will be actively improved in the future.
1 All products are trademarks of their respective owners.
2 Will be referenced as C++BuilderX in this tutorial.
-
8/6/2019 Symbian OS Workshop
7/48
Symbian OS Workshop
2005 Mopius Page 7/48
Choice of the Series 60 SDK
The Series 60 SDK for Symbian OS is available in higher version numbers, which target
newer Series 60 phones. Up to now, the devices have always been backwardcompatible, so an application developed for Symbian OS v6.x mobile phones (using the
SDK v1.2) also works on newer Symbian OS v7.0s and v8.0 phones.
While applications compiled using the SDK v2.0 (which mainly targets the Nokia 6600
with Symbian OS v7.0s) should still work on older devices, this can be a bit
problematic. If the source code is compiled by even newer SDKs, the files are not
backward compatible on a binary level any more.
Which version of the SDK you use is entirely your choice. If you only want to developfor newer phones, or if you want to do new things that were not possible before, go
with (at least) the SDK v2.0. Loading images and sounds has been specifically
improved. Internet (HTTP) connections are easier to handle as well.
If you want to develop a commercial application that should reach the broadest
possible audience, you shouldnt exclude older Series 60 phones. By choosing to target
Series 60 you already restrict your potential market. If you limit your target audience
even more by making your program only compatible to the newest phones, you willhave an even harder time selling it.
-
8/6/2019 Symbian OS Workshop
8/48
Symbian OS Workshop
Step 1 - Defining the Symbian OS SDK
Its time to start working! Open Borlands C++BuilderX Mobile Edition. Go to
Tools
Symbian SDK Configuration. Create a new SDK configuration, using theSDK Template of the SDK you have installed, in this case: Symbian Series 60 1.x
(Microsoft version). At least for the SDK v1.2, do not use the Borland SDK
version, otherwise compiling the project wont work! Set the path as shown in the
screenshot, and choose an appropriate name like Series 60 1.2.
Fig. 1 Defining the Symbian OS SDK in Borland's C++BuilderX.
Step 2 - Creating a new project
Create a new project: File
New...
Series 60
Series 60 GUI Application.
Fig. 2 Creating a new Symbian C++ project.
Enter Mopoid as its name (dont use a different name for this project, otherwise
some includes of the prewritten files we will include later on wont work). Place it in the
C:/Symbian/dev directory and let C++BuilderX create a project subdirectory, so
that all your projects will be kept separated from each other.
2005 Mopius Page 8/48
-
8/6/2019 Symbian OS Workshop
9/48
Symbian OS Workshop
Fig. 3 Defining properties of the project (Step 1).
Go to the next step. Enter the same name for the project, Mopoid. As we want to do
a game, choose Full Screen as view type.
The default UID3 proposed by C++BuilderX should NOT be used. Change the UID
to something between 0x01000000 and 0x0FFFFFFF Symbian reserved those IDs
for testing projects. Every application installed on a phone has to have its own unique
UID. Therefore, if you want to release your game to the public, send a mail to
[email protected] containing your name and how many UIDs you need (5
should be sufficient for the beginning). They will send you the UIDs as soon as
possible.
Fig. 4 Defining properties of the project (Step 2).
Step 3 - Testing the project
Your workspace should look similar to the screenshot in Fig. 5. Now is the time to test
your project to see if everything is configured correctly. Press the Run Project button
(F9).
2005 Mopius Page 9/48
mailto:[email protected]:[email protected] -
8/6/2019 Symbian OS Workshop
10/48
Symbian OS Workshop
Fig. 5 This is what the default workspace of Borland's C++BuilderX looks like.
If everything works well, the emulator will show up after some time. Deactivate the
memory resident virus scanner if you have one running to make this process a bit
faster. Your own application will be located at the bottom of the menu, so move down
using the cursor keys to select it.
If you dont want to do this every time you test your game, select it, press the leftsoftkey (Options), choose Move and move it to the upper left position of the
menu. It will stay there even if you close the emulator and start it again.
When you start the Mopoid application, you will only see a white screen. This is
because we chose to create a full screen application, which does not have a visible
status or menu bar. When you press the left softkey, a default menu will show up. In
the next steps we will adapt it to our needs.
Troubleshooting:
If Microsofts VisualStudio.net or Microsofts toolkit is installed on your PC and
Borland C++BuilderX uses this compiler for the Series 60 SDK v1.2, you may get this
error message:
LNK2019: unresolved external symbol __ftol2
2005 Mopius Page 10/48
-
8/6/2019 Symbian OS Workshop
11/48
Symbian OS Workshop
2005 Mopius Page 11/48
To solve this problem, open the file
C:\Symbian\6.1\Shared\EPOC32\Tools\cl_win.pm in a text editor, search for
the line that contains /W4 and change it to CLFLAGS = /nologo /Zp4 /W4
/QIfist (youre adding the /QIfist parameter to the options).3
Should C++BuilderX display errors like this during the build process:
Can't locate E32env.pm in @INC [...]
one possible solution is to put the following two paths at the beginning of your path
environment variable:
C:\Symbian\6.1\Shared\epoc32\gcc\bin;C:\Symbian\6.1\Shared\epoc32\tools;
If this doesnt help, make sure that Perl is installed and do a repair install of the
Symbian OS SDK, basically making sure that the SDK is installed after Perl on your
system.
Make sure that you close the emulator window after you are finished with testing your
project! If you want to compile and the emulator is still running in the background, you
will get several error messages!
Step 4 - Defining strings
By default, the MopoidContainer.akn file should be active. If it is not, open it
through the project window on the left: Mopoid.cbx Symbian project (bld.inf)
Mopoid.mmp Designs MopoidContainer.akn (double click).
To make our own menu items, we first have to define the text that we want to use. On
Symbian OS, text is normally defined in resource files. This makes it easier to localize
applications, as mobile phones are global and you will probably want your game to be
available in more than one language. Switch to the String Table designer:
3Thanks to Simon Woodside for this tip see http://simonwoodside.com/weblog/2004/07/18
http://simonwoodside.com/weblog/2004/07/18http://simonwoodside.com/weblog/2004/07/18 -
8/6/2019 Symbian OS Workshop
12/48
Symbian OS Workshop
Fig. 6 switching to the string table designer.
In the game we want to have a simple menu that allows us to start a new game, display
an about box and quit the game. Therefore, define the following four strings:
Fig. 7 Adding new strings to the resource file of the application.
For the message in the about box (r_aboutmessage), you will first have to increase
the Max Length to something like 60, so that you have enough room for your
message. Use \n to tell the system where to start a new line. Always press enter after
you finished writing the text to a cell, to make sure that C++BuilderX keeps your new
text.
Please note: For this tutorial, enter the names exactly as described. In a later step, you
will add some prewritten source files to your project, which assume several name
definitions.
Step 5 - Defining the menu
Its time to use our strings in the game. Switch to the Menu designer. You will see that
C++BuilderX has already created two menu items for you. We need one more, so
select the menu item tool on the left pane, and click into the menu to add a new item at
the bottom of it:
Fi . 8 Addin a new menu item usin the desi n tool.
2005 Mopius Page 12/48
-
8/6/2019 Symbian OS Workshop
13/48
Symbian OS Workshop
Now well adapt the menu items so that they use the text weve just defined.
Select iMenuItem1 by clicking on it. In the panel on the right, change its name to
iMenuItemNewGame. For its text, just choose our resource r_startgame for theID. Leave the command at its default value of 1001.
Please note: Its important that you press Enter after modifying a value. If you just
switch away, its possible that your input isnt saved.
Fig. 9 Setting the properties of a menu item.
Then, change the name of iMenuItem2 to iMenuItemAbout; choose r_about
for its Text-ID. The command 1002 is fine. Also check the second flag,
EEikMenuItemSeparatorAfter. This will create a small line below this menu item,
visually separating the third (Exit) command from the other items.
Last one is the menu item to quit the game. Change its name from iMenuItem3 to
iMenuItemExit and use r_exit for the Text ID. This time, we will not keep the
standard command ID, but use the EAknCmdExit command. This command will
also be sent to your application if the operating system wants to shut it down, for
example when the phone does not have enough memory left. Therefore it is required
that every application always responds to this event and instantly shuts the application
down.
If you try your game now, you will see that the Exit menu item will already work fine!
When testing the game in the future, always quit your application using the exit
command and dont just close the emulator. The reason is that the environment of the
emulator will automatically do a memory check and inform you if you have a memory
leak. If you just shut down the emulator, you will only discover it many hours later,
making it a lot more difficult to find the reason.
2005 Mopius Page 13/48
-
8/6/2019 Symbian OS Workshop
14/48
Symbian OS Workshop
Step 6 - Displaying the about box
Up to now, weve created a small application with its own menu, without writing a
single line of code. For displaying the about box, the first line of code has to be written.
Switch to the Non-visual design view:
Fig. 10 Adding an about box to the application.
Select CAknInformationNote in the tools panel (left). This is a simple small window
that will contain your text and a small, predefined icon. Next, click anywhere in the
white middle section to create the note. In the properties window on the right, change
its name to iAknAboutNote and choose the r_aboutmessage as the text ID.
Now weve defined the about box, to display it we just have to connect it to the about
menu command. Switch back to the menu designer, choose the About menu item.
Fig. 11 Calling the about box through selecting the menu item.
In the properties section on the right, switch to Events. Double click in the empty
text box next to OnViewCommand. C++BuilderX automatically creates a function for
you that will be called when the user selects this menu item and places you there. But
before writing any code, switch back to the MopoidContainer.akn and change the
name of the function the IDE has just created to
OniMenuItemAboutViewCommandL, basically adding an L at the end of the name.
2005 Mopius Page 14/48
-
8/6/2019 Symbian OS Workshop
15/48
Symbian OS Workshop
Why will be explained soon. Press enter and C++BuilderX should take you to the
function again; this time it has the corrected name.
Fig. 12 The code for displaying the about box.
Now, write the code seen in line 175 of the screenshot above in
MopoidContainer.cpp. This is a call the function that C++BuilderX has already
created for us, directly above.
2005 Mopius Page 15/48
When you try the program now, the about box will already work fine. But lets take a
closer look at why we added the L at the end of the function name.
You will note that the function (ExecuteiAknAboutNoteL())
also has an L at the end of its name. Why is this? The reason is
that memory is allocated in this function (for creating and
displaying the dialogue box also note the ELeave in its c
line), and that this process can fail. Currently, mobile phones have very limited
resources. Therefore, it is very important to take care of what happens when the
operating system is unable to provide the resources that your application needs.
reation
Fig. 13 The about box in the Series 60 emulator (SDK v1.2).
-
8/6/2019 Symbian OS Workshop
16/48
Symbian OS Workshop
2005 Mopius Page 16/48
These events, as well as other errors (like file not found), are handled by a system which
is similar to try/catch of Java and modern C++. An error is passed up in the call
hierarchy, until someone takes care of it. To make the possibility of a leave visible to
the developer, it is a standard convention in Symbian OS to append an L at the end
of the function name.
The function that displays our about message leaves if not enough memory is available.
Normally, you dont (and shouldnt) take care of this problem and let the system display
the appropriate error message. Handling every error yourself would make your code
huge.
If there is an error, the event will automatically be passed up to the next function in the
call stack. This means that the OniMenuItemAboutViewCommandL() function can
also leave. Therefore, we added the L to the end of its name.
So far, so good. However, C++BuilderX also created a command dispatching function
called DispatchViewCommandEvents() with the note NOTE: This routine is
managed by the C++BuilderX IDE - DO NOT MODIFY.
Note that the L is missing at the end of it. If we added it manually, C++BuilderX
would no longer recognize this function. If we go another step up in the call stack,youll get to the HandleCommandL() (L!) function of the MopoidView.cpp file.
Thats the function the operating system calls when the user selects your About
menu item!
So, because of the inflexibilities of the IDE, we already have a tiny bit of code that does
not conform to the Symbian OS coding conventions. In this case, we will just ignore it,
as the L is not for the system, but just a helpful thing for us developers. But it was a
good excuse to explain the basics of the leave system to you, and to show you thelimitations of C++Builders automatically generated code.
If something doesnt work...
... and you would like to find out why, the file Mopoid.Step7.zip is a working
project of what you have done up to now. From now on, a zip file of the reference
project will be available after each step!
-
8/6/2019 Symbian OS Workshop
17/48
Symbian OS Workshop
Step 7 - Getting the application to the mobile phone!
Normally the emulator works really well. But you might still get into situations where
the code works fine in the windows emulator, but simply crashes on the phone. The
most prominent examples are static member variables, which work fine in the emulator,
but do not work on the mobile phone!
As debugging directly on the mobile is difficult and doesnt always work, it will be
difficult finding the reason for the crash when your phone just reports System error.
However, if you regularly try your application on your phone, it will be easier to locate
the problem.
To tell the IDE that you want to build for the device, you have to switch the target
platform of the compilation process to ARMI (the processor on your Series 60 phone
is an ARM processor) and the type to UREL (Release version). To build your project,
choose Project Make Project Mopoid.cbx (Ctrl+F9).
Fig. 15 Compiling forrelease instead of debug.
Fig. 14 Changing the buildtarget of the application.
After this process has finished, a file called Mopoid_ARMI_UREL.sis will reside in
the directory C:\Symbian\dev\Mopoid\group. Transfer this file to your phone and
install it.
You can either do this using the PC Suite that came with the phone, or just send it to
the device through Bluetooth or IrDA link (if available) by right-clicking on the file,
Send to... Bluetooth device. For more instructions on how to install a file, read
the manual that came with your phone.
If everything works fine, dont forget to switch back to the WINS / UDEB build
configuration when you continue development!
2005 Mopius Page 17/48
-
8/6/2019 Symbian OS Workshop
18/48
-
8/6/2019 Symbian OS Workshop
19/48
Symbian OS Workshop
Fig. 16 Adding additional source files.
Select and add all files from the ./src/ directory which are not already part of your
project:
Fig. 17 The files to add.
Adding additional libraries to the project definition file
Your final game will do a lot of things load and play sounds, display PNG graphics
and access files. These functions require some libraries provided by the SDK. The only
thing you have to do is to add them to the project. Double-click on Mopoid.mmp in
your project definition window. This is the Symbian OS project definition file that
contains references to all source files and libraries that are needed for your project (and
some other stuff).
Scroll to the bottom of the file and add the following lines below all other library
definitions:
LIBRARY efsrv.lib // For loading data files
LIBRARY bitgdi.lib // For drawing
LIBRARY mediaclientimage.lib // For loading png files
2005 Mopius Page 19/48
-
8/6/2019 Symbian OS Workshop
20/48
Symbian OS Workshop
2005 Mopius Page 20/48
LIBRARY mediaclientaudio.lib // For loading and playing audio
LIBRARY estor.lib // For writing to & reading from files
Defining new text
A real game needs a lot of text. Define the following strings in the string table, as
described in Step 4. Add a space after the text items with a : at the end, as the
number will be appended to the text!
Name Text
r_score Score:
r_level Level:
r_pause Game Paused
r_gameover Game Over
r_finished You made it!
r_lifelost Life Lost!
r_lives Lives:
r_pressjoystick Press Joystick
r_highscore High Score:
r_enterlevel Entering Level:
r_title mopoid
New game
The start new game command has to be connected with the start game function of the
game engine. Create a new event function for the Start New Game menu item like
you did for the about box. This time, dont change the function name to contain the
L suffix the start game function doesnt leave. Insert the following text into the
new OniMenuItemNewGameViewCommand() function:
iGameEngine->StartNewGame();
Adding graphic and sound files
Several .png and .wav files have been prepared so that the game has a nice look and
-
8/6/2019 Symbian OS Workshop
21/48
Symbian OS Workshop
feel. You have to add them to the project, so that they will be copied to the mobile
phone! To do that, switch the build configuration to ARMI UREL using the blue
gearwheels. You should now see an entry called Package File in the project pane.
When adding the files, you have to take care, as C++BuilderX has a small bug...
Fig. 18 Adding additional files to the package.
Right-click on Package File and choose Add File to Package.... You will get to a
dialogue window. Choose the first file of the /data/ directory of our Mopoid
project (ball.png). Do notclick on OK yet, or you will have to remove the file from
the package and start again.
Fig. 19 Add the filename to the target path!
Add the file name (\ball.png) to the target path in the second text box! When
youre done, click on OK.
The target path defines the location and name of the file on the device. If the file name
isnt specified, the phone will not be able to copy the file! It would be great if the IDE
added the file name itself.
The ! at the beginning of the line means that the user can choose where he wants to
install the application; more on that later.
The bug in C++BuilderX 1.5 is: after you have added a file, you cant modify the target
path any more. The IDE does let you change it, but when you click on OK, it will
2005 Mopius Page 21/48
-
8/6/2019 Symbian OS Workshop
22/48
Symbian OS Workshop
discard your changes without notifying you. Therefore, do not forget to add the file
name right when adding the file!
Do this for all .png and .wav files, and the levels.dat file. When youre finished, your
project pane should look like this:
Fig. 20 All files are now part of the project.
Testing
Switch back to WINS / UDEB. When you run your game now, it should still work.
However, the screen will just be black with only one line of text on it. In the next few
steps we will add all the parts that are missing!
Troubleshooting
This chapter was rather risky, combining your project with the prepared source files
only works if you really did everything exactly as described in the earlier steps. If you
have any problems and the project doesnt work any more, use the reference project
from Mopoid.Step8.zip!
Step 9 - Loading imagesSymbian OS C++ has built-in support for .mbm files. These are collections of RLE-
compressed bitmap files. Advantages are: they are fast to load and easy to handle,
however they take a lot of space on the mobile device. A game uses a lot of graphics,
with this system it would get huge.
Therefore, its better to use .png or .jpg files. Unfortunately, no predefined loading
routines are available, and its rather complicated to do it manually. Also,
decompressing those files takes some time, therefore it works asynchronously, in its
2005 Mopius Page 22/48
-
8/6/2019 Symbian OS Workshop
23/48
Symbian OS Workshop
own thread. In Symbian OS v7.0s, an alternative way to load images is possible, but if
you want your game to reach the broadest possible audience, you will have to stick to
the old functions (for now).
Developing and explaining the whole process of loading an image would be a tutorial
of its own, therefore a finished class has been provided PngLoader.cpp. A second
file, provided by Nokia (bitmapmethods.cpp) helps with some common tasks.
Some more functions have been added to make it even more useful. You can simply
add those two files to your own future projects!
In the Mopoid project, a class is responsible for loading and storing all those images. If
an image is needed somewhere else, it can get the image by sending the ID of the
requested image to a function of the CSpriteHandler class.
C and T classes
What about the C at the beginning of the class name? In short,
this means that this class will always be constructed on the heap,
and it will most of the time own other (heap) objects. When the
destructor of our C class is called, those objects have to be destroyed.
The second most important type is T classes. It is basically like a simple data type, a
class of this type cant have a destructor. For example the basic data types in Symbian
have a T prefix (TInt, TReal, ...)
ConstructL
Open the SpriteHandler.cpp file to see the source code of our bitmap manager
class. You will note that the constructor is empty, and you write your code in a function
called ConstructL(), which is called byNewL().
The reason for this lies in the memory situation of mobile phones. If you develop a
typical application for the PC, you will (in most cases) not have to worry about free
memory. Here, the situation is different. It can happen that the available memory runs
out, and that creating an instance of a class fails.
However, when you allocate memory in the constructor and this process fails, the
allocated memory will be orphaned. Thats bad. Therefore, code executed in a C++
2005 Mopius Page 23/48
-
8/6/2019 Symbian OS Workshop
24/48
Symbian OS Workshop
2005 Mopius Page 24/48
constructor should never leave! However, the sprite handler should provide the
graphics right after the class is created.
The solution is simple a two phase construction. Just move (at least) all memoryallocating code to the ConstructL() class method. You can then create the object as
usual, and then in the next line call this function. This gives you the opportunity to
handle leaves correctly.
Especially if you need to create an instance of your class more than once, youd have to
write the code for these steps (allocation and callingConstructL()) multiple times. To
prevent this, the two phased construction is usually handled by a static NewL() or
NewLC() function. As a general rule, NewL() has to be called when the object you want
to create is assigned to a member variable. NewLC() will leave the object on the cleanup
stack, useful for automatic variables. This will be discussed later on. For now, lets
move on to implementing the bitmap loading!
Loading bitmaps
First, we have to define the filename of the graphic file we want to load. This is done
by:
_LIT(KBmpPanel, "panel.png");
This line creates a named object (KBmpPanel) that stores the string panel.png
directly into the application binary. Strings are handled differently in Symbian OS C++
compared to standard C++. Again the reason for this is the limited amount of memory
in mobile devices. In Symbian OS C++, strings are called descriptors, and they are
quite difficult to get used to. On the positive side, they use less memory than their C++
string counterparts.
Once we have loaded a bitmap, we need to store it somewhere. To view it, you have to
take a look at the header file of the sprite handler class. For whatever reason,
C++BuilderX doesnt display those files in the project structure. Instead, you have to
open the source file, open its includes section in the file structure panel on the left, and
go to the include file from there:
-
8/6/2019 Symbian OS Workshop
25/48
Symbian OS Workshop
Fig. 21 How to get to the include file.
In the class declaration, you will find the following declaration of a private member
variable:
TFixedArray iSprites;
Why is the variable called iSprites instead ofsprites or m_sprites? This is
another Symbian OS C++ coding guideline. All member (instance) variables should
have i as their prefix. While we are at it, parameter variables should have a at their
beginning.
What about the type of the variable? This is basically a normal, fixed length C++ array
with additional range checking and some other useful functions (for navigating through
the array, getting its length, deleting each element and so on).
Go back to the Spritehandler.cpp file. Lets fill our array with bitmaps. We do this
by calling a static method of our CPngLoader class that will do all of the work.
iSprites[ESpritePanel] = CPngLoader::LoadImageL(KBmpPanel,
EColor4K);
Note that we tell the class to load the image as EColor4K. This means that the graphic
will have 4096 colours, and this equals the colour depth of earlier Series 60 devices like
the Nokia N-Gage or the Nokia 7650. Newer phones already support EColor64K (or
higher). However, for the graphics of a simple Mopoid game, we dont need so manycolours anyway. ESpritePanel is the textual representation of an ID, called
enumeration, and is defined in MopoidSharedData.h.
Fig. 22 Theanel graphic
Fig. 23 Themask of the panel.
We want our panel to have round corners, so we will also need a mask. The easiest
2005 Mopius Page 25/48
-
8/6/2019 Symbian OS Workshop
26/48
Symbian OS Workshop
method to get this would be to have a second graphic file which contains the black and
white mask image. However, as said before, loading .png files takes quite some time, so
its better to generate the mask ourselves. Use the following method, which is also part
of the source code provided with this tutorial:
iSprites[ESpritePanelM] =
NBitmapMethods::CreateMaskL(iSprites[ESpritePanel], EFalse, 0);
This function will create a mask bitmap based on the colour of the top left pixel of the
source image. If you dont want all pixels that have the colour of the top left pixel to be
transparent, you can use the second and third parameter to specify a colour which
should be masked as transparent.
Now, load the ball image in the same way as the panel image. The file name is
ball.png, the enumeration names for the ids are ESpriteBall and
ESpriteBallM.
The bricks are a bit different. They have a rectangular shape and dont require a mask.
However, we have got several different colours for the bricks. Instead of loading the
images one by one, its better to combine all of the graphics into one file and then split
them up after loading this image. With this method, the image files will require less diskspace (overall), and even though the application will temporarily need more memory,
its a lot faster.
Fig. 24 3 brick graphics in 1 file.
Load the brick image using the following code:
_LIT(KBmpBrick, "bricks.png");
CPngLoader::LoadAndSplitImageL(KBmpBrick,
&iSprites[ESpriteBrickNormal], 3, EColor4K);
This code loads the image file, splits it up into three images and stores them in the
iSprites array, beginning at the ESpriteBrickNormalposition.
Deleting images
When you try to execute your application, it should already load the images, even
though you wont see them. We have not written the code to display them yet. Now try
2005 Mopius Page 26/48
-
8/6/2019 Symbian OS Workshop
27/48
Symbian OS Workshop
to quit the application. You will see a warning like this:
Fig. 25 Error message telling you about a memory leak.
This error message informs you about a memory leak somewhere in your application.
Its quite difficult to find the offending code later on; because of that, remember to quit
your application in the emulator instead of just closing the emulator window.
In our case, we dont free the memory allocated for the graphic files when the
CSpriteHandler object is destroyed. Fortunately, thanks to the TFixedArray class of
iSprites, this is easy to do. Writing the following code into the destructor of the class
will do all the work:
iSprites.DeleteAll();
Step 10 - Displaying the graphics
Just loading graphic files wont help you much you will also have to get them onto the
screen. In our application, the game engine class takes care of preparing the back buffer
image. This means that all graphics are drawn to an extra bitmap of the size of the
screen. When this process is finished, the whole bitmap is copied to the screen. This
prevents flickering, which would occur otherwise.
First, go to the ConstructL() method of the CGameEngine class. Uncomment the big
code block that does some size calculations with the graphics files that we have just
loaded. If you are interested, you can also take a look at the code, but it isnt important
for us now.
The frame itself is drawn in the DrawFrame()method, which is further down in the
source code of the same class. Note that the function is defined as const, this means
that its not allowed to modify the member data of the game engine class.
2005 Mopius Page 27/48
-
8/6/2019 Symbian OS Workshop
28/48
Symbian OS Workshop
2005 Mopius Page 28/48
Handling transparency
Lets take a look at the following line:
iBackBufferBmpGc->SetBrushStyle( CGraphicsContext::ENullBrush );
When drawing to a bitmap, Symbian OS provides both a pen and a brush through
the graphic context of an image, which handles drawing operations. An example: when
you draw a rectangle, the outline will be drawn using the settings you assigned to the
pen, and it will be filled by your brush.
We dont use those drawing functions, but we have to take care of this behaviour as
well! If we define a solid brush and want to draw a bitmap that has transparent parts,
those parts will be filled with your current brush colour and its other properties! Thats
why we set the brush to a null brush, letting the background of a bitmap shine through
its transparent parts.
Drawing a bitmap
First, well draw the ball. The first line is already here, it calculates the position of the
ball and puts it into a TPoint variable. This automatically provides an x and y
coordinate and is very useful.
Write this line directly after it:
iBackBufferBmpGc->BitBltMasked(ballSpritePos, iSpriteHandler->
GetSprite(MopoidShared::ESpriteBall), iBall.iSize,iSpriteHandler->
GetSprite(MopoidShared::ESpriteBallM), EFalse);
It calls the BitBltMasked() function of the back buffer bitmaps graphic context,
which basically copies a masked source bitmap to a target bitmap. The first parameter is
the position, the second the source image, the third the size of the image we want to
copy, the fourth the mask to use, and the fifth whether to invert the mask or not.
To look up the parameters of the functions provided by Symbian OS APIs, take a look
at the Symbian OS help. Search for the SDK Help in your start menu under
Symbian 6.1 SDKs -> Series 60 -> Documentation.
Now, scroll down a bit and do the same for the panel. For its position, use the value
stored in iPanel.iPos. The Enumeration IDs for the sprites are ESpritePanel
and ESpritePanelM. The size is: iPanel.iSize.
-
8/6/2019 Symbian OS Workshop
29/48
Symbian OS Workshop
As we have found out before, the bricks dont need transparency. Generally you should
take care not to draw large transparent areas, as this slows performance.
The function to draw a bitmap without a mask (BitBlt()) is similar, and even a bit
easier to use. You only have two parameters, the position and the source bitmap. Put
the following line of code at the marked position inside the for loop, which loops
through the bricks grid to draw all visible bricks.
Fig. 26 Our Mopoid game can now display graphics!
iBackBufferBmpGc->BitBlt(iGrid.ConvertGridToXY(x,y), iSpriteHandler-
>GetSprite(spriteId));
When you run your application now, it should already look quite decent:
However, there is no interactivity yet. To enable this, we have to handle key presses!
Step 11 - Handling keys
Its quite easy to handle key presses in Symbian OS. The framework will automatically
call the OfferKeyEventL() method of your container class (CMopoidContainer).
The code, which was created by the C++BuilderX IDE, forwards this call to the
HandleKeyEvents() function (this wouldnt be necessary in our case, as nothing elsehas to handle key presses in our application).
The HandleKeyEvents() function gets two parameters const TKeyEvent&
aKeyEvent and TEventCode aType. The first one (aKeyEvent) contains information
about the button that was pressed. The second parameter (aType) tells you what kind
of event happened.
In our Mopoid game, we want the panel to continuously move as long as the user
presses the direction key (in our case, he has to use the joystick). To get this behaviour,
2005 Mopius Page 29/48
-
8/6/2019 Symbian OS Workshop
30/48
Symbian OS Workshop
2005 Mopius Page 30/48
we have to set a flag when the key is pressed, and unset it when the user releases the
key again.
A special class that has been prepared (TKeyHandler) stores the direction that is
currently pressed by the user. Its owned by our game engine class, which has to take
care of sending movement events to the panel.
The task we have to do now is rather simple; therefore well only write the code for the
key down event. The prewritten source code already contains the rest. Search for the
part of the if statement that takes care of key down events (EEventKeyDown).
Inside, you will find a switch statement that takes care of the individual keys,
differentiated by their scan codes.
Here well handle two additional cases: EStdKeyLeftArrow that will be called when
the player moves the joystick to the left and EStdKeyRightArrow for the other side.
To send the event to the key handler we mentioned previously, you have to call:
iGameEngine->iKeyHandler.LeftPressed();
Of course this is slightly different for the right side. When you take a look at the
HandleKeyEvents() function, youll notice that it has a boolean return value. This will
tell the system if the key press has been handled. If it hasnt, it will be sent to the next
application that might be running in the background (Symbian OS is a multitasking
operating system!).
Because of that, we have to tell the system that we took care of this key press and that it
doesnt have to send it to anyone else. Set the flag thats defined at the beginning of the
function accordingly:
handled = ETrue;
Note that Symbian OS C++ uses its own definition of boolean values. The data type is
TBool and can have the values ETrue and EFalse.
Dont forget to add a break statement after each case handled in the switch statement!
After you have written the code, test it in the emulator. You should be able to move the
panel, the ball bounces and you can already play the game! The code of this step is just
standard C code, but if you have problems take a look at the MopoidContainer.cpp
file ofMopoid.Step11.zip.
-
8/6/2019 Symbian OS Workshop
31/48
Symbian OS Workshop
Step 12 - Displaying text
The game is still lacking an important part it doesnt display any status information
informing the player about his points, lives or level. Well add this now. Go to the
DrawFrame()method of the CGameEngine class.
Setting a font
Luckily, predefined functions take care of displaying the text, and are even able to align
it. But first, we have to tell the graphics context of the bitmap which font and colour to
use. Write the following code below the // Hud comment.
iBackBufferBmpGc->SetPenStyle(CGraphicsContext::ESolidPen);
iBackBufferBmpGc->SetPenColor(KRgbRed);
iBackBufferBmpGc->UseFont(CEikonEnv::Static()->AnnotationFont());
TBuf tempStr;
Lets analyze it step by step. The first line will already sound familiar, it defines the pen
style. In an earlier section, we explained that this is used for outlines of boxes. Its also
used for the font outline, which isthe font. In our case, we set the pen style to solid, so
that we actually see the text that we draw.
The next line defines the color. We use one of the default values, a plain red. If youd
like to define your own RGB color, use this:
iBackBufferBmpGc->SetPenColor(TRgb(255, 128, 0));
The next line chooses one of the standard system fonts. Symbian OS provides more
complex font mechanisms, as well as the option to create and use your own fonts. For
a simple Mopoid game, well stick to the easiest method and use the AnnotationFont.
Its a medium sized, bold font.
The forth and last line creates a descriptor, which is the Symbian
OS equivalent of a string. It has a maximum length of 30 chars. A
TBuf is derived from a class called TDes, which provides several
functions to manipulate the string data. Well use those to set the
contents of the text. Note that the TBuf is created on the stack, which is very limited
on mobile devices. Therefore, dont use it for strings that are longer than 256 chars. For
everything else, a heap based descriptor (HBufC
) should be used.
2005 Mopius Page 31/48
-
8/6/2019 Symbian OS Workshop
32/48
Symbian OS Workshop
2005 Mopius Page 32/48
Reading text from the resource file
Next, well read one of the strings that we have defined in the resource file (through the
string table of the C++BuilderX IDE). A static function of theCEikonEnv
class takescare of this and writes the string directly into the descriptor (which we have defined
before). The string resource got the name RS_R_SCORE. Normally it should only be
R_SCORE, however, C++BuilderX adds an additional RS_ in front of the name.
CEikonEnv::Static()->ReadResource(tempStr, RS_R_SCORE);
Formatting and displaying the text
The string weve read from the string table only contains a static text: Score: . We
have to add the current score of the player at the end of the string. The AppendNum()
function provided by the descriptor handles this.
tempStr.AppendNum(iSettings.iScore);
Now, the text is ready to be displayed on the screen. We can print it at a specific x/y
position using the following code:
iBackBufferBmpGc->DrawText(tempStr, TPoint(5, 25));
Please note: the y coordinate of 25 specifies the lower border of the text, so 5/25 is
the lower left point of the text, not the upper left as you may have expected!
We also want to display the high score. Write the code for this yourself. Read the text
resource RS_R_HIGHSCORE into the same temporary descriptor. This will overwrite
the content currently stored, which we dont need any more (it has already been printed
to the screen). Append the number that you can get through
iSettings.iHighScore and print the text at 5/38 (one line below the current
score).
Aligning text
Now the game will display the current score and the high score on the left side of the
screen.
We also want to display some information on the right side of it:
-
8/6/2019 Symbian OS Workshop
33/48
Symbian OS Workshop
Level Text: RS_R_LEVEL
Value: iSettings.iLevel
Position: y: 28, x offset from the right side of the screen: 3
Lives Text: RS_R_LIVES
Value: iSettings.iLives
Position: y: 38, x offset: 3
Read and format the strings as before, only the printing is different. Luckily, Symbian
OS provides a function that aligns text:
iBackBufferBmpGc->DrawText(tempStr, TRect(0, 0, SCREEN_WIDTH,
SCREEN_HEIGHT), 25, CGraphicsContext::ERight, 3);
The TRect(...) defines a rectangle which is used to align the text. In our case, its the
whole screen. To optimize the program, you could define the Screen TRect only once
at the beginning of the function, and use the variable in all calls that need it.
SCREEN_WIDTH and SCREEN_HEIGHT are defines made by us. Series 60 is a
standardization of the user interface; therefore the screen size of all Series 60 phones is
the same (176x208). In the future, this will get more flexible and bigger screen sizes will
be introduced to Series 60. The third parameter specifies the y position, the fourth the
alignment and the last one the x offset.
The status messages work in a similar way. To activate them, uncomment the code
block below. If you take a quick look at it, youll see that it uses the TitleFont(),
which is bigger than the AnnotationFont. It also centers the status message.
When you start the game now, it should look like this:
Fig. 27 The Mopoid game with text.
Great, isnt it? To make the game really cool, there are still several things left to add...
2005 Mopius Page 33/48
-
8/6/2019 Symbian OS Workshop
34/48
Symbian OS Workshop
2005 Mopius Page 34/48
Step 13 - Reading and writing files
This section will be very important for your future projects. In our Mopoid game, we
will just save the high score to demonstrate how reading and writing files works.
Preparation
Open MopoidGameEngine.cpp and go to the MopoidGameEngine.h file. Before
the class declaration starts, you will see that we have already defined the file version
number and the file name:
#define MOPOID_FILE_VERSION_NUMBER 1
_LIT(KMopoidDataFile, "settings.dat");
Symbian OS C++ already provides some APIs to access files. First, the corresponding
header file has to be included. Add the following line at the top of the other system
include lines:
#include
This includes all the functionality we need. We have already added the required libraries
(estor.lib, efsrv.lib) to our project definition (.mmp) in an earlier step.
Setting the file name
In our header file, we just stored the filename of our data file the path has to be
added dynamically by the application. This can be done by adding the application path,
as we want our data file to be in the same directory where the user installed the game.
Go back to the MopoidGameEngine.cpp file and scroll down until you reach
SaveGameProgressL() . This code should be executed first in this function:
TFileName fullName(KMopoidDataFile);
CompleteWithAppPath(fullName);
#ifdef __WINS__
fullName[0] = 'C';
#endif
As you can see, we have to take care when our game is running in the windows
emulator. The environment will return that the application is installed on drive Z,
which is the ROM drive (where the system itself is installed on the phone). Apparently,
its compiled onto this (virtual) drive. Its not writeable, therefore we have to adapt the
-
8/6/2019 Symbian OS Workshop
35/48
Symbian OS Workshop
2005 Mopius Page 35/48
drive to the standard C drive. On the device, you will get the real path and drive where
the application was installed.
Opening the file
There are multiple ways to write to a file. Here, we will use the most flexible one, which
is based on streams that are put into a store (i.e. the file). This also allows serializing
objects directly into the file and is very helpful if you need to save the game status of a
more complex game.
We use a direct file store, which doesnt allow modifying the data. That doesnt matter
for us, as we will replace all of its contents anyway. This code will open the file store:
CFileStore* store = CDirectFileStore::ReplaceLC(
CEikonEnv::Static()->FsSession(), fullName,
EFileWrite);
store->SetTypeL(KDirectFileStoreLayoutUid);
Note that we use the file server session from the CEikonEnv environment. A file server
takes care of the real writing and reading to and from files. The file server exists only
once for the whole system and you cant create your own instance it would just be
possible to connect to it. However, this is an expensive operation, so we will reuse the
file server session that the system uses to read our resource file.
Creating the stream
A store can contain multiple streams; one of them has to be the root stream. For saving
the high score, only one stream is needed. Multiple streams could be useful for saving
the data of individual players. The stream is created and returns its ID, which will be
used later on when we set this stream as the root of the store.
RStoreWriteStream stream;
TStreamId id = stream.CreateLC(*store);
Writing the data
Finally, we get to the point where the data is written to the file. We will write two
integer values to the stream. In Symbian OS, a TInt is defined as a 32-bit variable,
therefore well use theWriteInt32L()
function of the stream to write the data.
-
8/6/2019 Symbian OS Workshop
36/48
Symbian OS Workshop
2005 Mopius Page 36/48
// Write file version number
stream.WriteInt32L(MOPOID_FILE_VERSION_NUMBER);
// Write game progress
stream.WriteInt32L(iSettings.iHighScore);
It is not mandatory to write the file version to the stream. However, it has proven to be
veryuseful. Lets assume the following situation your customer has installed your
Mopoid game on his mobile phone. Later on, you release a new version, which also
saves the player name. Your customer downloads it and replaces the game on his
device. The old data file will not be deleted!
Then he starts up your new game version, which finds the (old!) data file and attempts
to load it, expecting to get the score and the player name. However, as the data file is
still from the old game, it doesnt include the player name. Its a lot easier to compare a
version number and handle the case correctly; for example you could also do an import
function...
Closing the file
Youre nearly finished. Just make sure that the data is written and close the file:
// Commit the changes to the stream
stream.CommitL();
CleanupStack::PopAndDestroy(); // stream
// Set the stream in the store and commit the store
store->SetRootL(id);
store->CommitL();
CleanupStack::PopAndDestroy(); // store
The Cleanup Stack
In the function that we have just written, the Symbian OS cleanup
stack is used. This is a very important part of developing in C++
for Symbian OS. The full scope of it is difficult to understand, but
is already covered by lots of literature. Therefore, heres only a short summary:
Imagine this situation. In a method, you create an object on the heap, your variable is a
pointer to it. Should some function call leave before the method is over, your method
will be left immediately. The framework will clean up all the automatic variables.
-
8/6/2019 Symbian OS Workshop
37/48
Symbian OS Workshop
2005 Mopius Page 37/48
However, in this case you just have the pointer to an object, which will be destroyed,
but leave the object itself unreferenced in memory. Thats bad.
Therefore, objects that are used through automatic variables have to be pushed onto
the cleanup stack. If a leave happens, the framework will automatically clean up all
objects that are in the cleanup stack.
Normally, youll use the cleanup stack like this:
MyObject x* = new (ELeave) MyObject();
CleanupStack::PushL(x);
x->DoSomethingDangerousL();
CleanupStack::PopAndDestroy();
In the file example, we called two functions that had a C at the end of their name.
This indicates that they leave an object on the cleanup stack, which you have to clean
up when you no longer need the object. Therefore, two PopAndDestroy()s are used.
Please note that even though the framework will clean up the cleanup stack when a
leave occurs, you have to take care of correct cleanup during an error-free program
execution yourself.
Loading
Saving a file is only half of the story. Fortunately, loading works in a similar way. First,
complete the file name as seen before. Next, the store has to be opened again, this time
for reading.
CFileStore* store = CDirectFileStore::OpenLC(CEikonEnv::Static()-
>FsSession(), fullName, EFileRead);
After opening the root stream...
RStoreReadStream stream;
stream.OpenLC(*store, store->Root());
... we can read the data:
TInt versionNumber = stream.ReadInt32L();
if (versionNumber != MOPOID_FILE_VERSION_NUMBER)
User::Leave(KErrNotFound);
iSettings.iHighScore = stream.ReadInt32L();
-
8/6/2019 Symbian OS Workshop
38/48
Symbian OS Workshop
You could improve the handling of a wrong version number, but for the first version
of the game its sufficient. Here we just leave with a not found error, meaning that we
were unable to find the correct setting information in the file. The call to this function
(in the ConstructL() of the game engine) traps the exceptions of the load function
and ignores a not found error, which also occurs if no file has been created yet. In the
case of a file not found error, the game simply sets the high score to the default value
of 0.
Dont forget about cleaning up after loading all your data!
CleanupStack::PopAndDestroy(2);
Cleanup when your application is uninstalled
Should the user ever decide to remove the game, all files have to be deleted from the
mobile device (this is also one of the requirements to get your application Symbian
Signed). The uninstallation is done by a program manger, and your own application
wont be called when its being uninstalled. Therefore, you have to specify which files
will need to be removed right where we define how your application has to be installed.
Fig. 28 The uninstall application has to remove the new data file as well.
Unfortunately, C++BuilderX is quite limited when it comes to defining your
installation file for your mobile phone, and it makes the task more complicated than it
would be without C++BuilderX.
Switch to build for the target device (ARMI / UREL) first using the blue gearwheels as
we already did in an earlier step. Right-click on the Package File in the project pane
and choose Export PKG File. This will create a very minimal Mopoid.pkg file in
the ./dev/Mopoid/group/ folder.
2005 Mopius Page 38/48
-
8/6/2019 Symbian OS Workshop
39/48
Symbian OS Workshop
Fig. 29 Exporting the package file.
Now, open the file with a text editor. It should look similar to this:
&EN
#{"Mopoid"},(0x01000001),0,1,0
(0x101F6F88), 0, 0, 0, {"Series60ProductID"}
"C:\Symbian\6.1\Series60\epoc32\release\ARMI\UREL\Mopoid.app"-
"!:\system\apps\Mopoid\Mopoid.app"
"C:\Symbian\6.1\Series60\epoc32\release\ARMI\UREL\Mopoid.r01"-
"!:\system\apps\Mopoid\Mopoid.r01"
"C:\Symbian\dev\Mopoid\data\ball.png"-"!:\system\apps\Mopoid\ball.png"
"C:\Symbian\dev\Mopoid\data\bounce.wav"-"!:\system\apps\Mopoid\bounce.wav"
"C:\Symbian\dev\Mopoid\data\bricks.png"-"!:\system\apps\Mopoid\bricks.png"
"C:\Symbian\dev\Mopoid\data\hit.wav"-"!:\system\apps\Mopoid\hit.wav"
"C:\Symbian\dev\Mopoid\data\levels.dat"-"!:\system\apps\Mopoid\levels.dat"
"C:\Symbian\dev\Mopoid\data\panel.png"-"!:\system\apps\Mopoid\panel.png"
It defines that the installation file only contains one language, English. The second line
contains the name of the application that will be displayed during the installation, its
UID that we set when we created the project, and the version number.
The third line defines that your application can be installed on all Series60 devices, even
on the old Nokia 7650 (which used v0.9 of the Series 60 SDK). If you develop an
application that isnt backward-compatible, you have to use a different Series 60
Product ID.
Then, the package file defines that both your application and the resource file (which
contains strings and menu definitions) are copied to the device into the
\system\apps\Mopoid\ folder. The ! at the beginning means that the user can
choose on which drive to install the application. The internal, writeable memory of
Series 60 devices is drive C, the optional MultiMediaCard has the drive letter E.
OK, our application will create a new file when its running. It doesnt have to be
2005 Mopius Page 39/48
-
8/6/2019 Symbian OS Workshop
40/48
Symbian OS Workshop
2005 Mopius Page 40/48
installed, but has to be removed when the game is uninstalled. How does it do that?
The following line does what we need:
""-"!:\system\apps\Mopoid\settings.dat",FN
FN means FileNull. The SDK help has a nice definition of what this line means:
A file which does not yet exist, so is not included in the sis file. It is created by the
running application and will be deleted when the application is removed. The name
assigned to the source file is unimportant and should be empty, i.e. . Note that such
files will not be deleted when upgrading to a later version. This ensures that such files as
.ini files, which store application preferences, are not lost in an upgrade.
Building from the command line
Unfortunately, C++BuilderX doesnt care about the package file it has exported.
Therefore, from now on you have to make the installation file (.sis) from the command
line. First, make sure that your IDE is still set to compile for ARMI / UREL (blue
gearwheels). Compile the project using Project -> Make Project Mopoid.cbx.
Now, open a command window (Start -> Execute -> type in cmd) and switch to
the C:\Symbian\dev\Mopoid\group folder. To make this faster, maybe you shouldinstall the Command Window Here PowerToy from Microsoft. Enter the following
command:
makesis Mopoid.pkg
This will assemble the .sis file using the information from your own package file, and a
Mopoid.sis file should now be available in the same directory. Try it on your mobile
phone! It makes sense to write a small batch file that contains the command above, so
that you dont have to type it in every time you want to build for the device.
When youre finished, dont forget to switch back to compile for the windows debug
emulator again (WINS / UDEB)!
Step 14 - Setting the application icon
Some information, like the application icon and caption, are stored in an .AIF file
(Application Information File). In this step, we will create this for our project.
-
8/6/2019 Symbian OS Workshop
41/48
Symbian OS Workshop
Go to File -> New... . Choose the category Mobile C++, select the New
Symbian AIF Wizard and click on OK. Accept the default values of the page showing
Step 1. Step two is more interesting, now you will add the icons that will appear in the
menu of your mobile phone.
Fig. 30 Adding icon files to the game.
Add the bitmaps from the aif directory of the project in the order shown above
always the icon bitmap file first, then its mask. Dont forget to click the Add button
after selecting a file!
When youre done with adding all four files, go to step three. Now you will add the title
of the game. As Mopoid only supports English, simply enter the caption Mopoid and
leave the language at ELangEnglish. Click on Add.
Fig. 31 The English caption is now defined.
2005 Mopius Page 41/48
-
8/6/2019 Symbian OS Workshop
42/48
Symbian OS Workshop
Fig. 32 Opening the resource file to fix a C++BuilderX bug.
After clicking on Finish, everything should normally be finished. However, there is
some kind of strange bug in the current version of C++BuilderX, because you wont
see any icons if you compile the game now. To fix this, double click on Mopoid.rss
(found in the Aif folder) in the project pane to open it.
Find the line containingnum_icons and change its value from 4 to:
num_icons = 2;
We only added two icons in different sizes, and their respective masks. C++BuilderX
should actually know those requirements, but apparently it doesnt.
Step 15 - Handling being in the background
Symbian OS is a multitasking operating system. While your application is running,
many other events could send your application to the background or draw an alert on
top of it. Examples: an incoming call or message, a low battery warning, the user
sending your application to the background by pressing the red button, etc.
Fig. 33 The game should be paused automaticallywhen it gets sent to the background.
2005 Mopius Page 42/48
-
8/6/2019 Symbian OS Workshop
43/48
Symbian OS Workshop
2005 Mopius Page 43/48
Even for a small game like Mopoid its very important to handle this event. The game
has to be paused so that it doesnt continue while the user is unable to play. Also, it
should use as few system resources as possible by stopping the continuous screen
updating process. Its also a good idea to save the game progress.
Symbian OS will send an event to your application when it gets sent to the background.
The function HandleForegroundEventL() of the active view is called.
C++BuilderX didnt implement it when it created the code, so were going to do it now.
Open MopoidView.cpp and go to its header file. Note that the CMopoidView class is
derived from CAknView, which already defines HandleForegroundEventL() . As we
will implement the function, add the following definition at the end of the public
function definitions:
void HandleForegroundEventL(TBool aForeground);
The parameter aForeground specifies whether our application was sent to the
background, or if it gained the focus again. Switch back to MopoidView.cpp and add
the following function at the bottom of the file:
// Handle any change of focus
void CMopoidView::HandleForegroundEventL(TBool aForeground)
{
if (aForeground) // gained focus
{
// Don't resume the game - wait for user to resume it
iContainer->iGameEngine->iHaveFocus = ETrue;
}
else // lost focus
{
// Pause game
if (iContainer)
{
iContainer->iGameEngine->PauseGame();
iContainer->iGameEngine->iHaveFocus = EFalse;
}
}
// call base class event handler
CAknView::HandleForegroundEventL(aForeground);}
-
8/6/2019 Symbian OS Workshop
44/48
Symbian OS Workshop
2005 Mopius Page 44/48
As you can see, depending on whether the application got or lost the focus, a status
variable of the game engine is modified accordingly. Note that its not good to resume
the game right when the application gets the focus again its better to let the user start
the game when he is ready.
Our own implementation overrides the base implementation, which also has to be
called at the end of our function.
Step 16 - Periodic Events
The update of the game itself is done using an Active Object, the corresponding class
can be found in the UpdateAO.cpp file. This means that the game doesnt have a
fixed frame rate and measures the time between the frames to find out how much the
ball and the panel have moved since the last frame.
This means that all values are calculated internally using floating point numbers.
Unfortunately, the processors in mobile phones dont support floating point values, so
all this is emulated in software, which makes those calculations much slower than their
integer counterparts.
For many games it would be sufficient to use a fixed frame rate, with periodic callbacks
from a timer. The movements could then be fixed integer numbers, without the need to
do those more accurate calculations.
Keeping the backlight on
Mopoid still uses a fixed timer (which is actually also an active object thats provided by
Symbian OS). Its used to decrease the score of the player every five seconds, to make
the game more challenging. Another issue is that the phones switch off their backlight
if no key has been pressed for some time. This is bad when the user is still playing, and
just waiting for the ball to come down again. Therefore, we have to reset the user
inactivity timer of the phone every few seconds. This is done using the following call,
which you should add to the timer callback function (DoCallBack()) of the game
engine class:
User::ResetInactivityTime();
-
8/6/2019 Symbian OS Workshop
45/48
Symbian OS Workshop
2005 Mopius Page 45/48
Using a timer
What we have to do now is to activate the timer, so that this function gets called at all.
Scroll up a bit and youll find the StartTimerL()
function of the game engine class.The timer object has already been declared as a private member variable of the game
engine class:
CPeriodic* iPeriodicTimer;
Therefore, in the function mentioned above, we have to create the timer object and
start it:
iPeriodicTimer = CPeriodic::NewL(CActive::EPriorityLow);
iPeriodicTimer->Start(KTickInterval, KTickInterval,TCallBack(TimerCallBack, this));
Note that we use the static NewL() function of the CPeriodic object that Symbian OS
provides. We do this because iPeriodicTimer is a member variable, therefore the
object isnt pushed onto the cleanup stack. If anything serious fails, the object will be
deleted by the destructor of the game engine.
In the next line we start the timer and tell it to do callbacks every 5 seconds
(KTickInterval is set to 5000000). The last parameter specifies the callback function
that the timer will call every five seconds. Its name is TimerCallBack() and it is
part of the game engine class (referenced bythis). This function is already
implemented by the example code.
Stopping the timer
When the game is paused or ends, the timer has to be stopped (and deleted). This is
quite simple. The following source code goes into the StopTimer() function.
if (iPeriodicTimer)
{
iPeriodicTimer->Cancel();
delete iPeriodicTimer;
iPeriodicTimer = NULL;
}
The cancel function of the timer is called to stop it. Then the object will be deleted and
set to NULL so that everyone knows that the timer is no longer here. If we need it again,
it will just be created again.
-
8/6/2019 Symbian OS Workshop
46/48
Symbian OS Workshop
2005 Mopius Page 46/48
Step 17 - Final notes
The game is finished! If you wish, you can take a look at some other parts of the source
code that are not part of this tutorial. For example the sound playing routines are quite
interesting. The game also uses an external level file. You can edit it with a normal text
editor and quickly create your own levels. This file is read and parsed by the game.
About the author
This tutorial was written by Andreas Jakl. He is the founder ofMopius, a company
which creates innovative mobile products that let users experience what they have
never seen before.
The game The Journey is one of the worlds first mobile, location-based adventure
game. It was released as an open source game and has already been downloaded more
than 10,000 times. Its successor, The Journey II, extends the concept and creates a
huge and fascinating virtual world to be explored by the player. The two games have
received several awards, including Most Innovative Game (Mobile Fun Awards) and
a jury award of the Austrian State Price. The game has even been featured on TV.
Contact
To get more information or to get in contact with the author:
Mopius
Andreas Jakl
Widerinstr. 22
3100 St. Plten
Austria / Europe
email:[email protected]
web: http://www.mopius.com/
tel.: +43 (0)676 / 722 82 78
mailto:[email protected]://www.mopius.com/http://www.mopius.com/mailto:[email protected] -
8/6/2019 Symbian OS Workshop
47/48
Symbian OS Workshop
2005 Mopius Page 47/48
Copyright
This tutorial is copyrighted by Andreas Jakl. You are free to use the source code of the
Mopoid game (licensed as GPL) provided as part of this tutorial in your own projects.
If you would like to use this tutorial (or parts of it) for own courses, please contact us.
You are not allowed to republish it without explicit written permission by the author.
Republish by Symbian with permission.
-
8/6/2019 Symbian OS Workshop
48/48
Symbian OS Workshop
Step 18 - Exercises
If you want to do some tasks on your own, below are suggestions on how the game
could be improved:
Alternative key handling
Some Series 60 phones have a joystick thats far from perfect. Those users might prefer
to control the panel using the number keys. Add an alternative key handling to allow
controlling the panel using the 4 (left) and 6 (right) keys. You can handle them in the
same switch case as for the joystick movements. Hint: handle the number keys by using
something like case '4':
Define more levels
The sample game comes with five levels enough to try it out, but there could be
more. Take a look at how the levels are defined in the levels.dat file, find out
what kinds of bricks the numbers in the file define, how many lines make up one level.
Then add new levels and configure the game so that it knows about your additions.
Remember to execute dobitmaps.bat after you changed the levels.dat file, so
that its copied to the correct directory where the emulator will find it!
Saving the game progress
Especially when the game is longer, its important that the user can resume a game later
on. It should therefore be possible to save (at least) the current level and the score that
the player had when he entered the level. Youd have to save the score in a new
member variable.
To save this, extend the data file by a flag signaling whether a game is/was active, the
score the player had when he entered the level and the level he was playing.
When the player leaves the game and the game is active, set the flag to true and save the
game data. The next time the game is started, those values should be restored.