{"id":481,"date":"2011-11-04T13:45:43","date_gmt":"2011-11-04T13:45:43","guid":{"rendered":"http:\/\/www.drmop.com\/?p=481"},"modified":"2011-11-04T13:45:43","modified_gmt":"2011-11-04T13:45:43","slug":"marmalade-sdk-tutorial-turning-iwgame-into-a-real-game-engine","status":"publish","type":"post","link":"http:\/\/www.drmop.com\/index.php\/2011\/11\/04\/marmalade-sdk-tutorial-turning-iwgame-into-a-real-game-engine\/","title":{"rendered":"Marmalade SDK Tutorial &#8211; Turning IwGame into a Real Game Engine"},"content":{"rendered":"<p>This tutorial is part of the Marmalade SDK tutorials collection. To see the tutorials index <a title=\"Marmalade SDK Tutorials\" href=\"http:\/\/www.drmop.com\/index.php\/marmalade-sdk-tutorials\/\" target=\"_self\">click here<\/a><\/p>\n<p>In our previous tutorial we created created an actor, scene and camera system to automate the handling of game objects for us as well as allow us to create different types of actors derived from a common actor base. This week we are going to take the previous IwGame code base and turn it into a proper game engine. If you just want the code to this tutorial then <a title=\"IwGame Engine Source Code\" href=\"http:\/\/www.drmop.com\/wp-content\/uploads\/2011\/11\/IwGame_v0.200.zip\" target=\"_self\">download it from here<\/a>.<\/p>\n<h2>Cleaning up the Mess<\/h2>\n<p>If you take a look at last weeks Main.cpp, you may agree that it just looks static, messy and not very readable. This week we are going to clean up our act and turn IwGame into a real usable game engine. Lets take a quick look at our new Main.cpp to see how much tidying up has been done:<\/p>\n<pre>\r\n<blockquote>\r\n\r\nint main()\r\n{\r\n    <span style=\"color: #008000;\">\/\/ Init Game<\/span>\r\n    Game::Create();\r\n    GAME-&gt;Init();\r\n\r\n    <span style=\"color: #008000;\">\/\/ Main Game Loop<\/span>\r\n    while (!s3eDeviceCheckQuitRequest())\r\n    {\r\n        <span style=\"color: #008000;\">\/\/ Update the game<\/span>\r\n        if (!GAME-&gt;Update())\r\n            break;\r\n\r\n        <span style=\"color: #008000;\">\/\/ Check for back button quit<\/span>\r\n        if (IW_GAME_INPUT-&gt;isKeyDown(s3eKeyAbsBSK))\r\n            return false;\r\n\r\n        <span style=\"color: #008000;\">\/\/ Draw the scene<\/span>\r\n        GAME-&gt;Draw();\r\n    }\r\n\r\n    GAME-&gt;Release();\r\n    Game::Destroy();\r\n\r\n    return 0;\r\n}<\/blockquote>\r\n<\/pre>\n<p>Wow, ok, where\u2019s everything gone? our game has been whittled down to initialisation, update, draw and clean-up. Well not quite, the code has gone somewhere, some of it has been integrated into the IwGame engine whilst the game specific code has been moved into a proper game class. Remember last week, we created scenes to manage actors? Well this week we have created a CIwGame class to manage scenes.<\/p>\n<h2>IwGame Class for Managing our Game<\/h2>\n<p>if you check out the engine code you will notice some new files:<\/p>\n<p>IwGame.cpp<br \/>\nIwGame.h<br \/>\nIwGameImage.cpp<br \/>\nIwGameImage.h<\/p>\n<p>Lets take a quick look at the CIwGame class:<\/p>\n<pre>\r\n<blockquote>\r\n\r\nclass CIwGame\r\n{\r\npublic:\r\n    <span style=\"color: #008000;\">\/\/ Public access for scene iteration<\/span>\r\n    typedef CIwList::iterator    _Iterator;\r\n    _Iterator                    begin() { return Scenes.begin(); }\r\n    _Iterator                    end()   { return Scenes.end(); }\r\n\r\nprotected:\r\n    <span style=\"color: #008000;\">\/\/\/\/ Properties<\/span>\r\n    CIwGameScene*           CurrentScene;        <span style=\"color: #008000;\">\/\/ Scene that has current input focus<\/span>\r\n    CIwGameScene*           NextScene;           <span style=\"color: #008000;\">\/\/ Scene that we wish to switch focus to<\/span>\r\n    CIwList&lt;CIwGameScene*&gt;  Scenes;              <span style=\"color: #008000;\">\/\/ A collection of game scenes<\/span>\r\n\r\npublic:\r\n    void                    addScene(CIwGameScene *scene);\r\n    void                    removeScene(CIwGameScene* scene);\r\n    void                    removeScene(unsigned int name_hash);\r\n    CIwGameScene*           findScene(unsigned int name_hash);\r\n    CIwGameScene*           findScene(const char* name);\r\n    CIwGameScene*           getScene(int index);\r\n    void                    clearScenes();\r\n    void                    changeScene(CIwGameScene *new_scene);\r\n    bool                    changeScene(unsigned int name_hash);\r\n    \/\/\/\/ Properties end\r\n\r\nprotected:\r\n    uint64                  LastFrameTime;        <span style=\"color: #008000;\">\/\/ The time at which the last frame ended<\/span>\r\n\r\npublic:\r\n    virtual void            Init();\r\n    virtual void            Release();\r\n    virtual bool            Update();\r\n    virtual void            Draw();\r\n    virtual void            Save() {}\r\n    virtual void            Load() {}\r\n\r\nprivate:\r\npublic:\r\n    void                    SetBackgroundColour(uint8 r, uint8 g, uint8 b, uint8 a);\r\n};<\/blockquote>\r\n<\/pre>\n<p>As you can see its basically a class that allows us to add \/ remove and change scenes. It also provides initialisation, release, update, drawing and save \/ load functionality.<\/p>\n<p>These methods represent the most basic functionality that I believe any game would need. If you take a look at IwGame.cpp you will notice that there is quite a lot of code in there. Lets take a quick look at what CIwGame::Init() does:<\/p>\n<p>CIwGame\u2019s Init() method carries out some basic Marmalade SDK and game specific initialisation:<\/p>\n<pre>\r\n<blockquote>\r\n\r\nvoid IwGame::Init()\r\n{\r\n    CurrentScene = NULL;\r\n    NextScene = NULL;\r\n\r\n    <span style=\"color: #008000;\">\/\/ Initialise Marmalade SDK graphics system and Iw2D module<\/span>\r\n    IwGxInit();\r\n    Iw2DInit();\r\n\r\n    <span style=\"color: #008000;\">\/\/ Initialise the input system<\/span>\r\n    CIwGameInput::Create();\r\n    IW_GAME_INPUT-&gt;Init();\r\n\r\n    <span style=\"color: #008000;\">\/\/ Init IwSound<\/span>\r\n    IwSoundInit();\r\n\r\n    <span style=\"color: #008000;\">\/\/ Initialise Marmalade SDK resource manager<\/span>\r\n    IwResManagerInit();\r\n\r\n#ifdef IW_BUILD_RESOURCES\r\n    \/\/ Tell resource system how to convert WAV files\r\n    IwGetResManager()-&gt;AddHandler(new CIwResHandlerWAV);\r\n#endif\r\n\r\n    <span style=\"color: #008000;\">\/\/ Set default background colour<\/span>\r\n    SetBackgroundColour(0, 0, 0, 0);\r\n\r\n    <span style=\"color: #008000;\">\/\/ Get initial time stamp<\/span>\r\n    LastFrameTime = s3eTimerGetMs();\r\n}<\/blockquote>\r\n<\/pre>\n<p>You will notice that much of this code was present in our previous tutorials Main.cpp initialisation code. We have moved it into our CIwGame base so that we have some basic initialisation code that allows us to get our games up and running quickly.<\/p>\n<p>Similarly our CIwGame::Release() method:<\/p>\n<pre>\r\n<blockquote>\r\n\r\nvoid IwGame::Release()\r\n{\r\n    <span style=\"color: #008000;\">\/\/ Clean up scenes<\/span>\r\n    for (_Iterator it = Scenes.begin(); it != Scenes.end(); ++it)\r\n        delete *it;\r\n    Scenes.clear();\r\n\r\n    <span style=\"color: #008000;\">\/\/ Shut down the input system<\/span>\r\n    IW_GAME_INPUT-&gt;Release();\r\n    CIwGameInput::Destroy();\r\n\r\n    <span style=\"color: #008000;\">\/\/ Shut down the resource manager<\/span>\r\n    IwResManagerTerminate();\r\n\r\n    <span style=\"color: #008000;\">\/\/ Shutdown IwSound<\/span>\r\n    IwSoundTerminate();\r\n\r\n    <span style=\"color: #008000;\">\/\/ Shut down Marmalade graphics system and the Iw2D module<\/span>\r\n    Iw2DTerminate();\r\n    IwGxTerminate();\r\n}<\/blockquote>\r\n<\/pre>\n<p>The only thing new here is the recursive release of all of the attached scenes<\/p>\n<p>The last method I am going to look at is our CIwGame::Update() method<\/p>\n<pre>\r\n<blockquote>\r\n\r\nbool IwGame::Update()\r\n{\r\n    <span style=\"color: #008000;\">\/\/ Calculate how long the last game frame took (capped at 60 and 10 fps) - We use this to scale all of our transient variables that rely<\/span>\r\n    <span style=\"color: #008000;\">\/\/ upon time so that everything movess at the same rate regardless of our devices frame rate<\/span>\r\n    float dt = (float)(s3eTimerGetMs() - LastFrameTime) \/ 16.67f;\r\n    if (dt &lt; 1.0) dt = 1.0f;     if (dt &gt; 6.0f) dt = 6.0f;\r\n    LastFrameTime = s3eTimerGetMs();\r\n\r\n    <span style=\"color: #008000;\">\/\/ Clear the screen<\/span>\r\n    IwGxClear(IW_GX_COLOUR_BUFFER_F | IW_GX_DEPTH_BUFFER_F);\r\n\r\n    <span style=\"color: #008000;\">\/\/ Update pointer system<\/span>\r\n    IW_GAME_INPUT-&gt;Update();\r\n\r\n    <span style=\"color: #008000;\">\/\/ Update Iw Sound Manager<\/span>\r\n    IwGetSoundManager()-&gt;Update();\r\n\r\n    <span style=\"color: #008000;\">\/\/ Check for scene change<\/span>\r\n    if (NextScene != CurrentScene)\r\n    {\r\n        <span style=\"color: #008000;\">\/\/ Notify scenes that there is a change of circumstances<\/span>\r\n        if (CurrentScene != NextScene)\r\n        {\r\n            if (CurrentScene != NULL)\r\n            {\r\n                CurrentScene-&gt;NotifyLostFocus(NextScene);\r\n                if (CurrentScene-&gt;getAllowSuspend())\r\n                    CurrentScene-&gt;NotifySuspending(NextScene);\r\n            }\r\n            if (NextScene != NULL)\r\n            {\r\n                NextScene-&gt;NotifyGainedFocus(CurrentScene);\r\n                if (NextScene-&gt;getAllowSuspend())\r\n                    NextScene-&gt;NotifyResuming(CurrentScene);\r\n            }\r\n            CurrentScene = NextScene;\r\n        }\r\n    }\r\n\r\n    <span style=\"color: #008000;\">\/\/ Update all scenes that are not suspended<\/span>\r\n    for (_Iterator it = Scenes.begin(); it != Scenes.end(); ++it)\r\n    {\r\n        if (CurrentScene == *it)\r\n        {\r\n            (*it)-&gt;Update(dt);\r\n        }\r\n        else\r\n        {\r\n            if (!(*it)-&gt;getAllowSuspend())\r\n            {\r\n                (*it)-&gt;Update(dt);\r\n            }\r\n        }\r\n    }\r\n\r\n    return true;\r\n}<\/blockquote>\r\n<\/pre>\n<p>Update() basically does most of what we were doing in our previous tutorials main loop, except that we use the concept of a \u201ccurrent scene\u201d. Because scenes can potentially be overlaid over one another and we do not want to always be processing all scenes within our game, we use the concept of a current scene which has the focus of the player.<\/p>\n<p>Now that we have the ability to change scenes, we ideally need a mechanism for notifying the other scenes that they have been switched to or switched away from, allowing our scenes to carry out processing specific to handle such events.<\/p>\n<p>Another important addition to our game update loop is the measurement of time. At the start of Update() we calculate how much time has passed since Update() was last called. We can use this value to scale all of our transient variables (animations, movement etc..) within our game to ensure that they move in a consistent manner regardless of variations in frame rate. The variable dt holds our scaling factor, which is how much we need scale our transient variables by to ensure that they remain in step with our frame rate. If we did not handle time within our game then animations and movement \/ spinning etc.. would slow down when our games frame rate drops and increase when our frame rate increases.<\/p>\n<h2>Building Our Own Game Class<\/h2>\n<p>The idea of the CIwGame class is to provide the most basic functionality required to initialise, clean-up and update \/ draw our game. In order to create a real game we should derive our own class from CIwGame and add our own game specific code, not forgetting to call the CIwGame base methods so we do not miss out on our already implemented functionality.<\/p>\n<p>In this case we create a class called Game.cpp which is a singleton class that derives from CIwGame and implements Init(), Release(), Update() and Draw() methods. if you take a quick look at Game.cpp you will notice that the game specific code from our old Main.cpp has been moved here.<\/p>\n<p>We also go a step further and remove our dependency on storing references to scenes, images and animations etc, instead opting for finding them within their respective managers as and when needed. For example:<\/p>\n<p>In Game::Update() we have:<\/p>\n<pre>\r\n<blockquote>\r\n\r\nCIwGameScene* scene = findScene(\"GameScene\");\r\nif (scene != NULL)\r\n{\r\n    <span style=\"color: #008000;\">\/\/ Get tapped position in our virtual screen space<\/span>\r\n    CIwFVec2 pos = scene-&gt;ScreenToVirtual(IW_GAME_INPUT-&gt;getTouch(0)-&gt;x, IW_GAME_INPUT-&gt;getTouch(0)-&gt;y);\r\n    <span style=\"color: #008000;\">\/\/ Find our sprite atlas<\/span>\r\n    CIwGameImage* image = scene-&gt;getImageManager()-&gt;findImage(\"sprites\");\r\n    <span style=\"color: #008000;\">\/\/ Find our manic face animation frames<\/span>\r\n    CIwGameAnimImageFrame* anim = scene-&gt;getAnimFrameManager()-&gt;getImageFrames(0);\r\n\r\n    <span style=\"color: #008000;\">\/\/ Create 10 player actors<\/span>\r\n    for (int t = 0; t &lt; 10; t++)\r\n    {\r\n        ActorPlayer::Create(pos.x, pos.y, scene, image, anim);\r\n    }\r\n}<\/blockquote>\r\n<\/pre>\n<p>Notice how we now search for our game scene, instead of accessing it via the local game_scene variable. We also do the same with image and anim.<\/p>\n<p>This brings me to another new addition to the CIwGame engine.<\/p>\n<h2>CIwGameImage and  CIwGameImageManager \u2013 Managing Images<\/h2>\n<p>After I had finished factoring out most of the code from Main.cpp I was left with what to do about the sprite atlas images that my game is going to use. I didn\u2019t really want to be storing pointers to images all over the place that may or may not still exist, this can lead to some nasty and hard to find bugs. instead I opted to create a class that will manage all of the images that my scene allocates. This way we have them all in one central location and the manager can manage their lifetimes for us.<\/p>\n<p>In addition, I thought that I would extend the CIw2DImage class a little by wrapping it up inside the CIwGameImage class, allowing us to add other cool functionality such as on-demand load and eventually streaming from an external web server (future blog will cover this).<\/p>\n<p>So you will find that all instances of CIw2DImage throughout the engine have been replaced with the more manageable CIwGameImage class.<br \/>\n.<br \/>\nAn important thing to note about CIwGameImage based images is that they rely on a CIwResGroup resource group, this is to allow them to be loaded on-demand.<\/p>\n<p>To create and add an image to the game engine its a simple case of:<\/p>\n<pre>\r\n<blockquote>\r\n\r\nCIwResGroup* Level1Group = IwGetResManager()-&gt;GetGroupNamed(\"Level1\");\r\ngame_scene-&gt;getImageManager()-&gt;addImage(\"sprites\", Level1Group);<\/blockquote>\r\n<\/pre>\n<p>This creates our image based on its resource name and group and adds it to our scenes image manager. Note that the underlying CIw2DImage is not yet created. This gets created when you first call CIwGameImage::getImage2D() (on-demand). You can however force the loading \/ creation of the underlying CIw2DImage by passing true to addImage():<\/p>\n<p>game_scene-&gt;getImageManager()-&gt;addImage(&#8220;sprites&#8221;, Level1Group, true); or by calling the Load() method on the CIwGameImage.<\/p>\n<p>Well that brings us to the end of this tutorial, I\u2019m very rushed this week so I will probably not get the time to create additional tutorials until next week. I did want to create an actual game this week using the engine, but I thought that with the engine tidy up is probably best to do that next week so readers don\u2019t get lost. I may be able to fit a short blog update in early next week covering the wrapping up of Marmalades sample audio engine into IwGame.<\/p>\n<p>If you want the source code that accompanies this tutorial then you can <a title=\"IwGame Engine Source Code\" href=\"http:\/\/www.drmop.com\/wp-content\/uploads\/2011\/11\/IwGame_v0.200.zip\" target=\"_self\">download it from here<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This tutorial is part of the Marmalade SDK tutorials collection. To see the tutorials index click here In our previous tutorial we created created an actor, scene and camera system to automate the handling of game objects for us as well as allow us to create different types of actors derived from a common actor [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,13,155,29,43,118,44,154,42,28,148,3,45,1],"tags":[188,189,190,191,729,718],"class_list":["post-481","post","type-post","status-publish","format-standard","hentry","category-airplay-sdk","category-android-app-development","category-apps","category-blackberry-playbook","category-blackberry-playbook-app-development","category-c-programming","category-game-and-app-development","category-games","category-ios-app-development","category-marmalade-sdk","category-pocketeers-limited","category-programming","category-samsung-bada-development","category-uncategorized","tag-2d-game-engine","tag-ciwgame","tag-ciwgameimage","tag-ciwgameimagemanager","tag-iwgame-engine","tag-marmalade-sdk"],"_links":{"self":[{"href":"http:\/\/www.drmop.com\/index.php\/wp-json\/wp\/v2\/posts\/481","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.drmop.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.drmop.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.drmop.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.drmop.com\/index.php\/wp-json\/wp\/v2\/comments?post=481"}],"version-history":[{"count":4,"href":"http:\/\/www.drmop.com\/index.php\/wp-json\/wp\/v2\/posts\/481\/revisions"}],"predecessor-version":[{"id":486,"href":"http:\/\/www.drmop.com\/index.php\/wp-json\/wp\/v2\/posts\/481\/revisions\/486"}],"wp:attachment":[{"href":"http:\/\/www.drmop.com\/index.php\/wp-json\/wp\/v2\/media?parent=481"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.drmop.com\/index.php\/wp-json\/wp\/v2\/categories?post=481"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.drmop.com\/index.php\/wp-json\/wp\/v2\/tags?post=481"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}