The basics of Cocos2d

by

Recently I started work on an iOS game. I decided not to use the Core Animations framework provided by Apple and instead experiment with some third party game engines. I chose Cocos2D as it is an all in one package. It gives you the ability to add and control sprites, add cool graphics and animations, access to a sound engine and also 2 physics libraries.

For this blog I am going to focus on showing you a basic ‘Frogger’ type game to get your feet wet with this framework. (The reason for the ‘Frogger’ game is this is the first thing I made :) )

Firstly, you must download this framework from the Cocos2d website : http://www.cocos2d-iphone.org/download . I downloaded the latest ‘unstable’ version of Cocos2d which was 2.1 and that is the library that will be referenced in this blog post. Once downloaded, open up the Terminal and direct yourself to the folder and run :

./install-templates.sh -f -u 

Now you are ready to rock. Open up XCode and create a new project of type Cocos2D. One major thing I noticed after I created my first Cocos2D project was that there are no xib files. This is because Cocos is all done inside an OpenGL view. It is possible to use xib’s, but you will have to layer them over.

There are also no view controllers either. Cocos2D works on the idea of Scenes. Each scene typically matches up to a specific part of the game (I.E. There would be a scene for the initial menu screen, the level screen and then also for the actual game screen). Each can contain multiple layers and inside these layers are nodes such as sprites, menu bars, scoring labels etc.

If you build your project straight away, this is what you are greeted with. First thing we are going to do is remove all of this by deleting pretty much everything in the init method. Then, inside the init() method we will add our first sprite. NOTE : The positioning for this framework is different to that of the iOS standard. The bottom left is (0, 0) rather than the top left.

This is how we add a sprite to the screen :

-(id) init
{
	if( (self=[super initWithColor:ccc4(255,255,255,255)]) ) {		
		CGSize winSize = [CCDirector sharedDirector].winSize;
        self.apple = [CCSprite spriteWithFile:@"apple-logo.png"];
        self.apple.position = ccp(winSize.width/2 , self.apple.contentSize.height/2);
        [self addChild:self.apple];
	}
	return self;
}

Now we have our heroic little Apple :). Next we need to give it some enemy’s and who better than the dreaded Android bot himself:(.

- (void) addAndroid {
    
    // Choose one of 3 Android images
    NSInteger randNum = rand() % 3 + 1;
    CCSprite * android = [CCSprite spriteWithFile:[NSString stringWithFormat:@"droid-%d.png", randNum]];
    
    // Randomly choose the starting point of our android man along the Y-Axis
    CGSize winSize = [CCDirector sharedDirector].winSize;
    NSInteger minY = android.contentSize.height / 2 + self.player.contentSize.height;
    NSInteger maxY = winSize.height - android.contentSize.height/2 - self.player.contentSize.height;
    NSInteger rangeY = maxY - minY;
    NSInteger actualY = (arc4random() % rangeY) + minY;
    
    // Add our android man to the right hand side of the screen
    android.position = ccp(winSize.width + android.contentSize.width/2, actualY);
    [self addChild:android];
    
    NSInteger actualDuration = (arc4random() % 2) + 2;
    
    // Create the actions
    CCMoveTo * actionMove = [CCMoveTo actionWithDuration:actualDuration
                                                position:ccp(-android.contentSize.width/2, actualY)];
    CCCallBlockN * actionMoveDone = [CCCallBlockN actionWithBlock:^(CCNode *node) {
        [node removeFromParentAndCleanup:YES];
    }];
    [android runAction:[CCSequence actions:actionMove, actionMoveDone, nil]];
}

I have 3 different Android images to choose from so I choose a random one every time. The import parts from this method are the CCMoveTo, CCCallBlockN and CCSequence. These tell the framework where to move our Android to, what to do when it’s done, and also in what sequence to perform these actions.

Then in our init() method we can schedule this function to be called as frequent as we want and it will result in all these little Android dudes flying across the screen. You will also notice that I have added direction buttons on either side, this is so that we can move our Apple when the game starts. For this example we are going to give the Apple automatic forward motion once the player touches the screen. And then depending on the side of the screen the player touches will determine whether the Apple moves either left or right.

- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
    if(self.moving == FALSE){
        // Create the actions
        self.moving = TRUE;
        CGSize winSize = [CCDirector sharedDirector].winSize;
        CCMoveTo * actionMove = [CCMoveTo actionWithDuration:10
                                                    position:ccp(self.apple.position.x, winSize.height)];
        CCCallBlockN * actionMoveDone = [CCCallBlockN actionWithBlock:^(CCNode *node) {
            [node removeFromParentAndCleanup:YES];
        }];
        [self.apple runAction:[CCSequence actions:actionMove, actionMoveDone, nil]];
    }
    else{
        UITouch *touch = [touches anyObject];
        CGPoint location = [self convertTouchToNodeSpace:touch];
        
        if(location.x<=self.left.boundingBox.size.width){
            self.apple.position = ccp(self.apple.position.x-10, self.apple.position.y);
        }
        else if(location.x>=self.right.position.x-self.right.boundingBox.size.width/2){
            self.apple.position = ccp(self.apple.position.x+10, self.apple.position.y);
        }
    }
}

Finally on the agenda is the collision detection. For this we are going to keep track of all the Androids on the screen and at every frame we check the position of the Apple versus the Android and if they intersect, the game is over!!!

- (void)update:(ccTime)dt {
    for (CCSprite *android in self.androids) {
        if (CGRectIntersectsRect(android.boundingBox, self.apple.boundingBox)){
            CCScene *gameOverScene = [GameOverLayer sceneWithWon:FALSE];
            [[CCDirector sharedDirector] replaceScene:gameOverScene];
        }
    }
    CGSize winSize = [CCDirector sharedDirector].winSize;
    if(self.apple.position.y >= winSize.height - self.apple.boundingBox.size.height/2){
        CCScene *gameOverScene = [GameOverLayer sceneWithWon:TRUE];
        [[CCDirector sharedDirector] replaceScene:gameOverScene];
    }
}

You will also notice the introduction of another layer called GameOverLayer. It simply display’s a label saying whether you won or lost the game. This is an example of how Cocos2D switches between scenes.

And that’s all you need to know to make your first simple game in Cocos2d.

Enjoy!!

Leave a Reply

Your email address will not be published. Required fields are marked *