Cocos2D Buttons Tutorial for iOS: How To Create Buttons in Cocos2D: Simple, Radio, and Toggle

A Cocos2D buttons tutorial for iOS on how to create buttons in Cocos2D – normal push buttons, radio buttons, and toggle buttons. By Ray Wenderlich.

Leave a rating/review
Save for later


Hide contents

Cocos2D Buttons Tutorial for iOS: How To Create Buttons in Cocos2D: Simple, Radio, and Toggle

10 mins

Buttons Tutorial Screenshot

Buttons Tutorial Screenshot

When you are making a game in Cocos2D, likely one of the first things you’ll find yourself needing is buttons. This Cocos2D buttons tutorial will show you how to create buttons in Cocos2D step by step, starting with simple buttons and then covering toggle and radio buttons too. This Cocos2D buttons tutorial assumes that you’ve already gone through the tutorial on how to create a simple game with Cocos2D, or have equivalent knowledge.

When I first started trying to add a button with Cocos2D, I thought the best way to was to just create a sprite representing the button and check for when the button was tapped. Although this is definitely possible, there’s a much easier way to create buttons in Cocos2D – by using the Cocos2D menu system.

The Cocos2D menu system consists of a menu that has a number of menu items inside it. Menu items can be either text or images, and the menu system contains logic for arranging menu items, highlighting items when they are tapped, toggling items, and more. So let’s give it a shot and try to create a simple button the Cocos2D way!

Creating A Simple Button

Create a new project in XCode using the cocos2d Application template, and name your project “CCButtons.” Next you need some images of buttons to work with – you can either use your own, or download some button images I have created. Once you have the images, drag them into your resources folder and make sure “Copy items into destination group’s folder (if needed)” is checked.

Open up HelloWorldScene.h under Classes and add a member variable to the HelloWorld class, we’ll need this in a bit:

CCLabelTTF *_label;

Then before we forget go to HelloWorldScene.m and add the cleanup code to the dealloc method:

[_label release];
_label = nil;

Ok now for the good stuff. In the same file (HelloWorldScene.m), replace the init method with the following code:

-(id) init
  if( (self=[super init] )) {
    CGSize winSize = [[CCDirector sharedDirector] winSize];
    // Create a label for display purposes
    _label = [[CCLabelTTF labelWithString:@"Last button: None" 
      dimensions:CGSizeMake(320, 50) alignment:UITextAlignmentCenter 
      fontName:@"Arial" fontSize:32.0] retain];
    _label.position = ccp(winSize.width/2, 
    [self addChild:_label];
    // Standard method to create a button
    CCMenuItem *starMenuItem = [CCMenuItemImage 
      itemFromNormalImage:@"ButtonStar.png" selectedImage:@"ButtonStarSel.png" 
      target:self selector:@selector(starButtonTapped:)];
    starMenuItem.position = ccp(60, 60);
    CCMenu *starMenu = [CCMenu menuWithItems:starMenuItem, nil];
    starMenu.position = CGPointZero;
    [self addChild:starMenu];
  return self;

First we create a label for debugging purposes. This should look pretty familiar – we did this in the last tutorial. However you’ll notice we’re using a new constructor this time that allows us to specify the dimensions of the label and the alignment. This way we specify the label size to be as wide as the window, and that the text should be centered. This is a handy technique to know, especially when you want to left or right justify text.

Next is the code where we create the button. We first create a menu item of class CCMenuItemImage and specify a selected and unselected image for the button. When we create the menu item, we specify a callback function to be called when the button is tapped (we’ll write this in a second). The last step is to create a menu to contain the button (or buttons).

Note that we create the menu at CGPointZero (a shortcut for 0,0). This is actually specifying where the center of the menu is. However, we also specify that the menu item is at offset (60, 60) relative to the center of the menu – so our button’s center is at (60, 60) on the screen.

Ok, one last bit of code to add. Underneath init add the callback function that will be called when the button is tapped:

- (void)starButtonTapped:(id)sender {
    [_label setString:@"Last button: *"];

Give it a compile and run, and if all goes well you should see the following:

Simple Button Screenshot

Toggle Buttons

Another common type of button you’ll need in an iPhone game is a toggle button. This is a button that has one image on it, until you tap it and it switches to another image. This could be used to toggle visibility of a control panel to make the best use of the limited screen real estate on the iPhone.

Luckily, Cocos2D comes with a special menu item class called CCMenuItemToggle that makes this easy. Let’s give this a shot! First add two more member variables to HelloWorldScene.h:

CCMenuItem *_plusItem; 
CCMenuItem *_minusItem;

And add the following cleanup code in your dealloc method:

[_plusItem release];
_plusItem = nil;
[_minusItem release];
_minusItem = nil;

Then add the following code in your init method right after you add the startMenu to the scene:

_plusItem = [[CCMenuItemImage itemFromNormalImage:@"ButtonPlus.png" 
  selectedImage:@"ButtonPlusSel.png" target:nil selector:nil] retain];
_minusItem = [[CCMenuItemImage itemFromNormalImage:@"ButtonMinus.png" 
  selectedImage:@"ButtonMinusSel.png" target:nil selector:nil] retain];
CCMenuItemToggle *toggleItem = [CCMenuItemToggle itemWithTarget:self 
  selector:@selector(plusMinusButtonTapped:) items:_plusItem, _minusItem, nil];
CCMenu *toggleMenu = [CCMenu menuWithItems:toggleItem, nil];
toggleMenu.position = ccp(60, 120);
[self addChild:toggleMenu];

First we create two CCMenuItemImages, just like we did in our previous example. Then comes the twist – we add both of those into a CCMenuItemToggle. This class keeps toggles between the elements inside, and keeps track of which is currently visible.

Note that we set the callbacks to nil when we created the CCMenuItemImages, but set it on the CCMenuItemToggle. This is to make it clear that any selectors on the CCMenuItemImages will not be called when they are inside a CCMenuItemToggle – only the CCMenuItemToggle’s selector will be called. Luckily, we can easily tell which of the menu items is visible in the callback.

Let’s see how by writing the callback! Add the following after your init method:

- (void)plusMinusButtonTapped:(id)sender {  
  CCMenuItemToggle *toggleItem = (CCMenuItemToggle *)sender;
  if (toggleItem.selectedItem == _plusItem) {
    [_label setString:@"Visible button: +"];    
  } else if (toggleItem.selectedItem == _minusItem) {
    [_label setString:@"Visible button: -"];

So as you can see, the CCMenuItemToggle has a selectedItem property that can show us which of the sub-items is currently visible (note it means visible, not which was tapped!)

So give it a compile and run, and if all goes well you should see the following:

Toggle Button Screenshot

Radio Buttons

A third common type of button that you might need in your iPhone projects are radio buttons. I found I needed some radio buttons for a game I was working on, but didn’t see an implementation for radio buttons in the Cocos2D source, so wrote an implementation of my own. While I was writing this article I came across two other guys who wrote implementations for radio button support in Cocos2D as well – so it looks like this will find its way into the Cocos2D source soon.

But it’s not in there yet, so in the meantime feel free to use the implementation I wrote or the ones I referenced above. For the purpose of this Cocos2D buttons tutorial, let’s implement radio buttons using the implementation I wrote. First, download CCRadioMenu.h and CCRadioMenu.m and drag them to the Classes directory of your project (making sure “Copy items into destination group’s folder (if needed)” is checked). Then add the following import to the top of HelloWorldScene.m:

#import "CCRadioMenu.h"

And the following to your init method after you add the toggle menu to the scene:

CCMenuItem *menuItem1 = [CCMenuItemImage itemFromNormalImage:@"Button1.png" 
  selectedImage:@"Button1Sel.png" target:self selector:@selector(button1Tapped:)];
CCMenuItem *menuItem2 = [CCMenuItemImage itemFromNormalImage:@"Button2.png" 
  selectedImage:@"Button2Sel.png" target:self selector:@selector(button2Tapped:)];
CCMenuItem *menuItem3 = [CCMenuItemImage itemFromNormalImage:@"Button3.png" 
  selectedImage:@"Button3Sel.png" target:self selector:@selector(button3Tapped:)];
CCRadioMenu *radioMenu = 
  [CCRadioMenu menuWithItems:menuItem1, menuItem2, menuItem3, nil];
radioMenu.position = ccp(120, 180);
[radioMenu alignItemsHorizontally];
radioMenu.selectedItem = menuItem1;
[menuItem1 selected];
[self addChild:radioMenu];

We create the CCMenuItemImages like usual, but instead of adding them to a CCMenu we add them to the new CCRadioMenu class. This class makes sure only one is selected at a time. We also set the first item to be selected by default at start.

The other new thing here is we call alignItemsHorizontally on the menu to take advantage of the neat auto-layout capability in Cocos2D. Note that the items will be laid out with respect to the center of the menu. Therefore, we can no longer center the menu at position (0, 0) – we have to move the center up and to the right a bit where we want the items to display.

One last thing to add – the callback methods as usual:

- (void)button1Tapped:(id)sender {
  [_label setString:@"Last button: 1"];

- (void)button2Tapped:(id)sender {
  [_label setString:@"Last button: 2"];

- (void)button3Tapped:(id)sender {
  [_label setString:@"Last button: 3"];

Once you compile and run this you should see something like the following:

Radio Buttons Creenshot

Behind The Scenes

If you look at how the menu system is implemented, you will note that menu items are CCNodes, but a Menu is a CCLayer. According to the Cocos2D best practices, you shouldn’t create a big hierarchy of layers, and should keep the count as low as you can.

So this means you probably should combine as many menu items into a single menu layer as you can. Also since a Menu derives from CCLayer you can’t make it run actions such as MoveTo, etc. I only mention this because I tried to move a whole menu of items when I was first starting and was wondering why it didn’t work :] Update: Eric from the comments below pointed out that CCLayer derives from CCNode, so you can run actions on it if you need to. Something else must have been going on when I was playing with it earlier, thanks Eric! :]

And That’s A Wrap!

Here’s a project with all of the code from the above tutorial.

Hope this was of use, and if you have any other cool tips about Buttons in Cocos2D please let me know!