symbian os workshop

Upload: kkfemin

Post on 07-Apr-2018

230 views

Category:

Documents


1 download

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.