Book Image

Cocos2d Game Development Blueprints

By : Jorge Jordán
Book Image

Cocos2d Game Development Blueprints

By: Jorge Jordán

Overview of this book

Table of Contents (15 chapters)
Cocos2d Game Development Blueprints
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

Run Xcode Run


Now that we have our newly created project, let's see how it looks. Click on Run at the top-left of the Xcode window and it will run the project in the iOS Simulator, which defaults to an iOS 6.1 iPhone:

Voilà! You've just built your first Hello World example with Cocos2d v3, but before going further, let's take a look at the code to understand how it works.

Note

We will be using iOS Simulator to run the game unless otherwise specified.

Understanding the default project

We are going to take an overview of the classes available in a new project, but don't worry if you don't understand everything; the objective of this section is just to get familiar with the look of a Cocos2d game.

If you open the main.m class under the Supporting Files group, you will see:

int main(int argc, char *argv[]) {

    @autoreleasepool {
        int retVal = UIApplicationMain(argc, argv, nil, @"AppDelegate");
        return retVal;
    }
}

As you can see, the @autorelease block means that ARC is enabled by default on new Cocos2d projects so we don't have to worry about releasing objects or enabling ARC.

ARC is the acronym for Automatic Reference Counting and it's a compiler iOS feature to provide automatic memory management of objects. It works by adding code at compile time, ensuring every object lives as long as necessary, but not longer.

On the other hand, the block calls AppDelegate, a class that inherits from CCAppDelegate which implements the UIApplicationDelegate protocol. In other words, the starting point of our game and the place to set up our app is located in AppDelegate, like a typical iOS application.

If you open AppDelegate.m, you will see the following method, which is called when the game has been launched:

-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [self setupCocos2dWithOptions:@{
          CCSetupShowDebugStats: @(YES),
    }];

    return YES;
}

Here, the only initial configuration specified is to enable the debug stats, specifying the option CCSetupShowDebugStats: @(YES), that you can see in the previous block of code.

The number on the top indicates the amount of draw calls and the two labels below are the time needed to update the frame and the frame rate respectively.

Note

The maximum frame rate an iOS device can have is 60 and it's a measure of the smoothness a game can attain: the higher the frame rate, the smoother the game.

You will need to have the top and the bottom values in mind as the number of draw calls and the frame rate will let you know how efficient your game will be.

The next thing to take care of is the startScene method:

-(CCScene *)startScene
{
    // The initial scene will be GameScene
    return [IntroScene scene];
}

This method should be overriden to indicate the first scene we want to display in our game. In this case, it points to IntroScene where the init method looks like the following code:

- (id)init
{
    // Apple recommends assigning self with super's return value
    self = [super init];
    if (!self) {
        return(nil);
     }

    // Create a colored background (Dark Gray)
    CCNodeColor *background = [CCNodeColor nodeWithColor:[CCColor colorWithRed:0.2f green:0.2f blue:0.2f alpha:1.0f]];
    [self addChild:background];

    // Hello world
    CCLabelTTF *label = [CCLabelTTF labelWithString:@"Hello World" fontName:@"Chalkduster" fontSize:36.0f];
    label.positionType = CCPositionTypeNormalized;
    label.color = [CCColor redColor];
    label.position = ccp(0.5f, 0.5f); // Middle of screen
    [self addChild:label];

    // Helloworld scene button
    CCButton *helloWorldButton = [CCButton buttonWithTitle:@"[ Start ]" fontName:@"Verdana-Bold" fontSize:18.0f];
    helloWorldButton.positionType = CCPositionTypeNormalized;
    helloWorldButton.position = ccp(0.5f, 0.35f);
    [helloWorldButton setTarget:self selector:@selector(onSpinningClicked:)];
    [self addChild:helloWorldButton];

    // done
    return self;
}

This code first calls the initialization method for the superclass IntroScene by sending the [super init] message. Then it creates a gray-colored background with a CCNodeColor class, which is basically a solid color node, but this background won't be shown until it's added to the scene, which is exactly what [self addChild:background] does. The red "Hello World" label you can see in the previous screenshot is an instance of the CCLabelTTF class, whose position will be centered on the screen thanks to label.position = ccp(0.5f, 0.5f).

Note

Cocos2d provides the cpp(coord_x, coord_y) method, which is a precompiler macro for CGPointMake and both can be used interchangeably.

The last code block creates CCButton that will call onSpinningClicked once we click on it.

Don't worry about all these new classes we have been talking about up to now as we will discuss them further in later sections. This source code isn't hard at all, but what will happen when we click on the Start button? Don't be shy, go back to the iOS Simulator and find out!

If you take a look at the onSpinningClicked method in IntroScene.m, you will understand what happened:

- (void)onSpinningClicked:(id)sender
{
    // start spinning scene with transition
    [[CCDirector sharedDirector] replaceScene:[HelloWorldScene scene]
        withTransition:[CCTransition transitionPushWithDirection:CCTransitionDirectionLeft duration:1.0f]];
}

This code presents the HelloWorldScene scene replacing the current one (InitScene) and it's being done by pushing HelloWorldScene to the top of the scene stack and using a horizontal scroll transition that will last for 1.0 second. Let's take a look at the HelloWorldScene.m to understand the behavior we just experienced:

@implementation HelloWorldScene
{
    CCSprite *_sprite;
}

- (id)init
{
    // Apple recommends assigning self with super's return value
    self = [super init];
    if (!self) {
        return(nil);
    }

    // Enable touch handling on scene node
    self.userInteractionEnabled = YES;

    // Create a colored background (Dark Gray)
    CCNodeColor *background = [CCNodeColor nodeWithColor:[CCColor colorWithRed:0.2f green:0.2f blue:0.2f alpha:1.0f]];
    [self addChild:background];

    // Add a sprite
    _sprite = [CCSprite spriteWithImageNamed:@"Icon-72.png"];
    _sprite.position = ccp(self.contentSize.width/2,self.contentSize.height/2);
    [self addChild:_sprite];

    // Animate sprite with action
    CCActionRotateBy* actionSpin = [CCActionRotateBy actionWithDuration:1.5f angle:360];
    [_sprite runAction:[CCActionRepeatForever actionWithAction:actionSpin]];

    // Create a back button
    CCButton *backButton = [CCButton buttonWithTitle:@"[ Menu ]" fontName:@"Verdana-Bold" fontSize:18.0f];
    backButton.positionType = CCPositionTypeNormalized;
    backButton.position = ccp(0.85f, 0.95f); // Top Right of screen
    [backButton setTarget:self selector:@selector(onBackClicked:)];
    [self addChild:backButton];

    // done
    return self;
}

This piece of code is very similar to the one we saw in IntroScene.m, which is why we just need to focus on the differences. If you look at the top of the class, you can see how we are declaring a private instance for a CCSprite class, which is also a subclass of CCNode, and its main role is to render 2D images on the screen.

Note

The CCSprite class is one of the most-used classes in Cocos2d game development, as it provides a visual representation and a physical shape to the objects in view.

Then, in the init method, you will see the instruction self.userInteractionEnabled = YES, which is used to enable the current scene to detect and manage touches by implementing the touchBegan method, which will be covered in detail later in this book.

The next thing to highlight is how we initialize a CCSprite class using an image, positioning it in the center of the screen. If you read a couple more lines, you will understand why the icon rotates as soon as the scene is loaded. We create a 360-degree rotation action thanks to CCRotateBy that will last for 1.5 seconds. But why is this rotation repeated over and over? This happens thanks to CCActionRepeatForever, which will execute the rotate action as long as the scene is running.

The last piece of code in the init method doesn't need explanation as it creates a CCButton that will execute onBackClicked once clicked. This method replaces the scene HelloWorldScene with IntroScene in a similar way as we saw before, with only one difference: the transition happens from left to right.

Did you try to touch the screen? Try it and you will understand why touchBegan has the following code:

-(void) touchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
    CGPoint touchLoc = [touch locationInNode:self];

    // Move our sprite to touch location
    CCActionMoveTo *actionMove = [CCActionMoveTo actionWithDuration:1.0f position:touchLoc];
    [_sprite runAction:actionMove];
}

This is one of the methods you need to implement to manage touch. The others are touchMoved, touchEnded, and touchCancelled. When the user begins touching the screen, the sprite will move to the registered coordinates thanks to a commonly used action: CCActionMoveto. This action just needs to know the position that we want to move our sprite to and the duration of the movement.

Now that we have had an overview of the initial project code, it is time to go deeper into some of the classes we have shown. Did you realize that CCNode is the parent class of several classes we have seen? You will understand why if you keep reading.