[Translation] Introduction to CocosBuilder

Published on January 22, 2013

[Translation] Introduction to CocosBuilder



Translation of Introduction to CocosBuilder .
The author of the original article is Ali Hafiji , a developer for iOS and Android.

CocosBuilder is a free tool that allows you to quickly and easily manage sprites, layouts, and scenes while developing your game using Cocos2D.

CocosBuilder is ideal for quickly planning menus and other elements of the interface of game scenes, while you will not experience problems in their layout in space.
During the training, you write a Cat Jump game. You will see how CocosBuilder saves you a ton of time and code.

Before CocosBuilder appeared, creating even a basic interface in a Cocos2D game was a headache for the developer. To add a menu or button to the game, you usually did something like this:
  • Trying to guess. “Mmm ... I think this button should be somewhere around 50 to 50.”
  • Application Launch. “Yeah, not really ...”
  • Another attempt. “I think 60 to 50 will be better!”
  • Check and everything is new. “Damn, it's not that anyway. Grrr! ”

CocosBuilder eliminates all the massive iterations for setting up and testing a sprite’s position. CocosBuilder frees you time to focus on the logic of the game, rather than tearing your hair out through your interface, which makes you a more productive developer - and that's always good, isn't it?

This beginner's guide will show you how to use CocosBuilder to create simple interfaces. You will learn how to create menus, buttons, particle systems, layers, and connect interfaces in CocosBuilder.
During the training, you will write a Cat Jump game originally developed for the Cocos2D via Minigames workshop . Of course, this time there will be much less coding. You will see how CocosBuilder saves you a ton of time and code.
This guide assumes that you have basic knowledge of Cocos2D. If you're new to Cocos2D, read the Cocos2D tutorials first.

Cat Jump Game


Cat Jump is a cat game that has a bad day. He just walks about his business, walks along the street when all of a sudden they come across him - cars, trucks, and even children on bicycles!
A screenshot of the game you saw at the beginning of this guide.

Your poor cat has a limited number of lives (of course 9), and your goal is to stay alive as long as possible, avoiding trouble.
To get started, download the CatJump version without CocosBuilder . Open it in Xcode, launch and play for a while - it's a lot of fun!
After playing, take a look at the code - you will see tons specified directly in the code, offsets and menu items, text elements and sprites. It was very hard to write all this - you will learn about a way to make it better!
During the training, you will remake the game Cat Jump by completing the following tasks:
  • Redo the main menu using CocosBuilder. Now the main menu is done by placing the menu items in the coordinates that are hardcoded in the code - you delete this code and redo the menu using CocosBuilder.
  • Add Options screen. You will add a new screen with three buttons to select the difficulty level: Easy, Medium and Hard. Choosing a complexity option will cause a selector in the program code.
  • Add About screen. You will also add a screen with a description of the program and a demonstration of a cool graphic effect. Using CocosBuilder, you don't write a single line of code to do this!
  • Redo the main screen of the game using CocosBuilder. You will remove the manual sprite layout and use CocosBuilder instead.
  • Redo the game ending screen using CocosBuilder. Again, no hardcoded offsets!

Finally, you will get useful tips on how to troubleshoot common CocosBuilder errors. You will learn about it now and save your time later.

Getting Started with CocosBuilder


If you have not already done so, download CocosBuilder . Make sure to download the latest version, which at the time of writing is 2.1. Also download the sample files.


Unzip CocosBuilder from the downloaded archive and copy it to the Applications folder.
Before creating a new project in CocosBuilder, you need to create a directory for your project. This is the place where you will store all game resources / assets.

Note : You can also use resource references in your project, but using the directory structure with the resources stored there is more convenient, as this allows me to know exactly where all my files are and helps to keep my resources organized.

Create a new folder on your desktop and name it CocosBuilderFiles . Then create two subfolders in this folder and name them Resources and Scenes .


The Resources folder will obviously contain all the resources for the game (sprites, fonts, etc.). If you want, you can copy all the resources from the Cat Jump project that you downloaded earlier, but to make it even easier - I created a ZIP file with everything you need. Download, unzip and copy its contents to the Resources folder.

Launch CocosBuilder and select the menu item File \ New \ New Project. Name the project CatJump and save it in the CocosBuilderFiles folder.
Now that you have created the project, you will see the resource and scene folders in the sidebar of the project on the left side of CocosBuilder. Also note that CocosBuilder automatically created a new folder called ccbResources . There you will see a new file called HelloCocosBuilder.ccb . Double-click on a file to see its contents.
This is a very simple layer labeled "Hello CocosBuilder":


Don’t worry, your CatJump game will be a little more complicated than that.

Look, Mom, there’s no code at all!


Let's start redesigning CatJump by creating the game’s main menu. This scene will have three buttons:
  • Play - So the game starts!
  • Options - We show a scene with parameters where users can choose the level of difficulty of the game.
  • About - Let's show the scene where there will be information on how to play the game.

And the first thing you need to do is delete the HelloCocosBuilder.ccb file, as this is just a template file created by CocosBuilder.

Note: You might think that it's quite simple to delete an unused scene file from a project, but I was not able to do it directly from CocosBuilder. I had to close CocosBuilder, remove HelloCocosBuilder.ccb from Finder, and then run the project again in CocosBuilder. If someone knows an easier way to do this, please post on the forum!

Then select the menu item File \ New \ New File. In the window that appears, make sure that the CCLayer is selected in the Root object type field and check the following permission types: iPhone Landscape and iPhone 5 Landscape .


Click the Create button, enter the name of the MainMenuScene file and save it in the Scenes folder.
The project panel should look something like this:


Well, here you have created your first scene! Now, how about adding a few sprites?
Click on the CCSprite button on the toolbar. Hint: The button is circled in the image below.


So you add a new sprite to the scene.
Select the created sprite and set the file as a frameTitle_catjump.png . To do this, use the right sidebar on which the properties of the selected item appear. In the CCSprite section near the Sprite frame field, in the drop-down menu, select the Title_catjump.png file in the Resources \ Normal folder.


Then, put the sprite in the center of the scene by simply dragging it to the center. Or, if you prefer to be precise, then you can set the Anchor Point property (in the CCNode section) to 0 for X and Y values.
Please note that this will only work if you have a Position field.set to the lower left corner. If you change the value of this field, then you must accordingly change the values ​​of X and Y. Have fun - see what happens when you put different values.

Fine! You now have a background image. The next thing to do is add buttons for menu items.
Click the CCControlButton toolbar item to create a new button on the screen.


A new button is created with a nice background image, which you can find in the ccbResources folder created by CocosBuilder. Give this button the name Play using the CCControlButton section on the right sidebar, the Title field.


Adjust the position of the button. You can place it anywhere by simply dragging it or setting an absolute position using the properties on the right sidebar.
Ok, we need more buttons! Repeat the above procedure to add two more. Name the second button Options, the third - About. Your final layout should be similar to the one shown in the image below:


Hurray, the layout of the first scene is complete!

Connect a layer to a class


Before proceeding, you need to make some adjustments. If you create a scene using a layer created in CocosBuilder, and if this layer of the scene is a custom class, then you must tell CocosBuilder the name of this class.
For example, if you initialize a scene using the MainMenuScene file , and you want its layer to be of the class that you created, then you need to specify the name of this class in the Code Connections section .
Select the MainMenuScene.ccb file and select the CCLayer root node in the timeline.
In the Code Connections section , in the Custom class field, write the name of your MainMenuLayer class. Now, when you initialize this scene, CocosBuilder will look for a class called MainMenuLayer and use it to instantiate the scene layer.


Next, you need to publish the CocosBuilder interface file. To do this, simply select the menu item File \ Publish. So you create a new file called MainMenuScene.ccbi in the Scenes directory.
Stop messing with CocosBuilder - now is the time to try it all out in Xcode!

Time to write code!


First, make sure you have the latest version of Cocos2D 2.X (2.1-beta4 at the time of writing this tutorial).
Then run Xcode and create a new project with the iOS \ cocos2d v2.x \ cocos2d template. Enter CatJump in the Product Name field , fill in the Company Identifier field as usual , and in the Device Family field select iPhone:


Finish creating the project and save it somewhere on your disk.
Then, in the root of the project, create a new Scenes group, and drag the MainMenuScene.ccb file that you previously created there. Make sure that the “Copy items to destination group's folder (if needed)” checkbox is checked and the “Add to targets” section next to CatJump is also checked.

Now you need to add CCBReader to your project. CCBReader comes complete with sample files that you downloaded earlier from CocosBuilder. Unzip the sample files (if you have not already done so) to a folder on your hard drive. Locate the CCBReader folder in the Add to Your Project \ cocos2d-iphone folder .
Drag the entire CCBReader folder into your project. Make sure that “Create groups for any added folders” is selected and the checkbox “Copy items into destination group's folder” is checked. Do the same with the CCControlExtension folder.
Next, create a new group in your project and name it Layers . Create a new file with the iOS \ cocos2d v2.x \ CCNode template. Make it a subclass of CCLayer and name it MainMenuLayer.m .
Before writing code, open AppDelegate.m and add the following import statement (immediately after the #import statements existing in the file):

#import "CCBReader.h"

Then find the application: didFinishLaunchingWithOptions: procedure , and in it the line:
[director_ pushScene: [IntroLayer scene]];

Once you find it, replace it with this:
[director_ pushScene: [CCBReader sceneWithNodeGraphFromFile:@"MainMenuScene.ccbi"]];

And that’s all you need to do in the code to run scenes created with CocosBuilder! CCBReader class will parse a file MainMenuScene.ccbi itself will create a scene!
But before you start the program, you need to take one last step. Remember the background image that you added to your scene and the button images from the ccbResources folder in the folder of your CocosBuilder project?
These images are not in the project, but we need them to make the program work normally. Otherwise, the application will cause an error. (In fact, you can check it right now by trying to run the program ...)
Take all the files from the Resources folder of your CocosBuilder project and drag them into the Resources folder of your Xcode project. Do the same with all the files in the ccbResources folder. As before, make sure that there is a checkmark next to the item “Copy items into destination group's folder”, that the item “Create groups for any added folders” is selected and that there is a checkmark next to our CatJump project.


Now run the program. If you receive an error message during compilation of CCBReader.m, replace the line with the error with the following:
return [_bundle pathForResource:resource ofType:ext inDirectory:subpath];

Run the program, you will see the main menu with three buttons, as shown below:


Developments


Congratulations, you now have a working layout created in CocosBuilder with just one line of code! :)
But how to get an event that the user clicked on one of these buttons?
CocosBuilder is easy to handle! It allows you to specify the name of the method to be called if the user clicks on the button. You can also specify the event for which this method will be called (using a set of parameters).
Let's add this functionality to MainMenuScene. Open MainMenuScene.ccb in CocosBuilder and select the Play button. In the right pane, in the CCNode section, change the value of the Tag property to 1.
Then, in the CCControl section, fill in the Selector text field with the buttonPressed method name:which will be called. Also make sure the Target field contains the Document root value .


Do the same for the other two buttons, but with different tags - for Options - the Tag field will be 2, for About - 3.
Amazing! You have associated button presses with the selector provided in CCLayer. Save the changes, publish MainMenuScene.ccb, and copy the published file to the project's Xcode folder.

Note : You do not need to drag the file into the Xcode project as before, since the file already exists in the project. So, either delete the file from the project and then drag it back to the project, or use Finder to copy the new file from the CocosBuilderFiles folder to the folder with the files of your Xcode project.

Now open MainMenuLayer.m in Xcode and add the following import statements there:
#import "CCControlButton.h"
#import "CCBReader.h"

Alternatively, add the following #define statements with constants immediately below the #import statements. They describe the tags of those buttons that you placed on the stage:
#define PLAY_BUTTON_TAG 1
#define OPTIONS_BUTTON_TAG 2
#define ABOUT_BUTTON_TAG 3

What about the buttonPressed: method ? Add it to MainMenuLayer.m:
-(void)buttonPressed:(id)sender {
	CCControlButton *button = (CCControlButton*) sender;
	switch (button.tag) {
	case PLAY_BUTTON_TAG:
	[[CCDirector sharedDirector] replaceScene:[CCTransitionCrossFade transitionWithDuration:1.0 scene:[CCBReader sceneWithNodeGraphFromFile:@"GameScene.ccbi"]]];
	break;
	case OPTIONS_BUTTON_TAG:
	[[CCDirector sharedDirector] replaceScene:[CCTransitionFlipAngular transitionWithDuration:1.0 scene:[CCBReader sceneWithNodeGraphFromFile:@"OptionsScene.ccbi"]]];
	break;
	case ABOUT_BUTTON_TAG:
	[[CCDirector sharedDirector] replaceScene:[CCTransitionCrossFade transitionWithDuration:1.0 scene:[CCBReader sceneWithNodeGraphFromFile:@"AboutScene.ccbi"]]];
	break;
	}
}

In this method, everything should be clear: here, each button is pressed separately. For example, when the About button is clicked, the AboutScene.ccbi scene is displayed.

Launch the game. You should now have a fully functional main menu.
Amazingly, you just created your first scene and you almost wrote no code.
Of course, you noticed that the code for buttonPressed: is associated with CCBI files that you have not done yet. Therefore, if you click on any of the buttons in the menu, the program will give an error, since these scenes are not yet in place.
This is what you are going to do next - fill in the blanks!

There is nothing complicated!


As in the main menu, there will be three buttons in the difficulty selection scene, and creating this scene will be just as easy.
In the Options scene, clicking the buttons will allow the user to select Easy, Medium or Hard. There will also be a button to return to the main menu.
Open CocosBuilder and create a new scene by selecting File \ New \ New File (follow the same steps as when creating MainMenuScene), name it OptionsScene and save it in the Scenes folder.
Add three buttons to the scene and name them Easy, Medium, and Hard. Then set their tags to 1, 2, and 3, respectively.
To receive events when the user clicks on the buttons, you must specify the method that will be called. Just as you did with MainMenuScene, write difficultyButtonPressed for each of the buttons in the Selector field : select Document Root in the Target field .

Note : I wonder what this Document Root means. This means the root node in the Default Timeline tree. Soon you will set the root node (CCLayer) to a custom class - OptionsLayer. This means that the OptionsLayer class will act as the Document Root.

Your layout will look something like this:

Now the button to go back to the main menu. This time, instead of adding CCControlButton, you need to add the CCMenu menu item.
Click the CCMenu button on the toolbar.


So you create the CCMenu menu and add it to the OptionsScene layer. Now add the CCMenuItemImage menu item by clicking on the CCMenuItemImage button on the toolbar.


Specify different sprites in the Normal and Selected fields, for each its own - btn-back-0.png and btn-back-1.png . These properties can be changed in the CCMenuItemImage section of the panel on the right.


Insert the “Back” button in the upper left corner of the scene and write the backButtonPressed selector for it :. Remember to select Document root in the Target field.
That's all! The scene should look like this:


Just as you did with MainMenuScene, add a custom class for OptionsScene. Name it OptionsLayer .


As before, save the changes, publish the scene, and add the CCBI file to the Xcode project.
Go to Xcode, create a new class in the Layers group and name it OptionsLayer (make sure that it is a subclass of the CCLayer class), just like you did before.
Then add the following import and definition statements to the beginning of OptionsLayer.m:
#import "CCBReader.h"
#import "CCControlButton.h"
#define DIFFICULTY_EASY_BUTTON_TAG 1
#define DIFFICULTY_MEDIUM_BUTTON_TAG 2
#define DIFFICULTY_HARD_BUTTON_TAG 3

As well as the following methods:
-(void)backButtonPressed:(id)sender {
	[[CCDirector sharedDirector] replaceScene:[CCTransitionFlipAngular transitionWithDuration:1.0 scene:[CCBReader sceneWithNodeGraphFromFile:@"MainMenuScene.ccbi"]]];
}
-(void)difficultyButtonPressed:(id)sender {
	CCControlButton *button = (CCControlButton*) sender;
	NSString *difficultyLevel = @"Hard";
	if (button.tag == DIFFICULTY_EASY_BUTTON_TAG) {
		difficultyLevel = @"Easy";
	} else if(button.tag == DIFFICULTY_MEDIUM_BUTTON_TAG) {
		difficultyLevel = @"Medium";
	}
	NSLog(@"Difficulty is set to %@", difficultyLevel);
}

All this should be familiar to you. Procedure backButtonPressed: returns the user back to the main scene menu.
The difficultyButtonPressed procedure : in its current form does not establish the level of complexity, but only writes the fact of the user's choice to the log. Feel free to choose a high level of difficulty, because nothing changes.
Launch the game, now you have two fully functional scenes. You are halfway to the full game interface!

The turn has come ... of fire!


About scenes are needed in order to provide users with additional information about your program - how to play or use the application, who made it, version number and so on.
Your About scene will be special: it will be a burning hell! This is not only to look cool, but also to understand how to add a particle system (like a special effect) using CocosBuilder.
Switch to CocosBuilder, create a new file called AboutScene and save it in the Scenes directory.
Start your layout by clicking the CCParticleSystemQuad button on the toolbar.


So you create a fiery system of particles. Select a particle system and change the Particle texture property to cat_leap_1.png. Play around with the CCParticleSystemQuad parameter until you are happy with the result. Then move the particle system to the lower right corner of the screen, as shown below:


Now you need to add some text. Add CCLabelBMFont by clicking on the following button on the toolbar:


In the font properties, select Arial.fnt (from the Resources folder). Then add two more text elements, one below the other, also specify the same font.
Break the text as follows - Help the cat jump over all the obstacles trying to run him over - between the three text elements. There are no more nuances here.
Now, the About scene will look like this:


You are almost done with this scene! All that remains is the Back button.
Add the Back button to the upper left corner, as you did before. As a selector, write backButtonPressed:, in the Target field - Document root.
The final step is to add a custom class for this scene, as well as for the previous two scenes. The user class name is AboutLayer , as shown below:


As before, save the changes, publish the scene, and add it to the Xcode project. Then go to Xcode and create a new Cocos2D class in the Layers group. Name it AboutLayer and make sure it is a subclass of the CCLayer class.
Open AboutLayer.m and add the following import statement:
#import "CCBReader.h"

And also this method:
-(void)backButtonPressed:(id)sender {
	[[CCDirector sharedDirector] replaceScene:[CCTransitionFlipAngular transitionWithDuration:1.0 scene:[CCBReader sceneWithNodeGraphFromFile:@"MainMenuScene.ccbi"]]];
}

The method will be called when the user clicks the Back button (green arrow) and the method replaces the current scene with the MainMenu scene.
Launch the game. Check: clicking on the About button displays the AboutScene scene, and the Back button returns you to the main menu. Not bad in a few minutes of your time, huh?

In Game!


Finally, it is time to bring our star into the game - a cat who will have a hard day! All you have to do is put all the sprites you need for the game in the right places, and you will do this without picking the code. So let's get started!
Go to CocosBuilder and create a new file. Name it GameScene and save it in the Scenes folder.
Then click the CCSprite button on the toolbar to create a new sprite. Set the Frame field of this sprite to bg.png and put it in the center of the screen. Your scene should look like the following:


Now add the main character of the game - the cat! Add another sprite to the layer by clicking the CCSprite button again. In the Frame field of the sprite, select cat_stand_1.pngand the coordinates are X: 75, Y: 75.
In addition, we add two CCLabelBMFonts elements. They will show the number of cat lives, and the number of jumps made.
Click CCLabelBMFont twice and get the items enter the text Lives: and Dodges: . For these elements, become the font Arial.fnt . Place the resulting text elements in the upper left and right corners of the screen, as shown below:


Great! All is ready.
Or not all? You have placed the sprites, but you have no way to refer to them in the code. For example, how would you manipulate a cat in the logic of the game? Do not rack your brains - with CocosBuilder it is simple.
Let's start with our hero, the cat. Select the sprite of the cat and in the right panel, in the sectionCode Connections , you will see a drop-down menu below the Custom class field .
In this menu (Don’t assign value is selected there now), select the Doc root var value and in the next text field write the variable name cat . So we connected the variable "cat" with a link to this sprite. The value "Doc root var" indicates that this variable will be present in the root document, in our case, the layer class.


Now repeat the same for text elements and bind them to the livesLabel and dodgesLabel variables .
Guess what will happen next? Like previous scenes, this scene requires a link to the layer class. Link this scene to classGameLayer , as shown below:


Save the changes, publish the scene, and add the CCBI file to the project. Go to Xcode and create a new class in the Layers group, name it GameLayer and make sure that it is a subclass of CCLayer.
It is time to describe the game logic. But since this is a guide to working with CocosBuilder (rather than building the game logic), just replace GameLayer.m with this long block of code:

GameLayer.m file contents
#import "GameLayer.h"
#import "CCBReader.h"
#import "SimpleAudioEngine.h"
#define kVehicleTypeNone -1
#define kVehicleTypeRedCar 0
#define kVehicleTypeYellowCar 1
#define kVehicleTypeDog 2
#define kVehicleTypeKid 3
@interface GameLayer() {
	CCLabelBMFont *livesLabel;
	CCLabelBMFont *dodgesLabel;
	CCSprite *cat;
	CCNode *_vehicles;
	BOOL _invincible;
	BOOL _jumping;
	double _nextSpawn;
	int _lives;
	int _dodges;
	CCSpriteBatchNode *_catJumpBatchNode;
	CCAnimation *_catJumpAnimation;
}
@end
@implementation GameLayer
- (id) init {
	self = [super init];
	if (self) {
		[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"CatJumpAtlas.plist"];
		_catJumpBatchNode = [CCSpriteBatchNode batchNodeWithFile:@"CatJumpAtlas.png"];
		[self addChild:_catJumpBatchNode z:1];
		_catJumpAnimation = [CCAnimation animation];
		[_catJumpAnimation addSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"cat_leap_1.png"]];
		[_catJumpAnimation addSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"cat_leap_2.png"]];
		[_catJumpAnimation setDelayPerUnit:0.625f];
		[_catJumpAnimation retain];
		// If you want to add this to the AnimationCache instead of retaining
		//[[CCAnimationCache sharedAnimationCache] addAnimation:catJumpAnimation name:@"catJumpAnim"];
		// Dog Animation
		CCAnimation *dogAnimation = [CCAnimation animation];
		[dogAnimation addSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"dog_1.png"]];
		[dogAnimation addSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"dog_2.png"]];
		[dogAnimation addSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"dog_3.png"]];
		[dogAnimation addSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"dog_4.png"]];
		[[CCAnimationCache sharedAnimationCache] addAnimation:dogAnimation name:@"dogAnimation"];
		// Kid Animation
		CCAnimation *kidAnimation = [CCAnimation animation];
		[kidAnimation addSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"kidontrike_1.png"]];
		[kidAnimation addSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"kidontrike_2.png"]];
		[kidAnimation addSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"kidontrike_3.png"]];
		[kidAnimation addSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"kidontrike_4.png"]];
		[[CCAnimationCache sharedAnimationCache] addAnimation:kidAnimation name:@"kidAnimation"];
		self.isTouchEnabled = YES;
		[self scheduleUpdate];
		_vehicles = [CCNode node];
		[self addChild:_vehicles];
		_lives = 9;
		_dodges = 0;
		double curTime = [[NSDate date] timeIntervalSince1970];
		_nextSpawn = curTime + 4;
	}
	return self;
}
- (void) didLoadFromCCB { 
	[self setLives:_lives];
	[self setDodges:_dodges];
}
- (void) setDodges:(int) noOfDodges {
	dodgesLabel.string = [NSString stringWithFormat:@"Dodges:%d", noOfDodges];
}
- (void) setLives:(int) noOfLives {
	livesLabel.string = [NSString stringWithFormat:@"Lives:%d", noOfLives];
}
- (void)carDone:(id)sender {
	CCSprite *vehicle = (CCSprite *)sender;
	[vehicle removeFromParentAndCleanup:YES];
	_dodges++;
	[self setDodges:_dodges];
}
- (void)doneInvincible {
	_invincible = FALSE;
}
- (void)update:(ccTime)dt {
	CGSize winSize = [CCDirector sharedDirector].winSize;
	CCSprite *vehicleSprite;
	// Spawn Vehicles (new)
	double curTime = [[NSDate date] timeIntervalSince1970];
	if (curTime > _nextSpawn) {
		int randomVehicle = arc4random() % 4;
		if (randomVehicle == kVehicleTypeRedCar) {
			// Red Car
			vehicleSprite = [CCSprite spriteWithSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"car1_1.png"]];
			[vehicleSprite setUserData:[NSNumber numberWithInt:kVehicleTypeRedCar]];
			CCSprite *wheel1 = [CCSprite spriteWithSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"car1_tire.png"]];
			CCSprite *wheel2 = [CCSprite spriteWithSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"car1_tire.png"]];
			id tireRotateAction1 = [CCRotateBy actionWithDuration:1.0f angle:360.0f]; // Ray, these are backwards on purpose as a lab exercise.
			id tireRotateAction2 = [CCRotateBy actionWithDuration:1.0f angle:360.0f];
			[wheel1 runAction:[CCRepeatForever actionWithAction:tireRotateAction1]];
			[wheel2 runAction:[CCRepeatForever actionWithAction:tireRotateAction2]];
			[vehicleSprite addChild:wheel1];
			[vehicleSprite addChild:wheel2];
			[wheel1 setPosition:ccp(65,18)];
			[wheel2 setPosition:ccp(212,18)];
		} else if (randomVehicle == kVehicleTypeYellowCar) {
			// Yellow Car (Same code as Red Car except for wheel placement, re-listed for clarity. Consilidate in your own games)
			vehicleSprite = [CCSprite spriteWithSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"car2_1.png"]];
			[vehicleSprite setUserData:[NSNumber numberWithInt:kVehicleTypeYellowCar]];
			CCSprite *wheel1 = [CCSprite spriteWithSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"car2_tire.png"]];
			CCSprite *wheel2 = [CCSprite spriteWithSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"car2_tire.png"]];
			id tireRotateAction1 = [CCRotateBy actionWithDuration:1.0f angle:-360.0f];
			id tireRotateAction2 = [CCRotateBy actionWithDuration:1.0f angle:-360.0f];
			[wheel1 runAction:[CCRepeatForever actionWithAction:tireRotateAction1]];
			[wheel2 runAction:[CCRepeatForever actionWithAction:tireRotateAction2]];
			[vehicleSprite addChild:wheel1];
			[vehicleSprite addChild:wheel2];
			[wheel1 setPosition:ccp(62,15)];
			[wheel2 setPosition:ccp(195,15)];
		} else if (randomVehicle == kVehicleTypeDog) {
			// Dog
			vehicleSprite = [CCSprite spriteWithSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"dog_1.png"]];
			[vehicleSprite setUserData:[NSNumber numberWithInt:kVehicleTypeDog]];
			// In your code, check that the animationByName did not return nil (due to memory warnings)
			CCAnimation *vehicleAnimation = [[CCAnimationCache sharedAnimationCache] animationByName:@"dogAnimation"];
			vehicleAnimation.restoreOriginalFrame = NO;
			vehicleAnimation.delayPerUnit = 0.5f/ vehicleAnimation.frames.count;
			id animationAction = [CCAnimate actionWithAnimation:vehicleAnimation];
			[vehicleSprite runAction:[CCRepeatForever actionWithAction:animationAction]];
		} else {
			// Kid on Bike (Same code as Dog, re-listed for clarity. Consilidate in your own games)
			vehicleSprite = [CCSprite spriteWithSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"kidontrike_1.png"]];
			[vehicleSprite setUserData:[NSNumber numberWithInt:kVehicleTypeKid]];
			// In your code, check that the animationByName did not return nil (due to memory warnings)
			CCAnimation *vehicleAnimation = [[CCAnimationCache sharedAnimationCache] animationByName:@"kidAnimation"];
			vehicleAnimation.restoreOriginalFrame = NO;
			vehicleAnimation.delayPerUnit = 0.5f/ vehicleAnimation.frames.count;
			id animationAction = [CCAnimate actionWithAnimation:vehicleAnimation];
			[vehicleSprite runAction:[CCRepeatForever actionWithAction:animationAction]];
		}
		// Common placement and movement code for all vehicles
		vehicleSprite.position = ccp(winSize.width + vehicleSprite.contentSize.width/2, 75);
		[_catJumpBatchNode addChild:vehicleSprite];
		[vehicleSprite runAction:[CCSequence actions:
								  [CCMoveBy actionWithDuration:1.25 position:ccp(-winSize.width-vehicleSprite.contentSize.width, 0)],
								  [CCCallFuncN actionWithTarget:self selector:@selector(carDone:)],
								  nil]];
		float randomInterval = arc4random() % 3 + 1.5;
		_nextSpawn = curTime + randomInterval;
	}
	// Check for collisions
	if (!_invincible) {
		float insetAmtX = 10;
		float insetAmtY = 10;
		BOOL isCatColliding;
		CGRect catRect = CGRectInset(cat.boundingBox, insetAmtX, insetAmtY);
		CGRect vehicleRect;
		for (CCSprite *vehicle in _catJumpBatchNode.children) {
			if ([vehicle tag] == 1) {
				continue;  // No need to check if the Cat collides with itself
			}
			isCatColliding = NO;
			NSNumber *vehicleTypeNumber = (NSNumber*)[vehicle userData];
			int vehicleType = [vehicleTypeNumber intValue];
			if (vehicleType == kVehicleTypeRedCar) {
				CGPoint boundingBoxOrigin = vehicle.boundingBox.origin;
				CGRect carHood = CGRectMake(boundingBoxOrigin.x+10,boundingBoxOrigin.y , 40,80);
				insetAmtX = 50;
				insetAmtY = 10;
				vehicleRect = CGRectInset(vehicle.boundingBox,insetAmtX,insetAmtY);
				if ((CGRectIntersectsRect(catRect,carHood)) ||
					(CGRectIntersectsRect(catRect, vehicleRect))) {
					isCatColliding = YES;
					CCLOG(@"Collided with Red Car");
				}
			} else if (vehicleType == kVehicleTypeYellowCar) {
				CGPoint boundingBoxOrigin = vehicle.boundingBox.origin;
				CGRect carHood = CGRectMake(boundingBoxOrigin.x+10,boundingBoxOrigin.y , 68,65);
				insetAmtX = 68;
				insetAmtY = 10;
				vehicleRect = CGRectInset(vehicle.boundingBox,insetAmtX,insetAmtY);
				if ((CGRectIntersectsRect(catRect,carHood)) ||
					(CGRectIntersectsRect(catRect, vehicleRect))) {
					isCatColliding = YES;
					CCLOG(@"Collided with Yellow Car");
				} 
			} else {
				// Dog or Kid
				CGRect vehicleRect = CGRectInset(vehicle.boundingBox, insetAmtX, insetAmtY);
				if (CGRectIntersectsRect(catRect, vehicleRect)) {
					isCatColliding = YES;
				}
			}
			if (isCatColliding == YES) {
				// Play sound, take a hit, invincible, break out of the loop
				[[SimpleAudioEngine sharedEngine] playEffect:@"squish.wav"];			
				_invincible = TRUE;
				[cat runAction:[CCSequence actions:
								[CCBlink actionWithDuration:1.0 blinks:6],
								[CCCallFunc actionWithTarget:self selector:@selector(doneInvincible)],
								nil]];	 
				_lives--;
				[self setLives:_lives];
				if (_lives <= 0) {
					[[CCDirector sharedDirector] replaceScene:[CCTransitionJumpZoom transitionWithDuration:1.0 scene:[CCBReader sceneWithNodeGraphFromFile:@"GameOver.ccbi"]]];
				}
				break;
			}
		}
	}
}
- (void)doneJump {
	_jumping = FALSE;
}
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
	if (!_jumping) {
		_jumping = TRUE;
		[[SimpleAudioEngine sharedEngine] playEffect:@"meow.wav"];
		CCLOG(@"Making the Cat Jump");
		_catJumpAnimation.restoreOriginalFrame = YES;
		CCAnimate *jumpAnimation = [CCAnimate actionWithAnimation:_catJumpAnimation];
		CCJumpBy *jumpAction = [CCJumpBy actionWithDuration:1.25 position:ccp(0,0) height:200 jumps:1];
		CCCallFunc *doneJumpAction = [CCCallFunc actionWithTarget:self selector:@selector(doneJump)];
		CCSequence *sequenceAction = [CCSequence actions:jumpAction,doneJumpAction, nil];
		[cat runAction:[CCSpawn actions:jumpAnimation,sequenceAction, nil]];
	}
}
@end



Feel free to look into the code to get an idea of ​​what is happening with the logic of the game, but don't worry too much about it - CocosBuilder is our focus.
Notice the variables at the top of the code, immediately after the #defines statement:
CCLabelBMFont *livesLabel;
CCLabelBMFont *dodgesLabel;
CCSprite *cat;

These variables, I'm sure you remember them, correspond to the variables that you created in CocosBuilder. They are automatically initialized as a cat sprite, a text about the number of lives and the number of jumps.
Launch the game. Now, if you click the Play button in the main menu, you can play the game.
Hooray! You have created a game scene. It was much easier than dodging kids on tricycles.

End of the game


Think you did everything? Not really.
You probably noticed that when the cat loses all its lives, the game gives an error. This is because the Game Over scene that CCBReader is trying to load is missing. This may be because you have not done it yet.
This scene will have two buttons:
  • Main Menu : Returns the user to the main menu.
  • Replay : The user plays the game again.

Switch to CocosBuilder and create a new file called GameOver . Add two CCControlButtons buttons with the names above. Make sure you do not forget to put tags 1 and 2 on them. In addition, do not forget to write buttonPressed: in the Selector field and Document root in the Target field .
Finally, set the class of the root layer to GameOverLayer , save the changes and publish the file.


Switch back to Xcode and add the CCBI file to the project. Then create a new Cocos2D class in the Layers group and name it GameOverLayer , making sure that this class is a subclass of the CCLayer class.
Add the following import statements to GameOverLayer.m:
#import "CCControlButton.h"
#import "CCBReader.h"

As well as definition operators:
#define MAIN_MENU_BUTTON_TAG 1
#define PLAY_AGAIN_BUTTON_TAG 2

Add a method that handles a button click:
-(void)buttonPressed:(id)sender {
	CCControlButton *button = (CCControlButton*) sender;
	switch (button.tag) {
		case MAIN_MENU_BUTTON_TAG:
			[[CCDirector sharedDirector] replaceScene:[CCTransitionFlipY transitionWithDuration:1.0 scene:[CCBReader sceneWithNodeGraphFromFile:@"MainMenuScene.ccbi"]]];
			break;
		case PLAY_AGAIN_BUTTON_TAG:
			[[CCDirector sharedDirector] replaceScene:[CCTransitionFadeUp transitionWithDuration:1.0 scene:[CCBReader sceneWithNodeGraphFromFile:@"GameScene.ccbi"]]];
			break;
	}
}

Run the program. You now have a fully functional game.
Was it much easier than selecting sprite positions in the game code?

Troubleshooting CocosBuilder Errors


CocosBuilder is a great tool for quickly and efficiently creating scenes. However, this tool is not very good at communicating when something is wrong with the scene. In order to save your time, I put together a checklist that you need to go through in case the scene does not work properly or you receive unexpected errors.
  • Make sure you save the changes to CocosBuilder before publishing the file. It is very important. CocosBuilder does not warn you that you have unsaved changes when you start publishing. So make it a habit to always save your changes before posting the scene.
  • When you drag a CCBI file into an Xcode project, always check that the Add to target box next to your project is checked. Usually, as soon as you tick the project in the Add to targets field, it remains there. But not with CCBI files. Therefore, always check for this checkmark, especially if you get an error when loading a scene.
  • Read the messages in the debug console. If CocosBuilder cannot tell you what went wrong, then the debug console may contain a message to help you figure out what went wrong. If it says: “File not found: GameOver.ccbi”, then this means that the GameOver.ccbi file was either not added to the project, or is not part of the target assembly that you are compiling, or simply there is an error in the file name.
  • Make sure you are not sealed. When you enter text such as variable names, custom classes, or the name of event selectors, it’s very important not to make a mistake. Try copying through the clipboard.

If you use these tips, you will save yourself time, and if the problem still arises, then we hope you will pounce on it like a frisky cat on a mouse.

What's next?


Here is the entire source code for the final draft.
You are now ready to use CocosBuilder to create your own games. I hope this tutorial saves you a lot of time creating new games!