Docstoc

Symbian OS Workshop

Document Sample
Symbian OS Workshop Powered By Docstoc
					Provided By: Martik Panosian



                                     Symbian OS – Workshop

    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 OS
    specifics 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




    © 2005 Mopius                                                                        Page 2/48
Provided By: Martik Panosian



                                                     Symbian OS – Workshop



    Contents

    Step 0 - Preparation ........................................................................................................... 5
        Getting started ................................................................................................................ 5
        Choosing an IDE ........................................................................................................... 6
        Choice of the Series 60 SDK........................................................................................ 7
    Step 1 - Defining the Symbian OS SDK ........................................................................ 8
    Step 2 - Creating a new project ........................................................................................ 8
    Step 3 - Testing the project .............................................................................................. 9
        Troubleshooting: .......................................................................................................... 10
    Step 4 - Defining strings ................................................................................................. 11
    Step 5 - Defining the menu ............................................................................................ 12
    Step 6 - Displaying the about box ................................................................................. 14
        If something doesn’t work... ....................................................................................... 16
    Step 7 - Getting the application to the mobile phone! ............................................... 17
    Step 8 - Adding the game engine to your project........................................................ 18
        Unzipping the file......................................................................................................... 18
        Distributing the game data.......................................................................................... 18
        Adding the source files to your project..................................................................... 18
        Adding additional libraries to the project definition file......................................... 19
        Defining new text......................................................................................................... 20
        New game...................................................................................................................... 20
        Adding graphic and sound files.................................................................................. 20
        Testing............................................................................................................................ 22
        Troubleshooting ........................................................................................................... 22
    Step 9 - Loading images .................................................................................................. 22
        C and T classes ............................................................................................................. 23
        ConstructL..................................................................................................................... 23
        Loading bitmaps ........................................................................................................... 24
        Deleting images ............................................................................................................ 26
    Step 10 - Displaying the graphics..................................................................................... 27
        Handling transparency................................................................................................. 28
        Drawing a bitmap......................................................................................................... 28
    Step 11 - Handling keys..................................................................................................... 29
    © 2005 Mopius                                                                                                                   Page 3/48
Provided By: Martik Panosian



                                                    Symbian OS – Workshop
    Step 12 - Displaying text ................................................................................................... 31
        Setting a font ................................................................................................................. 31
        Reading text from the resource file ........................................................................... 32
        Formatting and displaying the text ............................................................................ 32
        Aligning text .................................................................................................................. 32
    Step 13 - Reading and writing files .................................................................................. 34
        Preparation .................................................................................................................... 34
        Setting the file name..................................................................................................... 34
        Opening the file............................................................................................................ 35
        Creating the stream ...................................................................................................... 35
        Writing the data ............................................................................................................ 35
        Closing the file .............................................................................................................. 36
        The Cleanup Stack ....................................................................................................... 36
        Loading .......................................................................................................................... 37
        Cleanup when your application is uninstalled.......................................................... 38
        Building from the command line ............................................................................... 40
    Step 14 - Setting the application icon.............................................................................. 40
    Step 15 - Handling being in the background ................................................................. 42
    Step 16 - Periodic Events.................................................................................................. 44
        Keeping the backlight on ............................................................................................ 44
        Using a timer ................................................................................................................. 45
        Stopping the timer........................................................................................................ 45
    Step 17 - Final notes .......................................................................................................... 46
        About the author .......................................................................................................... 46
        Contact........................................................................................................................... 46
        Copyright ....................................................................................................................... 47
    Step 18 - Exercises ............................................................................................................. 48
        Alternative key handling.............................................................................................. 48
        Define more levels ....................................................................................................... 48
        Saving the game progress............................................................................................ 48




    © 2005 Mopius                                                                                                                  Page 4/48
Provided By: Martik Panosian



                                     Symbian OS – Workshop

    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 emulator
          through Borland’s C++BuilderX –
          http://www.microsoft.com/whdc/devtools/debugging/

    •     Visual C++ Toolkit: only needed if you don’t have Visual Studio 6 or .net
          installed. It’s 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 the
          short 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 system’s path variable, in case they ask! It’s 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” in
    the “C:\Symbian\6.1\Series60\Epoc32\Wins\c\system\Bootdata” directory of
    your Series 60 SDK. That’s 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.




    © 2005 Mopius                                                                    Page 5/48
Provided By: Martik Panosian



                                        Symbian OS – Workshop
    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 several
    choices, each with advantages and disadvantages 1 :

     Microsoft Visual C++ 6                          Fast; efficient compilation and debugging;
                                                   some tools for Symbian OS available
                                                     Old; no real support for Symbian OS code
                                                   development

     Microsoft Visual Studio .net                     Fast; modern and good IDE; Widespread
                                                      Not directly supported by the Symbian OS
                                                   SDKs – makes development for Symbian OS
                                                   even more complicated; expensive

     Metrowerks CodeWarrior                           Symbian OS at least partially integrated
                                                       Not so cheap; IDE more difficult to master
                                                   at the beginning

     Borland C++BuilderX Mobile                       Supports visual design of menus and
     Edition 2                                     dialogues; Symbian OS related features;
                                                   currently free!
                                                      Slow and clumsy IDE; Symbian OS
                                                   integration should go farther.

     Eclipse                                          Very good IDE; free!
                                                      No support for debugging; Symbian OS not
                                                   really integrated yet.

    As you can see, there is no obvious ‘best’ way to develop Symbian OS C++
    applications. For this tutorial, Borland’s 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.
    © 2005 Mopius                                                                         Page 6/48
Provided By: Martik Panosian



                                   Symbian OS – Workshop
    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 backward
    compatible, 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 develop
    for 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 shouldn’t 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 will
    have an even harder time selling it.




    © 2005 Mopius                                                                    Page 7/48
Provided By: Martik Panosian



                                    Symbian OS – Workshop

    Step 1 - Defining the Symbian OS SDK




                    Fig. 1 – Defining the Symbian OS SDK in Borland's C++BuilderX.

    It’s time to start working! Open Borland’s C++BuilderX Mobile Edition. Go to
    “Tools” → “Symbian SDK Configuration”. Create a new SDK configuration, using the
    SDK 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 won’t work! Set the path as shown in the
    screenshot, and choose an appropriate name like “Series 60 1.2”.

    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 (don’t use a different name for this project, otherwise
    some includes of the prewritten files we will include later on won’t 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
Provided By: Martik Panosian



                                     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
    uid@symbiandevnet.com 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
Provided By: Martik Panosian



                                          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 don’t want to do this every time you test your game, select it, press the left
    softkey (“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 Microsoft’s VisualStudio.net or Microsoft’s 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
Provided By: Martik Panosian



                                    Symbian OS – Workshop
    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” (you’re 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\to
    ols;
    If this doesn’t 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
    © 2005 Mopius                                                                      Page 11/48
Provided By: Martik Panosian



                                         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
    It’s 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:




                               Fig. 8 – Adding a new menu item using the design tool.
    © 2005 Mopius                                                                                Page 12/48
Provided By: Martik Panosian



                                    Symbian OS – Workshop
    Now we’ll adapt the menu items so that they use the text we’ve 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 the
    ID. Leave the command at its default value of “1001”.

    Please note: It’s important that you press Enter after modifying a value. If you just
    switch away, it’s possible that your input isn’t 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 don’t 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
Provided By: Martik Panosian



                                        Symbian OS – Workshop

    Step 6 - Displaying the about box
    Up to now, we’ve 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 we’ve 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
Provided By: Martik Panosian



                                        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.




                             Fig. 13 – The about box in the Series 60 emulator (SDK v1.2).



    When you try the program now, the about box will already work fine. But let’s 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 creation
    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.

    © 2005 Mopius                                                                            Page 15/48
Provided By: Martik Panosian



                                    Symbian OS – Workshop
    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 don’t (and shouldn’t) 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,
    you’ll get to the “HandleCommandL()” (“L”!) function of the “MopoidView.cpp” file.
    That’s 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 the
    limitations of C++Builder’s automatically generated code.

    If something doesn’t 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!



    © 2005 Mopius                                                                   Page 16/48
Provided By: Martik Panosian



                                     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 doesn’t 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. 14 – Changing the build   Fig. 15 – Compiling for
                              target of the application.   release instead of debug.



    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, don’t forget to switch back to the “WINS / UDEB” build
    configuration when you continue development!




    © 2005 Mopius                                                                      Page 17/48
Provided By: Martik Panosian



                                    Symbian OS – Workshop

    Step 8 - Adding the game engine to your project
    Developing a whole game takes a lot of time, and in this tutorial we want to explore the
    basics of development for Symbian OS, instead of using a lot of time to create game
    routines. Because of this, we will import some prewritten files into our project and add
    several important and interesting features.

    Please note: it is possible to create a game with a more beautiful object oriented
    structure. However, the provided files were written in a way to make it easy to
    understand the Symbian OS related issues, and not to provide a perfectly structured
    program.

    Many of the steps below will be important when you develop your own project. You
    will also most likely want to add graphic and sound files, add existing source files and
    so on.

    Unzipping the file
    Unzip the file “Mopoid.Step8.Update.zip” to your “C:\Symbian\dev\” directory.
    Make sure that you keep the directory structure of the archive! Overwrite all files. If
    there is no warning that files are overwritten, you didn’t extract it to the right directory.

    Distributing the game data
    The archive contains a new directory called “data”, which includes graphics and
    sounds for our game. When you execute the application in the emulator, it will look in
    an own directory for any files. Call the “.\data\dobitmaps.bat” file to automatically
    create the corresponding directory and copy all data files there. If your Series 60 SDK is
    not installed in the default location (“C:\Symbian”) or if you are using a different SDK
    than v1.2, you will first have to adapt the directory names in the batch file.

    Adding the source files to your project
    Next, you have to tell the IDE that you want to add some new source files to the
    project. Right-click on the “Sources” item of the project window, and choose “Add
    sources...”



    © 2005 Mopius                                                                     Page 18/48
Provided By: Martik Panosian



                                   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
Provided By: Martik Panosian



                                   Symbian OS – Workshop
    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, don’t change the function name to contain the
    “L” suffix – the start game function doesn’t 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

    © 2005 Mopius                                                                   Page 20/48
Provided By: Martik Panosian



                                       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 not click 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
    you’re done, click on OK.

    The target path defines the location and name of the file on the device. If the file name
    isn’t 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 can’t 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
Provided By: Martik Panosian



                                    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 you’re 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 doesn’t work any more, use the reference project
    from “Mopoid.Step8.zip”!



    Step 9 - Loading images
    Symbian 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, it’s better to use .png or .jpg files. Unfortunately, no predefined loading
    routines are available, and it’s rather complicated to do it manually. Also,
    decompressing those files takes some time, therefore it works asynchronously, in its
    © 2005 Mopius                                                                    Page 22/48
Provided By: Martik Panosian



                                     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 can’t 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 by NewL().

    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. That’s bad. Therefore, code executed in a C++

    © 2005 Mopius                                                                  Page 23/48
Provided By: Martik Panosian



                                     Symbian OS – Workshop
    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 memory
    allocating 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, you’d have to
    write the code for these steps (allocation and calling ConstructL()) 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, let’s
    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 doesn’t 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:



    © 2005 Mopius                                                                      Page 24/48
Provided By: Martik Panosian



                                   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<CFbsBitmap*, MopoidShared::ENumSprites> iSprites;

    Why is the variable called iSprites instead of sprites 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. Let’s 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 don’t need so many
    colours anyway. ESpritePanel is the textual representation of an ID, called
    enumeration, and is defined in “MopoidSharedData.h”.



                                   Fig. 22 – The             Fig. 23 – The
                                   panel graphic             mask 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
Provided By: Martik Panosian



                                   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
    it’s 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 don’t 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 don’t require a mask.
    However, we have got several different colours for the bricks. Instead of loading the
    images one by one, it’s 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 disk
    space (overall), and even though the application will temporarily need more memory,
    it’s 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 ESpriteBrickNormal position.


    Deleting images
    When you try to execute your application, it should already load the images, even
    though you won’t see them. We have not written the code to display them yet. Now try
    © 2005 Mopius                                                                   Page 26/48
Provided By: Martik Panosian



                                       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.
    It’s 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 don’t 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 won’t 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 isn’t 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 it’s not allowed to modify the member data of the game engine class.

    © 2005 Mopius                                                                         Page 27/48
Provided By: Martik Panosian



                                         Symbian OS – Workshop
    Handling transparency
    Let’s 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 don’t 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! That’s
    why we set the brush to a null brush, letting the background of a bitmap shine through
    its transparent parts.

    Drawing a bitmap
    First, we’ll 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 bitmap’s 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”.
    © 2005 Mopius                                                                       Page 28/48
Provided By: Martik Panosian



                                      Symbian OS – Workshop
    As we have found out before, the bricks don’t 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




                               Fig. 26 – Our Mopoid game can now display graphics!


    the following line of code at the marked position inside the for loop, which loops
    through the bricks grid to draw all visible bricks.

    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
    It’s 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 wouldn’t be necessary in our case, as nothing else

    has 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
Provided By: Martik Panosian



                                    Symbian OS – Workshop
    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. It’s 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 we’ll 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 we’ll 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, you’ll notice that it has a boolean return value. This will

    tell the system if the key press has been handled. If it hasn’t, 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
    doesn’t have to send it to anyone else. Set the flag that’s 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.

    Don’t 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 of Mopoid.Step11.zip.

    © 2005 Mopius                                                                     Page 30/48
Provided By: Martik Panosian



                                    Symbian OS – Workshop

    Step 12 - Displaying text
    The game is still lacking an important part – it doesn’t display any status information
    informing the player about his points, lives or level. We’ll 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<30> tempStr;

    Let’s 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. It’s also
    used for the font outline, which is the 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 you’d
    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, we’ll stick to the easiest method and use the AnnotationFont.
    It’s 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. We’ll 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, don’t 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
Provided By: Martik Panosian



                                   Symbian OS – Workshop
    Reading text from the resource file
    Next, we’ll 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 the CEikonEnv class takes
    care 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 we’ve 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 don’t 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:


    © 2005 Mopius                                                                    Page 32/48
Provided By: Martik Panosian



                                    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, it’s 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, you’ll 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, isn’t it? To make the game really cool, there are still several things left to add...
    © 2005 Mopius                                                                       Page 33/48
Provided By: Martik Panosian



                                    Symbian OS – Workshop

    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 <s32file.h>

    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,
    it’s compiled onto this (virtual) drive. It’s not writeable, therefore we have to adapt the
    © 2005 Mopius                                                                    Page 34/48
Provided By: Martik Panosian



                                     Symbian OS – Workshop
    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 doesn’t allow modifying the data. That doesn’t 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 can’t 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 we’ll use the WriteInt32L() function of the stream to write the data.

    © 2005 Mopius                                                                      Page 35/48
Provided By: Martik Panosian



                                    Symbian OS – Workshop
    // 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
    very useful. Let’s 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 doesn’t include the player name. It’s 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
    You’re 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, here’s 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.

    © 2005 Mopius                                                                    Page 36/48
Provided By: Martik Panosian



                                    Symbian OS – Workshop
    However, in this case you just have the pointer to an object, which will be destroyed,
    but leave the object itself unreferenced in memory. That’s 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, you’ll 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();

    © 2005 Mopius                                                                     Page 37/48
Provided By: Martik Panosian



                                       Symbian OS – Workshop
    You could improve the handling of a wrong version number, but for the first version
    of the game it’s 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”.

    Don’t 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
    won’t be called when it’s 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
Provided By: Martik Panosian



                                   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 isn’t 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 it’s running. It doesn’t have to be

    © 2005 Mopius                                                                   Page 39/48
Provided By: Martik Panosian



                                         Symbian OS – Workshop
    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 doesn’t 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 should
    install 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 don’t have to type it in every time you want to build for the device.

    When you’re finished, don’t 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.
    © 2005 Mopius                                                                                     Page 40/48
Provided By: Martik Panosian



                                          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. Don’t forget to click the “Add” button
    after selecting a file!

    When you’re 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
Provided By: Martik Panosian



                                       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 won’t
    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 containing num_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 doesn’t.




    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 automatically
                                        when it gets sent to the background.



    © 2005 Mopius                                                                              Page 42/48
Provided By: Martik Panosian



                                   Symbian OS – Workshop
    Even for a small game like Mopoid it’s very important to handle this event. The game
    has to be paused so that it doesn’t 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. It’s 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 didn’t implement it when it created the code, so we’re 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);
    }
    © 2005 Mopius                                                                   Page 43/48
Provided By: Martik Panosian



                                   Symbian OS – Workshop
    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 it’s not good to resume
    the game right when the application gets the focus again – it’s 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 doesn’t 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 don’t 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 that’s provided by
    Symbian OS). It’s 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();


    © 2005 Mopius                                                                   Page 44/48
Provided By: Martik Panosian



                                     Symbian OS – Workshop
    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 you’ll 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 isn’t 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 by this). 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.
    © 2005 Mopius                                                                     Page 45/48
Provided By: Martik Panosian



                                   Symbian OS – Workshop

    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 of Mopius, 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 world’s 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. Pölten
    Austria / Europe


    email: contact@mopius.com
    web: http://www.mopius.com/
    tel.: +43 (0)676 / 722 82 78



    © 2005 Mopius                                                                   Page 46/48
Provided By: Martik Panosian



                                    Symbian OS – Workshop
    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.




    © 2005 Mopius                                                                    Page 47/48
Provided By: Martik Panosian



                                    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 that’s 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 it’s copied to the correct directory where the emulator will find it!

    Saving the game progress
    Especially when the game is longer, it’s 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. You’d 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.




    © 2005 Mopius                                                                   Page 48/48

				
DOCUMENT INFO
Shared By:
Stats:
views:23
posted:11/5/2011
language:English
pages:47
Description: Symbian OS Workshop Easy To Use And Create Your Own.