Cocos2d Tips: Transitioning between game screens

Let’s learn how to create menu for a cocos2d game and how to move between a menu, the game scene, a level complete scene etc.

Eventually your game will grow and you will have to create a clear structure to keep everything organized.

20120911-203055.jpg

As you can see, as with any app, the AppDelegate is the first object called. As such, it is the entry point to your game and will call the very first scene of your game. This means the first scene should probably the main menu which welcomes the user to the game and presents him with options.

As you can see from the Cocos2d tips “Creating a Menu”, menus can be quite complex:

http://quique123.wordpress.com/2012/09/12/cocos2d-tips-creating-a-menu/ ‎

When a cocos2d game is created, a Singleton instance of the GameDirector is instantiated and charged with managing scenes. After all, your Main Menu scene is just another scene/layer called by the game director. Thus it is quite common to create another Singleton class used to tell the director which scene to call.

Let’s call it the GameManager and his sole job is to tell the director which scene to call. Before we take a look at some code, keep in mind a game may grow to have quite a few scenes and while text is more human readable, it is easier to manage variables as numbers. The main reason is that switch statements use numbers, not text.

So it is common practice to use code such as this in a Constants.h file that you import into your GameManager.m Class:

typedef enum {

kNoSceneUninitialized=0,

kFirstScene=1,

kSecondScene=2,

kThirdScene=3,

} SceneTypes;

Now you can easily use a method such as this:

-(void)runSceneWithID:(SceneTypes)sceneID {

SceneTypes oldScene = currentScene;

currentScene = sceneID;

id sceneToRun = nil;

switch (sceneID) {

case kMainMenuScene:

sceneToRun = [MainMenuScene node];

break;

case kFirstScene:

sceneToRun = [Scene1 node];

break;

case kSecondScene:

sceneToRun = [PlaneScene node];//[Escena2 node];//

break;

case kThirdScene:

sceneToRun = [Scene3 node];

break;

default:

CCLOG(@”Unknown ID, cannot switch scenes”);

return;

break;

}

if (sceneToRun == nil) {

// Revert back, since no new scene was found

currentScene = oldScene;

return;

}

}

if ([[CCDirector sharedDirector] runningScene] == nil) {

NSLog(@”runningScene is nil…its ok because we are in process of setting the new scene???”);

[[CCDirector sharedDirector] runWithScene:sceneToRun];

} else {

[[CCDirector sharedDirector] replaceScene:[CCTransitionFlipAngular transitionWithDuration:0.5f scene:sceneToRun]];

}

currentScene = sceneID;

}

GAME START

Now this simple switch can be used to change scenes.  All you have to do at the end of the AppDelegate is call GameManager’s sceneToRun method and pass it the MainMenuScene.

MAIN MENU SELECTION

At the Main Menu scene, depending on the level selected from the menu you can pass a particular scene constant to GameManager in order to determine the level scene to call.

LEVEL END

From within your game level layer, after defining if your player won or lost, you can call GameManager to run a custom EndOfLevel scene/layer.  Then from that transitional scene you can call the MainMenuScene again.

Cocos2d Tips: Connect Layers

Games have many layers.

layers

The most common example is the main action layer (where the players and enemies are) having to communicate with the HUD layer (which presents score, health and other info) to the gamer. Let’s see how we can communicate between layers.

Typically you create a Scene and then a Layer in order to add that Layer as a child to the Scene.

Let’s say our Scene.h looks like this:

#import <Foundation/Foundation.h>

#import “cocos2d.h”

@interface Scene1 : CCScene {

}

@end

And our Scene.m looks like this:

-(id)init {

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

Scene1ActionLayer * actionLayer = [[[Scene1ActionLayer alloc] init] autorelease];

[self addChild:actionLayer z:0 tag:kActionLayer];

}

return self;

}

So we are adding the main action layer, actionLayer, to our scene at z=0 with a tag kActionLayer.  Simple enough.  Now let’s say we want to create a HUD layer to contain game information.  This can range from points, to level information, to instructions or simply health or powerup information.

Im not much of a designed so I created this simple rectangle as a bottom bar for my game.

HUDbar

The idea here is that those stars will actually represent the powerups a player must collect in order to complete a level.  Thus this will actually be a silhouette and each time the player picks up a power up, the HUD gets updated to place the powerup image in that space.  So we need the actionLayer to communicate with the HUD layer in order to say “Update the BIG GUNS power up!”.

We go ahead and create the actionLayer, possibly with a method called updateHUDWithPowerup:(Powerup*)power up; where Powerup is anything as simple as a typedef or as complex as a custom NSObject.

First, we need an instance of the HUD layer inside our actionLayer to call its method.  So inside our actionLayer, we forward declare it in our action layer :

@class “HUDLayer;

and then create an ivar for its instance:

HUDLayer *hudLayerInstance;

Second, we import the class in our action layer.m:

#import “HUDLayer.h”

Third, we simply allocate the instance in our actionLayer’s init method:

hudLayerInstance = [[HUDLayer alloc] initWithActionLayer:self];

[self addChild:backLayer z:0 tag:100];

Fourth, when the time comes to update the HUDLayer from the action layer’s update method (perhaps), we call:

[hudLayerInstance someMethodDefinedInHUDLayer:withThisValue];

Fifth, don’t forget to code the HUDLayer.  In its interface, forward declare your action layer class and add the custom initializer as well as your method like so:

@class ActionLayer;

@interface HUDLayer : CCLayer {

CCLabelTTF *_scoreLabel;

}

@property (nonatomic, assign) CCLabelTTF *scoreLabel;

-(id)initWithActionLayer:(ActionLayer*)layer;

@end

Finally implement your initializer and its “someMethodDefinedInHUDLayer” in order to pass it “withThisValue”.

Voila!  Another option is using Delegates/Protocols.

 

 

In this case we are adding all children to the Scene.  In order to get them to communicate, we would need to have methods inside the Scene itself to call actions between objects.  I prefer the former method.  I leave this kind of setup for adding layers that don’t really do much, such as timers, background, eye candy etc.  They are still important layers, they just dont interact with the actionLayer much or at all.

2012 in review

The WordPress.com stats helper monkeys prepared a 2012 annual report for this blog.

Here’s an excerpt:

4,329 films were submitted to the 2012 Cannes Film Festival. This blog had 17,000 views in 2012. If each view were a film, this blog would power 4 Film Festivals

Click here to see the complete report.