BIT-101 [2003-2017]

Cocos2d – Part 4: Menus and Transitions


Menus

OK, let’s talk menus. Because some people might have a preconceived idea of what a menu is, let’s define it in this context as a collection of visual items that can be tapped on to make a choice. This includes main menu screens of games as well as settings or options menus and even things like level choosers. Menus are very often lists of text items, but could also include icons or larger images as items.

Let’s take a simple example of a main menu. It might have various options such as “Play”, “Settings”, and “About”. If you’ve been following along, you’ll probably be getting the idea that this menu would reside in a menu screen, and that choosing one of these options would take you to a play scene, a settings scene, or an about scene. So start a new project as described in Part 1 of this series, and create four new classes: MenuScene, PlayScene, SettingsScene, and AboutScene. In each one, import the Scene.h file, and have each class extend Scene.

First let’s create the three target scenes. I grabbed three different 480×320 images to serve as different backgrounds and added them to my project. Each of these classes is almost identical, so I’m just going to show you the PlayScene and you should be able to figure out the rest.

[c]#import “PlayScene.h”
#import “Label.h”
#import “cocos2d.h”
#import “MenuScene.h”
#import “Sprite.h”

@implementation PlayScene

– (id) init
{
self = [super init];
if (self != nil) {
Sprite *bg = [Sprite spriteWithFile:@“background.png”];
bg.position = ccp(240, 160);
[self addChild:bg];

Label *label = [Label labelWithString:@“play scene” fontName:@“Arial” fontSize:20];
label.position = ccp(240, 160);
[self addChild:label];

[self schedule:@selector(onEnd:) interval:5];
}
return self;
}

– (void)onEnd:(ccTime)dt
{
[[Director sharedDirector] replaceScene:[MenuScene node]];
}

@end
[/c]

Here you can see we are creating, positioning and adding the background. No rocket science there. Then creating a label and adding that. We haven’t covered labels, but what you see there is pretty straightforward. Finally, we fake a game over by starting a schedule job that will fire after 5 seconds. This just tells the Director to replace this scene with the MainMenu scene.

The settings and about scenes are nearly identical. Just use a different background and change the label string.

Now, onto the menu scene. This also obviously extends Scene as well. Nothing else interesting is in the interface, so we’ll move onto the implementation:

[c]#import “MenuScene.h”
#import “MenuItem.h”
#import “Menu.h”
#import “PlayScene.h”
#import “SettingsScene.h”
#import “AboutScene.h”
#import “cocos2d.h”

@implementation MenuScene

– (id) init
{
self = [super init];
if (self != nil) {
MenuItem *menuItem1 = [MenuItemFont itemFromString:@“Play” target:self selector:@selector(onPlay:)];
MenuItem *menuItem2 = [MenuItemFont itemFromString:@“Settings” target:self selector:@selector(onSettings:)];
MenuItem *menuItem3 = [MenuItemFont itemFromString:@“About” target:self selector:@selector(onAbout:)];

Menu *menu = [Menu menuWithItems:menuItem1, menuItem2, menuItem3, nil];
[menu alignItemsVertically];
[self addChild:menu];
}
return self;
}

– (void)onPlay:(id)sender
{
NSLog(@“on play”);
[[Director sharedDirector] replaceScene:[PlayScene node]];
}

– (void)onSettings:(id)sender
{
NSLog(@“on settings”);
[[Director sharedDirector] replaceScene:[SettingsScene node]];
}

– (void)onAbout:(id)sender
{
NSLog(@“on about”);
[[Director sharedDirector] replaceScene:[AboutScene node]];
}

@end[/c]

The first thing we do in init is to create a few MenuItems. These will be text menu items, so these are created with the MenuItemFont’s itemFromString:target:selector method. You simply pass in the text you want to display, and the target (self) and selector you want to have called when the item is tapped.

Each selector simply tells the Director to replace the MenuScene with the newly chosen scene.

Finally, we create the menu itself with these three items, using Menu’s menuWithItems static method. This takes a nil terminated list of MenuItems. We tell it to align these vertically, and add the menu to the scene.

All that’s left is to tell the Director to run with the MenuScene. This would be done in the main app delegate’s applicationDidFinishLaunching method. I’m hoping that you have learned enough so far to not need explicit instructions on how to do this.

When you are done, you should have a nice menu like this:

menu

So that’s a start to menus. Note that there is a lot more you can do with them. Don’t like the default font? Change it with this line:

[MenuItemFont setFontName:@“Arial”];

And in addition to MenuItemFont, there is MenuItemAtlasFont, MenuItemImage, MenuItemLabel, and MenuItemToggle. As for layout, you can arrange items vertically, horizontally, with or without padding, or in columns or rows. There’s probably lots more you can do with them, allowing all kinds of customization.

Transitions

OK, now that we are moving between scene, let’s polish things up a bit and add some nice transitions. So far, we have been replacing scenes like this:

[[Director sharedDirector] replaceScene:[PlayScene node]];

Kind of jarring. Fortunately, cocos2d comes with a whole slew of cheesy transitions. 🙂 OK, they’re not all cheesy, but I advise a conservative viewpoint when choosing amongst them. That said, let’s throw caution to the wind and get all ostentatious with our transitions. Hell, this is only a tutorial.

You’ll find all the transitions listed in the Transitions.h file in the cocos2d folder. They are all used pretty much the same:

[TransitionClassName transitionWithDuration:(ccTime)t scene:(Scene *)s]

The interesting thing about calling this method is that it returns an instance of TransitionScene, which extends Scene and contains the scene you passed into it. So you can use this method directly in the call to Director’s replaceScene, or any other scene changing method. For example, in MenuScene, replace this line:

[c][[Director sharedDirector] replaceScene:[PlayScene node]];[/c]

with this:

[c][[Director sharedDirector] replaceScene:[RotoZoomTransition transitionWithDuration:1.0 scene:[PlayScene node]]];[/c]

And behold the lovely results when you hit the Play item! Who wouldn’t want their iPhone app to do that??? 😉

OK, that’s it for this installment. Make some menus and make me proud.

« Previous Post
Next Post »