Book Image

Creating Games with cocos2d for iPhone 2

By : Paul Nygard
Book Image

Creating Games with cocos2d for iPhone 2

By: Paul Nygard

Overview of this book

Cocos2d for iPhone is a simple (but powerful) 2D framework that makes it easy to create games for the iPhone. There are thousands of games in the App Store already using cocos2d. Game development has never been this approachable and easy to get started. "Creating Games with cocos2d for iPhone 2" takes you through the entire process of designing and building nine complete games for the iPhone, iPod Touch, or iPad using cocos2d 2.0. The projects start simply and gradually increase in complexity, building on the lessons learned in previous chapters. Good design practices are emphasized throughout. From a simple match game to an endless runner, you will learn how to build a wide variety of game styles. You will learn how to implement animation, actions, create "artificial randomness", use the Box2D physics engine, create tile maps, and even use Bluetooth to play between two devices. "Creating games with cocos2d for iPhone 2" will take your game building skills to the next level.
Table of Contents (16 chapters)
Creating Games with cocos2d for iPhone 2
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

Let's build a menu


We'll start building the project from the default cocos2d v2.x - cocos2d iOS template. Once the project is created, we first remove the HelloWorldLayer.h/.m files. HelloWorld is a good starting point for learning the code structure, but we don't really want (or need) this boilerplate class for anything (don't forget to remove the #import "HelloWorldLayer.h" at the top of the IntroLayer.m class). For now we'll leave the reference in the bottom of the IntroLayer.m's makeTransition class.

One of the most commonly used classes in the cocos2d framework is probably the CCLayer. A CCLayer is the object that is (usually) represented on the screen, and acts as our "canvas" for our game. We use the CCLayer object as a basis, and then create subclasses of it to add our own game code.

There is another often-used class, the CCScene class. A CCScene class can be thought of as a "container" for CCLayer objects. A CCScene object is rarely used for much more than adding CCLayers as children. A good comparison is like the creation of cartoons before the age of computers. Each scene was assembled from a stack of transparent plastic sheets, each with a different part of the scene on it: each main character would have their own layer, another for the background, another for each different element of the scene. Those plastic sheets are the equivalent of a CCLayer objects, and the CCScene class is where these are stacked up to display on screen.

We will start with a basic CCLayer subclass, MTMenuLayer. We create a title, and a basic menu. We need to pay attention to how we call the MTPlayfieldScene class (our main game screen) from the menu.

Filename: MTMenuLayer.m

-(void) startGameEasy {
    [[CCDirector sharedDirector] replaceScene:
     [MTPlayfieldScene sceneWithRows:2 andColumns:2]];
}

-(void) startGameMedium {
    [[CCDirector sharedDirector] replaceScene:
     [MTPlayfieldScene sceneWithRows:3 andColumns:4]];
}

-(void) startGameHard {
    [[CCDirector sharedDirector] replaceScene:
     [MTPlayfieldScene sceneWithRows:4 andColumns:5]];
}

You will notice that the startGameXXX methods are calling a custom constructor for the scene, rather than the normal [MyLayer scene] that is commonly used. We will explain the sceneWithRows:andColumns: method shortly.

This book will not include the complete code within the text. Portions that aren't interesting for the discussion will be omitted.

Tip

Downloading the example code

You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files

e-mailed directly to you.

Where is the scene?

Oh, you noticed? The boilerplate cocos2d template includes a class method +(id) scene inside the layer (in HelloWorldLayer). While this approach works, it can lead to confusion as we build more complex scenes with multiple layers. Using the template-based approach may seem odd when you call a method that takes a CCScene object as a parameter, yet you pass it a value like [MySpecialLayer scene]. So are you referencing a CCScene or CCLayer object? It makes a lot more logical sense to us that you would, in this example, pass a value like [MySpecialScene scene]. It is less confusing to pass a scene object when a CCScene is requested. A CCScene object is a higher-level container that was designed to contain CCLayer objects, so why not keep it as its own class? Let's go ahead and examine our approach:

Filename: MTMenuScene.h

#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "MTMenuLayer.h"

@interface MTMenuScene : CCScene {
}

+(id)scene;

@end

Filename: MTMenuScene.m

#import "MTMenuScene.h"

@implementation MTMenuScene

+(id)scene {
    return( [ [ [ self alloc ] init ] autorelease ] );
}

-(id) init
{
  if( (self=[super init])) {
        MTMenuLayer *layer = [MTMenuLayer node];
        [self addChild: layer];
  }
  return self;
}

@end

Here we have followed the convention that the scene method returns an autoreleased object. We do not explicitly call alloc on it (when we instantiate the class), so we don't "own" the object.

Now we can go back to the IntroLayer.m file, and change the makeTransition method to point to our new menu scene:

-(void) makeTransition:(ccTime)dt
{
  [[CCDirector sharedDirector] replaceScene:
     [CCTransitionFade transitionWithDuration:1.0
        scene:[MTMenuScene scene] withColor:ccWHITE]];
} 

We also need to make sure we are importing the MTMenuScene.h file in the AppDelegate.m file. Now that our menu is complete, we can concentrate on the game itself.

Note

It is important to note that this design of using CCScene as a separate class in the structure is not universally adopted. Many people choose to follow the same approach as the templates. Both ways will work, but we are of the "camp" that strongly believes these should kept separate, as we have done here. Both ways are perfectly valid coding practice, and you are free to structure your code in other way.

Building the playfield

Next, we will add a CCScene class to drive our main game screen, here named MTPlayfieldScene. Much of this looks the same as the MTMenuScene class we defined earlier, except here we define a method sceneWithRows:andColumns: instead of the simpler scene method we used in the previous code.

Filename: MTPlayfieldScene.m

+(id) sceneWithRows:(NSInteger)numRows
         andColumns:(NSInteger)numCols {
  return [[[self alloc] sceneWithRows:numRows
                             andColumns:numCols]
                                    autorelease];
}

-(id) sceneWithRows:(NSInteger)numRows
         andColumns:(NSInteger)numCols {
  
  if( (self=[super init])) {
        // Create an instance of the MTPlayfieldLayer
        MTPlayfieldLayer *layer = [MTPlayfieldLayer
                                   layerWithRows:numRows
                                   andColumns:numCols];
        [self addChild: layer];
  }
  return self;
} 

Here we have the custom sceneWithRows:andColumns: method we referenced in the MTMenuLayer earlier. The class method handles the alloc and init methods, and identifies it as an autoreleased object, so we don't have to worry about releasing it later. The sceneWithRows:andColumns: method passes the rows and columns variables directly to the MTPlayfieldLayer class' custom init method, layerWithRows:andColumns:. This lets us pass the requested values through the scene to the layer, where we can use the values later.