Designing An Open-Source iPhone Game

Advertisement

I love games and I’m a huge math nerd, so I made a new iPhone game based on a famous math problem1 called The Seven Bridges of Königsberg2. I’m selling it in the App Store3, but I also want to share it with everyone, so I made it open source4.

This article is the first in a series that will walk through iOS programming using this game as an example. This first article gives you an overview of the game and of iOS programming in general. We’ll look at a few specific pieces and see how the whole project fits together.

First Steps

This article uses the real game as the example. You’ll need a couple of things to start using the code:

  1. A Mac,
  2. The Xcode development environment from Apple, which you can get free from Apple5.

After you’ve set up Xcode, go ahead and download the project from GitHub6. Open it, and then run it by pressing the big “Run” button in the upper-left corner of Xcode.

Running Seven Bridges in Xcode7

That will open the game in the simulator so that you can play for free and follow along with the article.

The Rules Of The Game

Seven Bridges is a puzzle game. The player visits a town of islands surrounded by rivers.

Hello Bridges level

The game’s interaction works with a single gesture: tap where you want the player to go. If you hit a bridge, you’ll cross it; if you hit a river, you’ll bounce off it.

Two Bridges level

The game lets you restart the level, undo your last move and go back to the menu. There are also a few other screens to support the game.

Level set selector

Levels selector

You won screen

Confused? Check out the Seven Bridge walkthrough video8.

You’ll see similar layouts in popular games such as Cut the Rope9 and Where’s My Water?10

Before We Start

Seven Bridges is a simple game. It doesn’t handle complex physics like Angry Birds11 does or rich textures like Infinity Blade12 does. Seven Bridges has just a single player who walks over bridges and bumps into rivers. It sounds easy, but a lot goes into even a simple game like this.

Seven Bridges is written in a combination of Objective-C13 and Objective-C++14. If you’re used to programming in scripting languages such as JavaScript, then Objective-C will come as a shock.

Programming for iOS

Getting started with JavaScript is easy. You start with a little jQuery behind a button and go from there. Many iPhone programming tutorials make it sound like writing iPhone applications is just as easy. It’s not.

Objective-C has been around for nearly 30 years. Programming with it entails learning a large ecosystem and some fundamental concepts of how it all holds together. All of the Objective-C documentation assumes that you have a strong background in both object-oriented programming15 and the C programming language16.

Objective-C is very different from JavaScript, and programming with it requires an understanding of some of the old-school programming fundamentals. Make sure you’ve read a book about object-oriented programming, such as Object-Oriented Analysis and Design with Applications17 by Grady Booch, as well as The C Programming Language18 by Brian Kernighan and Dennis Ritchie. Reading “The Objective-C Programming Language19” guide from Apple is also a good idea.

The news isn’t all bad. Objective-C shows its age in some areas, but the tools are well written and the runtime environment is amazing.

The Files

You already have the code on your computer, so let’s get a better idea of what we’re looking at. You can tell what each file does by looking at its extension.

  • .h
    These files are class headers20. Each of these files represents the public information available about a single class or object in the project.
  • .m
    These files are Objective-C implementation files.
  • .mm
    These files are Objective-C++ implementation files. Objective-C++ is a hybrid in which you can use parts of Objective-C and C++21 in the same file. Seven Bridges uses Objective-C++ so that it can take advantage of frameworks written in C++.
  • .xib
    These files define visual views22 in the game where you can lay out buttons and other controls.
  • .png
    These files are individual images used in the game.
  • .pvr.gz
    These files contain large sets of images called sprite sheets. The images are combined into a single file so that they load faster and take up less space.
  • .plist
    These are XML properties files. They define the basics of how the application works and the positions of the images in each sprite sheet.
  • .m4a
    These are audio files that provide the sounds for the game.

Xcode projects also include a folder named your project.xcodeproj containing all of the project’s configuration files. Mine is named bridges2 because I messed up the project so badly that I had to start over.

The Frameworks

In addition to the standard Objective-C libraries, Seven Bridges uses three major frameworks.

UIKit

Every iOS application starts with UIKit23. This comprehensive framework from Apple provides all of the basic controls your application uses, such as windows, buttons and text fields. Most of the classes in UIKit start with the prefix UI, like UIWindow and UIButton.

The easiest way to work with UIKit is by using the visual editor provided with Xcode. Xcode makes it easy to drag and drop controls into your application. It works well for business applications, but it wouldn’t know anything about the rivers or bridges in my game. For that, I need a gaming framework and a bit of code.

Cocos2d

You could draw on the screen directly with OpenGL24, but that signs you up for a lot of work in managing each pixel on the screen. Game libraries provide higher-level support for placing images, creating animations and managing your game. There are a few for iOS.

I chose Cocos2d for iPhone25 because it’s well supported, has a simple API and comes with a lot of examples. It also has Ray Wenderlich26’s excellent tutorials. Ray is a prolific writer about iOS games; every time I searched for a new topic, it led me back to him. His tutorial about collision detection27 provided the fundamentals for my game, and his simple iPhone game with a Cocos2D tutorial28 is a perfect little sample game.

Cocos2d handles all of the animations in my game, as well as the scenes where you’re actually playing; it also handles sprites29, which we’ll get to a little later. It was originally written in Python for desktop applications, so make sure to search for “Cocos2d iPhone” when you’re looking for help on the Web. Cocos2d files start with the prefix CC.

Cocos2d handles user interactions, but it can’t handle interactions with objects. I need to know when the player runs into a river, bridge or any other object. That type of collision detection is made much easier with a physics library such as Box2d.

Box2d

Box2d30 is a physics engine31 written in portable C++. It can handle complex variables like gravity and friction, but we’re only using it for collision detection. Box2d files start with the prefix b2.

My game doesn’t use the complex physics of swinging candy from Cut the Rope or of sloshing liquids from Where’s My Water? It just handles a player walking around the screen and bumping into things. Box2d tells me when those bumps happen, and my code handles the rest.

Player bump interaction

In this article, we’ll see how to use these three frameworks together to build a scene, integrate sprites, respond to user gestures and detect collisions.

Building A Scene

The playable area of the game is drawn with LevelLayer3732, which extends the Cocos2d class CCLayerColor. This layer handles all of the drawing in the game and the responses when the user taps on the game screen.

The game is made up of a set of images called sprites. Each item in the game’s scene, such as a bridge or a piece of a river, is made up of a separate image file.

The 7 Bridges sprite sheet

Images used this way, instead of being created programmatically, perform much faster and can include subtleties such as shading and texture without needing a lot of code. The technique also makes delegating artwork easier because the artist doesn’t need to know anything about Objective-C.

The sprites all fit together into a single file called a sprite sheet. Cocos2d takes that image and a properties file containing coordinates and creates the individual images from it when the application runs.

The real reason to use a sprite sheet is performance. Ray Wenderlich has written a good article comparing sprite sheet performance to individual images33. The short story is that sprite sheets are much faster than images loaded individually.

Managing sprite sheets manually is a real pain, so I used TexturePacker34. It costs a little money, but $25 is well worth the hours of adjusting pixel coordinates it saved me. TexturePacker can also convert a sprite sheet to PVR (the internal image format for iOS) and compress it with Gzip so that it loads even faster.

Once we’ve created the sprite sheet, we’re ready to add the sprites to a scene.

Adding the Sprites

Xcode makes it easy to drag and drop images into a view, but that won’t work for dynamic scenes like our game levels. We’ll need to write some code.

Cocos2d interprets our sprite sheet with the CCSpriteBatchNode class. We initialize the sprite sheet once for the application and then use the individual items when we build our level.

CCSpriteBatchNode *spriteSheet = [[CCSpriteBatchNode batchNodeWithFile:@"bridgesprites.pvr.gz"
                                 capacity:150] retain];
[[CCSpriteFrameCache sharedSpriteFrameCache]
addSpriteFramesWithFile:@"bridgesprites.plist"];
[self addChild:spriteSheet];

This code creates a new sprite sheet with our sprites file, initializes it with the properties file that defines the images in the sheet, and adds the sheet as a child to our current scene. You can see the full code for this in the init method of LevelLayer.mm35.

Now that we have the sheet, we can use it to load individual sprites, like this:

CCSprite *bridge = [CCSprite spriteWithSpriteFrameName:@"bridge_v.png"];
[spriteSheet addChild:bridge];
bridge.position = ccp(100, 100);

This code snippet creates a new sprite from the sprite sheet, adds that sprite as a child of the sheet, and positions it 100 points from the left side of the screen and 100 points up from the bottom. (We’ll get to what “points” are in the next section.)

Cocos2d manages the sprite sheets with a caching mechanism it calls the sprite frame cache. We loaded the frame cache in the previous code snippet when we loaded the bridgesprites.pvr.gz sprite sheet file and the bridgesprites.plist file that describes it. Cocos2d loaded all of those images into the cache, and we can now get them by name.

All positions in Cocos2d are based on a coordinate system in which point 0,0 is in the bottom-left corner. UIKit puts the point 0,0 at the top left of the screen. There are a few places where we need to convert back and forth further in the code.

Instead of using points directly, the game uses a tile system to position the sprites.

Pixels, Points and Tiles

iOS supports five devices:

  • iPhone 3.5 inch
  • iPhone 3.5 inch with Retina display
  • iPhone 4 inch with Retina display
  • iPad
  • iPad with Retina display

Different iOS device sizes

Supporting every device means handling multiple layouts. Cocos2d gives us a lot of help here by supporting points instead of pixels when specifying layout. Pixels represent an exact screen location, whereas points are relative to the device. This makes it easy to support Retina devices whose screens are the same size but pack in twice as many pixels.

Seven Bridges goes farther by defining a tile system. Tiles are a way of grouping pixels into larger squares for easier layout. We make the screen 28 tiles tall and at least 42 tiles wide. The tiles make it easy to define where the sprites go on each level. Switch the DEBUG_DRAW constant in Bridgecolors.h36 to true and you’ll be able to see the tile grid in the background of each level.

Two Bridges debug view

Touches and Interactions

UIKit handles touches on controls such as buttons and tables, but for the game scene we’ll need a generic touch handler. Cocos2d provides that with the ccTouchesEnded method. First, we have to tell Cocos2d that we want touch events, like this:

self.isTouchEnabled = YES;

Then, we implement the ccTouchesEnded method to get called whenever the user taps the screen.

-(void)ccTouchesEnded:(NSSet*) touches withEvent:(UIEvent*) event { 
   UITouch *touch = [touches anyObject];
   CGPoint location = [touch locationInView:[touch view]];
   location = [[CCDirector sharedDirector] convertToGL:location];

   // Do some stuff with the point that the user touched…
}

LevelLayer3732 handles each screen touch with some simple logic:

  • If the player isn’t on the screen yet, then place the player sprite where the user has touched and return.
  • If the player is on the screen, then move the player from the current location to the place where the user has touched.

That’s all we need to do for the touch. The real logic of the game happens when we handle the collisions.

Boxes and Collisions

Each object on the screen is a sprite: a little image file that sits at particular coordinates on the screen. Cocos2d can handle the position and animation of those images, but it won’t know if they run into each other. This is where Box2d shines.

The LayerMgr38 class adds and removes all of the images from the layers in the game. When it adds an image, it also creates a box around it. Boxes are the fundamental concept of Box2d. They outline the position of an object on the screen and detect when it interacts with other objects. Box2d supports complex box shapes, but all of the boxes in this game are rectangles.

Whenever we add an image to the scene, we draw a box around it with Box2d. The box works with a helper class called a contact listener39. This listener sits in a timer and asks the Box2d model if any of the objects have run into each other after each frame of the game.

The contact listener implements two important functions: BeginContact and EndContact. These functions are called when two objects come into contact and when that contact stops. When that happens, we save the data so that we can use it in the layer that renders the level.

void MyContactListener::BeginContact(b2Contact* contact) {
    MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() };
    CCSprite *spriteA = (CCSprite *) contact->GetFixtureA()->GetBody()->GetUserData();
    CCSprite *spriteB = (CCSprite *) contact->GetFixtureB()->GetBody()->GetUserData();
    if (spriteA.tag == PLAYER || spriteB.tag == PLAYER) {
        _contacts.push_back(myContact);
    }
}

void MyContactListener::EndContact(b2Contact* contact) {
    MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() };

    std::vector::iterator pos;
    pos = std::find(_contacts.begin(), _contacts.end(), myContact);
    if (pos != _contacts.end()) {
        _contacts.erase(pos);
    }
}

Once we’ve stored the data about the collisions, we use it every time we draw the level.

CCSprite *spriteA = (CCSprite *) bodyA->GetUserData();
    CCSprite *spriteB = (CCSprite *) bodyB->GetUserData();

    if (spriteA.tag == RIVER && spriteB.tag == PLAYER) {
        [self bumpObject:spriteB:spriteA];
    } else if (spriteA.tag == BRIDGE && spriteB.tag == PLAYER) {
        [self crossBridge:spriteB:spriteA];

The contact listener gives us the two sprites that collided, and we’ll use the tag of each sprite to determine how to handle it. When two sprites run into each other, we react with some simple logic:

  • If the player contacts a river, then bounce back.
  • If the player contacts a bridge, then check whether the bridge has been crossed.
    • If the bridge is crossed, then bounce back.
    • If the bridge isn’t crossed, then cross it and move the player to the other side.

Separating the player’s movement from the collision makes it easy to move the player around the screen. We don’t have to define islands or worry about managing where the player is allowed to move. We just place each sprite in the level and wait for the player to run into it.

Defining Levels

Each level in the game is defined in a separate JSON document. Separating the level definitions from the code is important so that we can update the levels or add new ones without having to change the code.

Each level defines a name, an ID and a set of objects that go in the level.

{
    "level": {
        "name": "Hello Bridges!",
        "rivers": [
            {
                "x": "14",
                "y": "b-t",
                "orient": "v"
            }
        ],
        "bridges": [
            {
                "x": "14",
                "y": "m",
                "orient": "h"
            }
        ]
    }
}

Each object has a coordinate in the tile system and a set of properties that define how the object works. For example, a bridge specifies an orient property to determine whether the bridge is horizontal or vertical and a color property to determine whether the bridge has a particular color. A separate page defines everything you can put in a level40.

Many games define levels in XML, but I chose JSON because it’s faster to parse and works better with the Web. One day, I’d like to create a mode in which you can load new levels from a website without having to download a new version of the game.

The Level41 class defines each level; levels are controlled by a LevelMgr42. The level manager loads the levels, sorts them for the menu and creates the thumbnails of each level on the menu screen.

Seven Bridges does a lot more, but this is a good place to stop for the first article.

What’s Next

This article has walked us through some of the core parts of games for iOS, but there’s a lot more. You can get Seven Bridges43 (not free) or download the source code44 and run it for free in the simulator.

We’ve reviewed the major frameworks, looked at the anatomy of a game, and learned the basics of user interactions. In the next article, we’ll delve deeper into the pieces and see how they all fit together.

(al)

Footnotes

  1. 1 http://en.wikipedia.org/wiki/Seven_Bridges_of_K%C3%B6nigsberg
  2. 2 http://zgrossbart.github.com/bridges/
  3. 3 https://itunes.apple.com/us/app/seven-bridges/id586598714?ls=1&mt=8
  4. 4 https://github.com/zgrossbart/bridges
  5. 5 https://developer.apple.com/xcode/
  6. 6 https://github.com/zgrossbart/bridges
  7. 7 http://www.smashingmagazine.com/wp-content/uploads/2012/10/xcode_run.png
  8. 8 https://vimeo.com/55454871
  9. 9 http://en.wikipedia.org/wiki/Cut_the_Rope
  10. 10 http://en.wikipedia.org/wiki/Where's_My_Water%3F
  11. 11 http://en.wikipedia.org/wiki/Angry_birds
  12. 12 http://en.wikipedia.org/wiki/Infinity_Blade
  13. 13 http://en.wikipedia.org/wiki/Objective-C
  14. 14 http://en.wikipedia.org/wiki/Objective-C#Objective-C.2B.2B
  15. 15 http://en.wikipedia.org/wiki/Object-oriented_programming
  16. 16 http://en.wikipedia.org/wiki/C_(programming_language)
  17. 17 http://www.informit.com/store/product.aspx?isbn=020189551X
  18. 18 http://en.wikipedia.org/wiki/The_C_Programming_Language_(book)
  19. 19 https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjectiveC/ObjC.pdf
  20. 20 http://en.wikipedia.org/wiki/Header_file
  21. 21 http://en.wikipedia.org/wiki/C%2B%2B
  22. 22 https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaViewsGuide/WhatAreViews/WhatAreViews.html#//apple_ref/doc/uid/TP40002978-CH5-SW1
  23. 23 http://developer.apple.com/library/ios/#documentation/uikit/reference/UIKit_Framework/_index.html
  24. 24 http://en.wikipedia.org/wiki/Opengl
  25. 25 http://www.cocos2d-iphone.org/
  26. 26 http://www.raywenderlich.com/
  27. 27 http://www.raywenderlich.com/606/how-to-use-box2d-for-just-collision-detection-with-cocos2d-iphone
  28. 28 http://www.raywenderlich.com/352/how-to-make-a-simple-iphone-game-with-cocos2d-tutorial
  29. 29 http://en.wikipedia.org/wiki/Sprite_(computer_graphics)
  30. 30 http://en.wikipedia.org/wiki/Box2d
  31. 31 http://en.wikipedia.org/wiki/Physics_engine
  32. 32 https://github.com/zgrossbart/bridges/blob/master/bridges2/LevelLayer.mm
  33. 33 http://www.raywenderlich.com/2361/how-to-create-and-optimize-sprite-sheets-in-cocos2d-with-texture-packer-and-pixel-formats
  34. 34 http://www.codeandweb.com/texturepacker
  35. 35 https://github.com/zgrossbart/bridges/blob/master/bridges2/LevelLayer.mm
  36. 36 https://github.com/zgrossbart/bridges/blob/master/bridges2/BridgeColors.h
  37. 37 https://github.com/zgrossbart/bridges/blob/master/bridges2/LevelLayer.mm
  38. 38 https://github.com/zgrossbart/bridges/blob/master/bridges2/LayerMgr.mm
  39. 39 https://github.com/zgrossbart/bridges/blob/master/bridges2/MyContactListener.h
  40. 40 https://github.com/zgrossbart/bridges/wiki/Level-Specification
  41. 41 https://github.com/zgrossbart/bridges/blob/master/bridges2/Level.h
  42. 42 https://github.com/zgrossbart/bridges/blob/master/bridges2/LevelMgr.h
  43. 43 http://zgrossbart.github.com/bridges/
  44. 44 https://github.com/zgrossbart/bridges

↑ Back to topShare on Twitter

Zack Grossbart is an engineer, designer, and author. He's a founding member of the Spiffy UI project, the architect of the WordPress Editorial Calendar, and a Consulting Engineer with NetIQ. Zack began loading DOS from a floppy disk when he was five years old. He first worked professionally with computers when he was 15 and started his first software company when he was 16. Zack lives in Cambridge, Massachusetts with his wife and daughter.

Advertising
  1. 1

    Nice tutorial. Well done!

    2
  2. 2

    This is a great tutorial. It starts at the very bottom (explaining each file type), and explores core concepts from ground up.

    I would love to see more of these for android and other more “complex” subjects.

    4
  3. 3

    OH MY GOD. The spacing between Replay & Menu :(

    1
  4. 5

    Great article. Im just starting out with iOS, so this should come in handy. thanks

    0
  5. 6

    Great tutorial! I have an iOS card game (Blackbird) and I just used UIKit. I’ve been hoping to do another game using Cocos2d and Box2d at some point and this was a great introduction to them!

    I have thought about making my app open source, but I didn’t because I have been worried that someone else would take it, modify it, and release it for free or enhance it to compete with mine or something. I’m interested in your reasoning/thoughts on making yours open source and still selling it in the App Store. Am I worrying over nothing?

    1
    • 7

      There’s a few reasons I made my game open source.

      The first is that I believe in the benefits of open source. It isn’t for every project, I write closed source code for my day job, but it’s great for projects like this.

      I don’t make a living from this game. I’d love to break even on Seven Bridges, but if I don’t that would be OK. I wrote the game to learn more about iOS programming and show other people what I can do.

      Open source makes my code better. I wrote more comments, did more refactoring, and cleaned up more code because I knew lots of people would be looking at it.

      And other people did look at my code. They asked questions, made comments, and found a few bugs.

      My experience with open source wasn’t all positive. Soon after I released Seven Bridges another developer took my code and released their own version called Bridges Seven. They took my name off of it (in violation of the license) and charged $5.99 instead of my $0.99. I was bemused at first, but then they released a free version with ads. The free version had no mention of me, the other contributors, or the original app. It also had no improvements or other changes.

      It turns out my experience is pretty common. This developer is well known for stealing apps from GitHub and repackaging them. I contacted Apple about this and they sent him a letter challenging his copyright claims. He backed down and quickly removed his app from the store.

      I hope this game helps other developers. I’d love to have other people design new levels, learn from the code, and reuse whatever they can.

      Open source is always scary. You risk other people using your code in ways you don’t want and the whole world can see your mistakes. Every bad decision I made during this project is there in the project history. That fear can make it tough to release open source, but it also helps.

      The benefits of open source outweigh the negatives for me, but every developer has to make their own decision.

      4
  6. 10

    Swet Nath@iPhone Game Development

    February 14, 2013 3:36 am

    Nice information !!!!!!! I am also a part of B24 E Solutions which is an iPhone App and Game development company and very well know that these type of information articles and screenshots are very helpful for developers.

    1
  7. 11

    I’ve introduced some pieces of the game and iOS development in this article, but there’s a lot more. I’m working on the next article in this series and I want to hear from you. What would you like to see? Here are my ideas:

    – iOS game design fundamentals
    – iOS graphics and graphic formats
    – Handling player movements and animations
    – Creating level screenshots and handling menus
    – Developing for iPhone and iPad
    – Objective-C language fundamentals
    – Loading levels and parsing JSON with Objective-C
    – Xcode details and tools
    – The math that makes games run

    Are you excited to see any of these? Is some part of iOS programming driving you crazy? Have any other great ideas for the next article in the series? Leave a comment and let me know?

    2
    • 12

      Personally, I would be excited to read more about:

      * Handling player movements and animations
      * iOS game design fundamentals
      * The math that makes the game run

      1
  8. 13

    Great tutorial, thanks a lot for taking the time to put it all together.

    If you’re doing another, I’d personally be interested in:

    - Loading levels and parsing JSON with Objective-C
    - Handling player movements and animations

    I think the old 8-bit tile-based game mechanics work well on touch screens, so if you’re covering animations it’d be really interesting to learn about character animation (i.e. whether during a screen press event you’d tell a character sprite to cycle through frames x-y of a series of bitmat images). Guessing here!

    -1
  9. 14
  10. 15

    I want the next article!
    Loving this.

    1
  11. 16

    Rahul Aggarwal

    June 4, 2013 3:12 am

    Nice Article. I agree to most of your points above.

    Myself being part of this industry since 2002 can say with confidence that mobile is more than iOS. Yes iOS did bring about new energy and innovation but mobility is more than about the platform alone. IT is about unleashing the power of information which can be accessed from anytime, anywhere.

    Moreover, with the combination of Mobile and Cloud, Mobile has the power to surpass the desktops.

    I have been working at Endeavour, The Mobility Company since 2002 and hence can tell you that today mobile is more of a lifestyle than just a device.
    techendeavour.com/mobile-application-development

    1

Leave a Comment

Yay! You've decided to leave a comment. That's fantastic! Please keep in mind that comments are moderated and rel="nofollow" is in use. So, please do not use a spammy keyword or a domain as your name, or else it will be deleted. Let's have a personal and meaningful conversation instead. Thanks for dropping by!

↑ Back to top