website tonight analytics
magnify
Home Arjun Roychowdhury Cocos2D iphone tutorial: Die, Grossini, Die! – Part I
formats

Cocos2D iphone tutorial: Die, Grossini, Die! – Part I

Click here for Part II.

What do I have against Grossini? I don’t like the  way he dances.

Okay, if you are shocked, take it easy. Its my spotty sense of humor. Who is Grossini? Well, Grossini, is a bald headed dancing sprite that Cocos2D has made immortal. I have just started learning Cocos2D as a platform for game development. After my earlier effort of building Bricks using UIKit, I discovered Cocos2D-iphone and this is my first venture into it. Cocos2d-iphone is a port of the cocos2d engine for the, umm, iphone by Ricard Quesada.

Cocos2D is an excellent and easy to use iPhone 2D gaming engine with pre-built operations for a whole bunch of stuff. While there aren’t too may good books on Cocos2D today (there are some that will be released later this year), there are excellent online resources and tutorials on the same.

The Obligatory Video of what we will be developing

No, its not really a game. Just sit back and watch some jumping and blood-shed.

What “GrossiniDie” is intended to do

You may have already figured it out from the video. Basically, our goal is to present a user with a “Main Screen”. Once he selects “Play Game” we want to show an animated sprite (Grossini) dancing on the screen and jumping around as well. As he jumps, there are knives positioned at the top. If he hits a knife, we play a horrid scream, spill some blood and he continues to bounce. To make it is little more random, the knives  move up or down a bit after a hit. This is a “show” not a “game”. You sit back and giggle at Grossini’s fate.

Credits

As usual, I picked up concepts, code fragments and tips from various sources. They are:

What we will be learning in this tutorial

  • Basic fundamentals of how to setup a Cocos2D game
  • Sprite Animation
  • Collision Detection
  • Custom Particles
  • Adding sound (you will not hear sound in the youtube video)
  • Simple seamess game background scrolling

What you need to know (i.e. I won’t be explaining it here)

  • Basic iphone programming
  • How to use Xcode
  • You should already have cocos2D installed
  • I won’t be explaining how to create a new cocos2D game template – if you need help see this

Which version of Cocos2D?

I’ve noticed that Cocos2D changes some APIs etc as it makes new releases. This tutorial is based on cocos2d-iphone-0.99.4

Getting Started: My project Organization

This is my project file organization. I will explain how Cocos2D sees things via this. Focus on the “Classes” group.

GrossiniDieAppDelegate

First, there is GrossiniDieAppDelegate. This class is called by iphone’s main.m to get things started. The Cocos2D engine is initialized here. You don’t have to do much. Basically, all of this is auto generated if you did a File->new project->Cocos2D Application. Amongst other things, Cocos2D loads the first “scene” that defines the entry point to your game here and from there on, you are responsible for the rest of the game. More on scenes later. Basically, when you create a Cocos2D app from the template, it auto creates a “HelloWorldAppDelegate” set (.h/.m) which is the first scene that gets loaded. I renamed those files to GrossiniDie*.*, refactored HelloWorld to GrossiniDie & changed main.main to load the GrossiniDie class.

MainMenu

This is where I create my Main screen menu. When you saw the video, the first scene that loaded up after the splash screen was this.

GameScreen

This is where the game logic resides. Once you select “Play” in MainMenu, this class starts the actual game. This is also where I implement the Pause functionality (not as a new Scene as I will explain later)

CCParticleMyBlood

Okay, not really my blood :) CCParticleMyBlood is a custom particle effect. I first used ParticleDesigner. Its a great visual tool to create new effects and helps you understand what each parameters do. So anyway, I looked at the values for its “Small Explosion” effect and simply used them in my CParticleMyBlood. This effect is displayed when “Grossini” hits a knife.

How Cocos2D arranges a Game

This is by no means exhaustive. Read this for a more detailed understanding. At a high level, when Cocos2D creates a singleton called “CCDirector”. The CCDirector is sort of the “master controller” of the game (like a movie director, I guess). Then you have “Scenes”. You can create as many scenes as you want. Each scene represents a different “stage” of your game, if you want. For example, you can have a “Scene” that displays a “Menu”, another “Scene” where you actual game is played, then another scene for the next level etc. And then you use CCDirector APIs to move from one screen to another. It is really really simple. If you used iphone SDKs native APIs to navigate views, this is a piece of cake. Finally, inside each scene, you can have multiple layers and sprites.

Explanation for the source

GrossiniAppDelegate.h

I did not make any changes here. Zilch. Nada. Let’s move on.


//
//  GrosiniAppDelegate.h
//
//
//  Created by Arjun on 11/18/10.
//  Copyright Hughes Systique Corp. 2010. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface GrossiniDieAppDelegate : NSObject <UIApplicationDelegate> {
	UIWindow *window;
}

@property (nonatomic, retain) UIWindow *window;

@end

GrossiniAppDelegate.m

Okay, I just made 1-2 changes here. First here is the full file. Click to see code.

//
//  GrossiniAppDelegate.m
//
//
//  Created by Arjun on 11/18/10.
//  Copyright Hughes Systique Corp. 2010. All rights reserved.
//

#import "GrossiniDieAppDelegate.h"
#import "cocos2d.h"
#import "MainMenu.h"
#import "SimpleAudioEngine.h"

@implementation GrossiniDieAppDelegate

@synthesize window;

- (void) applicationDidFinishLaunching:(UIApplication*)application
{
	// CC_DIRECTOR_INIT()
	//
	// 1. Initializes an EAGLView with 0-bit depth format, and RGB565 render buffer
	// 2. EAGLView multiple touches: disabled
	// 3. creates a UIWindow, and assign it to the "window" var (it must already be declared)
	// 4. Parents EAGLView to the newly created window
	// 5. Creates Display Link Director
	// 5a. If it fails, it will use an NSTimer director
	// 6. It will try to run at 60 FPS
	// 7. Display FPS: NO
	// 8. Device orientation: Portrait
	// 9. Connects the director to the EAGLView
	//
	CC_DIRECTOR_INIT();

	// Obtain the shared director in order to...
	CCDirector *director = [CCDirector sharedDirector];

	// Sets landscape mode
	[director setDeviceOrientation:kCCDeviceOrientationLandscapeLeft];

	// Turn on multiple touches
	EAGLView *view = [director openGLView];
	[view setMultipleTouchEnabled:YES];

	// Default texture format for PNG/BMP/TIFF/JPEG/GIF images
	// It can be RGBA8888, RGBA4444, RGB5_A1, RGB565
	// You can change anytime.
	[CCTexture2D setDefaultAlphaPixelFormat:kTexture2DPixelFormat_RGBA8888];
	[[CCDirector sharedDirector] setDisplayFPS:NO];

	[[CCDirector sharedDirector] runWithScene: [MainMenu scene]];

	[[SimpleAudioEngine sharedEngine] preloadEffect:@"die.wav"];

}

- (void)applicationWillResignActive:(UIApplication *)application {
	[[CCDirector sharedDirector] pause];
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
	[[CCDirector sharedDirector] resume];
}

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
	[[CCDirector sharedDirector] purgeCachedData];
}

-(void) applicationDidEnterBackground:(UIApplication*)application {
	[[CCDirector sharedDirector] stopAnimation];
}

-(void) applicationWillEnterForeground:(UIApplication*)application {
	[[CCDirector sharedDirector] startAnimation];
}

- (void)applicationWillTerminate:(UIApplication *)application {
	[[CCDirector sharedDirector] end];
}

- (void)applicationSignificantTimeChange:(UIApplication *)application {
	[[CCDirector sharedDirector] setNextDeltaTimeZero:YES];
}

- (void)dealloc {
	[[CCDirector sharedDirector] release];
	[window release];
	[super dealloc];
}

@end

You will notice a lot of stuff is already pre-done for you. As I mentioned earlier, a singleton of CCDirector is created. It automatically hooks up basic stuff like pausing your game if it is interrupted etc.

Here are some changes I made towards the end in applicationDidFinishLauncing:

[[CCDirector sharedDirector] setDisplayFPS:NO];
[[CCDirector sharedDirector] runWithScene: [MainMenu scene]];
[[SimpleAudioEngine sharedEngine] preloadEffect:@"die.wav"];

If you run a cocos2D app, you will see a set of numbers on the bottom left. This is the “Frames Per Second” indicator. It is a nice way to see if you are adding too many complexities to the screen that can slow down the performance. In my case, I choose to disable that display. That’s what the “setDisplayFPS:NO” does. Next, the first thing I want to load in my game is my “Menu” scene that basically asks you to press “Play”. That’s what runWithScene does. Finally, I want to play a horrendous scream when Grossini hits a knife. I preload that sound effect with the preloadEffect line. I don’t really need to do this hear. I can directly load and play it when Grossini hits, but that results in a delay of about a second or so for the first hit, which I can easily avoid by doing a preloadEffect here, and then do a playEffect later.

SimpleAudioEngine is again a singleton, and its the “Sound Engine” class for cocos2d. Simple, isn’t it?

MainMenu.h

//
//  MainMenu.h
//  Fighter
//
//  Created by Arjun on 11/18/10.
//  Copyright 2010 Hughes Systique Corp. All rights reserved.
//

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

@interface MainMenu : CCLayer {

}
+(id) scene;

@end

MainMenu.m

Click below for full source. Also remember, this is the “Scene” that CCDirector loads first – that’s what we told it to do in the AppDelegate.m class.


//
//  MainMenu.m
//  Fighter
//
//  Created by Arjun on 11/18/10.
//  Copyright 2010 Hughes Systique Corp. All rights reserved.
//

#import "MainMenu.h"
#import "GameScreen.h"

@implementation MainMenu

+(id) scene {
	// ‘scene’ is an autorelease object.
	CCScene *scene = [CCScene node];
	// ‘layer’ is an autorelease object.
	CCLayer *layer = [MainMenu node];
	// add layer as a child to scene
	[scene addChild: layer];
	// return the scene
	return scene;

}
-(id) init {
	if( (self=[super init] ))
	{

		CCSprite *menu_background = [CCSprite spriteWithFile:@"menu background.png"];
		menu_background.anchorPoint = ccp(0, 0);
		menu_background.position = ccp(0, 0);
		[self addChild:menu_background z:0];

		[CCMenuItemFont setFontName:@"Marker Felt"];
		[CCMenuItemFont setFontSize:35];
		CCMenuItem *play_menu = [CCMenuItemFont itemFromString:@"Play" target:self selector:@selector(play:)];

		CCMenu *menu =[CCMenu menuWithItems:play_menu,nil];
		menu.anchorPoint=ccp(0,0);
		menu.position = ccp(380, 20);
		[self addChild:menu];

	}
	return self;
}

-(void) play: (id) sender {
	[[CCDirector sharedDirector] replaceScene:[CCFadeTransition transitionWithDuration:1 scene:[GameScreen node]]];
}

@end

Let’s go through some parts:

+(id) scene {
	// ‘scene’ is an autorelease object.
	CCScene *scene = [CCScene node];
	// ‘layer’ is an autorelease object.
	CCLayer *layer = [MainMenu node];
	// add layer as a child to scene
	[scene addChild: layer];
	// return the scene
	return scene;
}

Remember the line in AppDelegate.m that called “[[CCDirector sharedDirector] runWithScene: [MainMenu scene]];” ? Well, this is what it invokes. You will find this little function in almost all “Scenes”. You will find it in each of my scenes, for example. Basically, it creates a Scene object, then creates a layer object (Remember, I said a scene can have one or many layers), which it instantiates as a MainMenu object (This in turn invokes the init method of MainMenu which I will cover later). It then makes that layer object a child of the scene and returns the scene handle back to CCDirector, so it can internally remember that it now needs to control this scene as well.

-(id) init {
	if( (self=[super init] ))
	{

		CCSprite *menu_background = [CCSprite spriteWithFile:@"menu background.png"];
		menu_background.anchorPoint = ccp(0, 0);
		menu_background.position = ccp(0, 0);
		[self addChild:menu_background z:0];

And this is what is called when the scene function instantiates a MainMenu object.
Basically, a layer can have many Sprites. Sprites is just a special class with inbuilt properties that let me move, transform, animate them easily.
First thing I do, is I want a background for this layer. I load it up using a CCSprite function and add it as a child of MainMenu. Now the one thing you need to remember is cocos2d uses a different co-ordinate system from the usual pixel system. In the latter, (0,0) is the top left, with X increasing as we go right and Y increasing as we go down.
In cocos2d co-ordinate system, (0,0) is lower LEFT and X increases as we go right, but Y increases as we go UP (this is more aligned to the graph axis). So, when you need to mesh cocos2d co-ordinates with physical screen co-ordinates (Example, detecting collisions etc), you need to remember this and convert.

The other thing is that by default, the “anchor” point of a sprite is its center. In other words, when you position it, for example, you position its center. I find that confusing. I prefer it to be the corner so I know how to calculate placement. So I change the anchorPoint to be (0,0) which is lower left. Then, I position the image at 0,0 in the cocos2d coordinate system. That’s why we use “ccp” and not “CGPoint”. The rule of thumb in cocos2d programming is if you see a “cc” function that looks like a replacement of a native iphone function, use the “cc” function. Next, I add the image to the main menu. I specify Z axis as 0. I will place sprites etc on a larger Z value. The Z value is convenient to ensure that images show up in front of, or behind other images correctly. You can assign any number, but just be sure that what needs to go on top has a higher Z value.


		[CCMenuItemFont setFontName:@"Marker Felt"];
		[CCMenuItemFont setFontSize:35];
		CCMenuItem *play_menu = [CCMenuItemFont itemFromString:@"Play" target:self selector:@selector(play:)];

		CCMenu *menu =[CCMenu menuWithItems:play_menu,nil];
		menu.anchorPoint=ccp(0,0);
		menu.position = ccp(380, 20);
		[self addChild:menu];
	}
	return self;
}

Next up, I need to create a “Play” button that is clickable. The CCMenuItem function of cocos2d has many ways I can create a menu, including with images or text. In this case, I chose a text menu that displays “Play”. If you touch it, it will call the “Play” function. You will see an example of a graphical menu later (pause screen)

-(void) play: (id) sender {
	[[CCDirector sharedDirector] replaceScene:[CCFadeTransition transitionWithDuration:1 scene:[GameScreen node]]];
}

When you press play, all it does it tells CCDirector to please replace the current MainMenu scene with the GameScreen scene, which will be up next. You can do all sorts of fancy animations as well. Here we say please fade out the MainMenu screen in 1 second and put in the GameScreen node.

How cool is that?

Exploding Blood Spill

Okay, before we show the GameScene (the meat), lets quickly cover the “Blood Spill Effect”. I first tried to create my own particle effect based off CCParticleExplode. Then I discovered the excellent visual Particle Designer that has a good set of effects and shows you all the gravity, speed etc. variables. So I based my effect off its “small exposion” effect. I am currently using it in evaluation mode. When you buy it (which I bet I will very soon), so can save the effect as a plist and directly load it into your game so you don’t have to manually enter the variables. The image I used for this is a small red ball. Yup, the same ball that I used for my UIKit bricks game. Looks like a blood particle too :-)

CCParticleMyBlood.h

//
//  CCParticleMyBlood.h
//  Fighter
//
//  Created by Arjun on 11/18/10.
//  Copyright 2010 Hughes Systique Corp. All rights reserved.
//

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

@interface CCParticleMyBlood:CCQuadParticleSystem {

}

-(id) init;
-(id) initWithTotalParticles:(int)p;

@end

CCParticleMyBlood.m

//
//  CCParticleMyBlood.m
//  Fighter
//
//  Created by Arjun on 11/18/10.
//  Copyright 2010 Hughes Systique Corp. All rights reserved.
//

#import "CCParticleMyBlood.h"

@implementation CCParticleMyBlood

-(id) init
{
	return [self initWithTotalParticles:955];
}

-(id) initWithTotalParticles:(int)p
{
	if( (self=[super initWithTotalParticles:p]) ) {

		// duration
		duration = 0.01f;

		self.emitterMode = kCCParticleModeGravity;

		// Gravity Mode: gravity
		self.gravity = ccp(-118,-2013);

		// Gravity Mode: speed of particles
		self.speed = 0;
		self.speedVar = 440.7;

		// Gravity Mode: radial
		//self.radialAccel = 100;
		//self.radialAccelVar = 100;

		// Gravity Mode: tagential
		self.tangentialAccel = 0;
		self.tangentialAccelVar = 0;

		// angle
		angle = 360;
		angleVar = 360;

		// emitter position
		CGSize winSize = [[CCDirector sharedDirector] winSize];
		self.position = ccp(winSize.width/2, winSize.height/2);
		posVar = CGPointZero;

		// life of particles
		life = 0;
		lifeVar = 0.724;

		// size, in pixels
		startSize = 3;
		startSizeVar = 2.0f;
		endSize = kCCParticleStartSizeEqualToEndSize;

		// emits per second
		emissionRate = totalParticles/duration;

		// color of particles
		startColor.r = 1.0f;
		startColor.g = 0.0f;
		startColor.b = 0.0f;
		startColor.a = 1.0f;
		startColorVar.r = 0.0f;
		startColorVar.g = 0.0f;
		startColorVar.b = 0.0f;
		startColorVar.a = 0.0f;
		endColor.r = 1;
		endColor.g = 0.0f;
		endColor.b = 0.0f;
		endColor.a = 1.0f;
		endColorVar.r = 0.0f;
		endColorVar.g = 0.0f;
		endColorVar.b = 0.0f;
		endColorVar.a = 0.0f;

		self.blendAdditive = NO;
	}

	return self;
}
@end

Like I said before, I used the excellent ParticleDesigner tool to see the various settings of its “Small Explosion” effect and just used the settings here with a few mods.

Game Logic

Finally, lets get on to the game logic.
Click here for Part II

 

2 Responses

  1. [...] iphone tutorial: Die, Grossini, Die! – Part II 19 11 2010 (Click here Part I) Previously, we described the fundamentals of a Cocos2D game (or in this case, [...]

  2. EmmyNo Gravatar

    Great tutorial!! Thanks.

Leave a Reply

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

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>