Create buttons in Cocos2d by using CCControlButton

Note: this post is outdated, you should take a look to this more recent article.

In the previous posts I introduced the CCControl class (to help us to create control objects in Cocos2d) and how to use this to create a basic control like a slider.

Today I’ll continue on my run and I’ll show you how to create a button easily from a CCControl. For this we will use a class that I created for this purpose namely the CCControlButton. Unlike the CCMenuItem, the CCControlButton allows you to add a background image (which can be stretchable) and a title text. It was designed to simplify the use of buttons in Cocos2d by copying (almost) the same behavior as the UIButton.

I’m going to start by explaining you how to stretch the sprites properly by using the CCScale9Sprite, and then I’ll show you how to use the CCControlButton with examples.

Before to start, you can retrieve all the needed files on github here (You need of CCControl, CCControlButton and CCScale9Sprite).

CCScale9Sprite

The CCControlButton allows you to add a stretchable sprite as background in order to fit to the title size. To create this stretchable background, I have used (and modified) a class originaly made by Steve Oldmeadow and Jose Antonio Andújar Clavell called CCScale9Sprite.

This class allows you to define a cap insets which define the portions of the sprite that should not be stretched. For example if you have rounded corners for a button or a popup on the edges, you can specify that the corners must not be stretched. The diagram below can help you to visualize how the image is cut:

CCScale9Sprite resize process

Here is the code representing the scheme above:

CCScale9Sprite *buttonSprite = [CCScale9Sprite spriteWithFile:@"CCControlButton.png" capInsets:CGRectMake(12, 12, 56, 56)];
[buttonSprite setContentSize:CGSizeMake(299, 134)];

The cap inset describes a rectangle (in the most case the center region) which cuts the sprite into a grid of 3 * 3, which allows the class to know which portions can be stretched or not. In this example, we have defined the cap insets in such a way that the corners must not be resized. The left and right sides will resize the height only while the top and bottom sides will resize only the length, and the center will stretch the height and the length.

As you can imagine this technique is very useful when you need to dynamically resize elements like popups or buttons. Indeed, here we don’t know the size of the button’s title in advance, and this technique allows the button to fit the background dynamically under the title.

Now that you know how works the CCScale9Sprite, I’m going to show you how to create buttons with CCControlButton.

CCControlButton

The CCControlButton allows you to create buttons easily with Cocos2d without use the standard CCMenu. As it is based on CCControl, it natively supports the association of target-action pair for callbacks. The CCControlButton is compound of two “layers”:

  • the background sprite: CCScale9Sprite,
  • the title label: a CCNode<CCLabelProtocol, CCRGBAProtocol>.

Each of these elements can be modified for each button states. For example you can change the color of the label and/or the background when you pushed the button. To be more explicit, here a sample of code to create simple buttons with some random texts (this example is available here):

- (CCControlButton *)standardButtonWithTitle:(NSString *)title
{
    /** Creates and return a button with a default background and title color. */
    CCScale9Sprite *backgroundButton = [CCScale9Sprite spriteWithFile:@"CCControlButton.png"];
    CCLabelTTF *titleButton = [CCLabelTTF labelWithString:title fontName:@"Helvetica" fontSize:30];
    [titleButton setColor:ccBLACK];

    return [CCControlButton buttonWithLabel:titleButton backgroundSprite:backgroundButton];
}

- (id)init
{
    if ((self = [super init]))
    {
        CGSize screenSize = [[CCDirector sharedDirector] winSize];

        // Defines an array of title to create buttons dynamically
        NSArray *stringArray = [NSArray arrayWithObjects:@"Hello",@"Variable",@"Size",@"!", nil];

        CCNode *layer = [CCNode node];
        [self addChild:layer];

        double total_width = 0, height = 0;

        // For each title in the array
        for (NSString *title in stringArray)
        {
            // Creates a button with this string as title
            CCControlButton *button = [self standardButtonWithTitle:title];
            [button setPosition:ccp (total_width + button.contentSize.width / 2, button.contentSize.height / 2)];
            [layer addChild:button];

            // Compute the size of the layer
            height = button.contentSize.height;
            total_width += button.contentSize.width;
        }

        [layer setAnchorPoint:ccp (0.5, 0.5)];
        [layer setContentSize:CGSizeMake(total_width, height)];
        [layer setPosition:ccp(screenSize.width / 2.0f, screenSize.height / 2.0f)];
    }
    return self;
}

And here the result:

Buttons with a variable size depending on the size of their title

As you can see, the background of the buttons have fitted to the size of the titles automatically. To do so, for each buttons, we have firstly create the background using the CCScale9Sprite, then we have created a label with the title and to finish we have made a button using both. You may noticed that I have not specified the cap insets for the background. Indeed, if you don’t defined it, the CCScale9Sprite will automaticaly cuts the sprite into a grid of 3 * 3 equal parts.

Of course, the CCControlButton offer all the possibilities of CCControls (target-action pairs for events) and other options such as the possibility to custom the button for each states or to fix the background. For example if you want make the keyboard of a calculator, you may want have each button with an identical size. To do so, you must define a prefered size to the background sprite and tells the button to not adjust the background:

CCScale9Sprite *backgroundButton = [CCScale9Sprite spriteWithFile:@"CCControlButton.png"];
[backgroundButton setPreferedSize:CGSizeMake(45, 45)];  // Set the prefered size

CCLabelTTF *titleButton = [CCLabelTTF labelWithString:@"1" fontName:@"Helvetica" fontSize:30];
[titleButton setColor:ccBLACK];

// Creates a button with "1" as title
CCControlButton *button = [CCControlButton buttonWithLabel:titleButton backgroundSprite:backgroundButton];
button.adjustBackgroundImage = NO;  // Tells the button that the background image must not be adjust
                                    // It'll use the prefered size of the background image
[self addChild:button];

Here is the result with more buttons:

Buttons with a fixed size

This option is very usefull to create aesthetics menus with the same buttons size. Now you can retrieve the source and add the CCControlButton into your Cocos2d project.

What’s next

As you can see, the CCControlButton is very easy to use, but you have to write a lot of line of codes to describe each state of your buttons. So, I think that is possible to increase the productivity by adding some convenient ways to build each button. For example we could add the blocks management for the callbacks and more of convenient initializers.
It could be also possible to create a CCControlMenu ala Cocos2d’s CCMenu to simplify the creation of menus. In a nutshell there is a lot of improvements to do yet!

Don’t forget that this library is open-source (MIT licence), so you if you want add/modify/correct the code you are welcome. You can find all the files and examples here on github.

The next time I’ll present you other controls made with the CCControl class.

If you have any comments or questions about this article, don’t hesitate to post a comment!

1 Star2 Stars3 Stars4 Stars5 Stars (7 votes, average: 5.00 out of 5)
Loading...

4 comments

Time limit is exhausted. Please reload CAPTCHA.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  1. Guy · December 23, 2011

    Hey,

    How can I set absoulte width and height for a button created with CCCONTROLBUTTON?

    it seems when i set a prefered size to the background it won’t use it.. but it will adjust to the text size.

    Guy.

  2. Antol · December 23, 2011

    Hi,

    Man, use Anchor Point 🙂 It’s realy simplify your code:

    Befor correct using Anchor Point:
    topLeft->setPosition(ccp(-rescaledWidth/2 – topLeft->getContentSize().width/2 +despx, rescaledHeight/2 + topLeft->getContentSize().height*0.5f +despy) );

    After:
    topLeft->setPosition(ccp(0, size.height));

    It’s in method void CCScale9Sprite::setContentSize(const CCSize &size)

  3. Adrian · December 23, 2011

    Thanks for building this! It seems great. Unfortunately, I’ve been trying to get your control working with my app without success. It seems to be a problem with pre-compiling cocos2d as a static library so that I can work in ARC, but you noted your code was ARC-compliant, so I’m wondering if you encountered any problems like this. Basically, in CCControl.m, I’m getting an error:
    CCControlExtension/CCControl/CCControl.m:414:33: Sending ‘CCControl *const __strong *’ to parameter of type ‘void *’ changes retain/release properties of pointer

    If you have any insights, I’d love to hear them.

  4. Pingback: (Cocos2d-x)CCScale9Spriteで画像の一部を引き伸ばす « pMemo & 適当に