Thursday, November 6, 2014

Creating a basic main menu for our game

When you create a new project you get a couple files named HelloWorldScene.cpp and HelloWorldScene.h.

Rename them and refactor them to look like this:

MainMenuScene.h:


#ifndef __MAINMENU_SCENE_H__
#define __MAINMENU_SCENE_H__

#include "cocos2d.h"

class MainMenu : public cocos2d::Layer
{
public:
    // there's no 'id' in cpp, so we recommend returning the class instance pointer
    static cocos2d::Scene* createScene();

    // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
    virtual bool init();
    
    // implement the "static create()" method manually
    CREATE_FUNC(MainMenu);

 void goToGameScene(Ref *pSender);
};

#endif // __MAINMENU_SCENE_H__


MainMenuScene.cpp:


#include "MainMenuScene.h"

USING_NS_CC;

Scene* MainMenu::createScene()
{
    // 'scene' is an autorelease object
    auto scene = Scene::create();
    
    // 'layer' is an autorelease object
    auto layer = MainMenu::create();

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}

// on "init" you need to initialize your instance
bool MainMenu::init()
{
    if ( !Layer::init() )
    {
        return false;
    }
    
    Size visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();
 auto *title = Label::createWithBMFont("myfont.fnt", "My Awesome Title", TextHAlignment::CENTER);
 auto menuTitle = MenuItemLabel::create(title);
 auto playItem = MenuItemImage::create("play.png", "play.png");
 auto menu = Menu::create(menuTitle, playItem, NULL);
 menu->alignItemsVerticallyWithPadding(visibleSize.height / 4);
 this->addChild(menu);

 auto background = Sprite::create("mainmenu-background.png");
 background->setPosition(Point(visibleSize.width/2, visibleSize.height/2));
 
 CCLOG("Characters: %f", background->getBoundingBox().size.width);
 CCLOG("Characters: %f", this->getBoundingBox().size.width);
 this->addChild(background, -1);
    
    return true;
}

What i did is pretty simple, i just created two menu items and added them to a menu. After that i loaded a background and positioned it in my scene.

The first menu item is created with Label::createWithBMFont, which takes a .fnt file and uses it to draw some text.
I created my files with BitMap Font Generator. All you need to do is tell it which font to use (you can download a ttf font from internet and load it too). Select the chars you want to load (that bar with checkboxes at the right side).
To make it work with cocos2dx you need it to generate only one page and to output a .png as texture. You can set both of those in export options (you need to play around with output sizes to find one that fits your desired chars and font size).
Once you are done with that, go to "Save bitmap as..." and place into a valid path.

The other menu item was easier...just load a sprite.

Once i have my items i create a menu with a padding of 1/4 of the height. If you have more items you may need to make this value lower.

When we are in the scene, we can reference it with "this", which i do to add the menu as a child.

Now i wanted to add a background, so i loaded a sprite. As the sprites have an anchor point at the middle of them and by default they are put at 0,0 in the parent, you need to move it to the center of the screen with setPosition(Point(visibleSize.width/2, visibleSize.height/2)). If you use visibleSize you can position the childs based on % instead of px. If you want to use px, make sure you use your designSizeResolution, as everything is based on it.

In this case my background was 480x320, the same size as my design resolution, so i don't need to resize it to fit anything that fits my "low-res" setting.

With that you should have a basic scene with a menu that contains a title and a play button. You even have a background now.

If you want to link your scene to another one, you can add something like to play item:
auto playItem = MenuItemImage::create("play.png", "play.png", CC_CALLBACK_1(MainMenu::goToGameScene, this));
and later in MainMenu.cpp:

void MainMenu::goToGameScene(Ref *pSender)
{
 auto scene = GameActionScene::createScene();
 
 Director::getInstance()->replaceScene(scene);
}
Don't forget to create another scene with the class GameActionScene (you can use HelloWorldScene as a template again).

No comments:

Post a Comment