Saturday, January 17, 2015

[Tutorial] Cocos2d-x: Menu, from basic to advanced

Now, let's start. Create a new Project named Menu as follow, using cmd 


>cocos new menu -p com.vn.menu -l cpp -d f:android/project

After new Project is created, you should run this command

>cocos compile -s f:android/project/menu -p win32


This is the first compile, purpose is linking to libraries in Engine. The first time to compile is so long. The next compile will be much faster because we only change some in Class and Resource.

Step 1) Copy code and run
You open Classes folder as following path E:/android/project/menu/Classes with 4 familiar files. But here we won't use class HelloWorldScene but replace by 2 other classes: MenuLayer and SceneManger.

You delete 2 files HelloWorldScene.cpp and HelloWorldScene.h, download source files Here and copy 4 files in zip file into Classes folder. And then you open file AppDelegate.cpp, in the second line #include you replace HelloWorldScene.h by  SceneManager.h, 
Delete the line auto scene = HelloWorld::createScene();
and director->runWithScene(scene); đi nhé. 
Add the following command SceneManager::goMenu(); into under the two above lines

Done, before compiling and running you open file Menu.vcxproj as following path E:/android/project/menu/proj.win32/ and find "HelloWorldScene.cpp" You will see 4 files here when compiled (HelloWorldScene.h, HelloWorldScene.cpp, AppDelegate.cpp, AppDelegate.h )

Because you deleted files HelloWorldScene.h and HelloWorldScene.cpp so here you delete too. And add 4 files SceneManager.h, SceneManager.cpp, MenuLayer.h , MenuLayer.cpp into Menu.vcxproj for compiler to process these 4 files when we compile again to run, as follow:


Try running

>cocos run -s f:.android/project/menu -p win32

And sorry! A lot of errors. Because source code is not suitable to current Engine we use, so we must edit a bit. 

Step 2) Study a bit source file

You can see many errors, and some of them are difficult to know. After a long time, when you have much experience, sure you can fix them.

On the top, there are 8 errors: Identifier 'Object' .....

Open 2 Header files SceneManager.h and MenuLayer.h , Add the following line USING_NS_CC; into below the lines #include, in both 2 files. And now compile, and build OK, But when running file .exe in E:/android/project/menu/bin, it appears "stop working" error.

When building with no error, it means code is now followed standard of Engine. But when running, it happens "Stop working", maybe due to 2 following errors: not compatible with system ( build on 32bit OS and run on 64bit OS ) and the second reason is lacking of Resource ( image files, sound files, font files, ...).

In this case we intend not copy 1 font file "Marker Felt.ttf" into Resource folder so building ok but running generates error. So you should copy file "Marker Felt.ttf" from E:/android/project/menu/Resource/font to Resource folder outside ( the same level with images of HelloWorld)


Compile again


>cocos run -s f:.android/project/menu -p win32

OK now


Step 3) Study Code

You open 2 header files: SceneManager.h and MenuLayer.h,  they contain the declaration of some functions or attributes of a class. 

+ Open file SceneManager.cpp, here there are 3 functions:

void SceneManager::goMenu(), this function creates a layer ( this is aslo called class but not similar to Class. Class is for object with attributes and functions, but layer is similar to a surface for placing others on it). And then this function calls the void function SceneManager::go(Layer* layer)

void SceneManager::go(Layer* layer) performs two tasks, transfer layer that is created above for other function Scene* SceneManager::wrap(Layer *layer) to process this layer, the processing by Wrap function will return a Scene. After that checking whether any scene is running or not, if any, replace by Scene that has new layer just created. If not, Scene that is running will run with Scene that new layer just created.

Scene* SceneManager::wrap(Layer *layer) perform the task getting parameters that layer passes, place on a new Scene, and return a value of a Scene.

+Open file MenuLayer.cpp, there are also 3 functions:

* bool MenuLayer::init(), function init always returns bool

TTFConfig config_font96("Marker Felt.ttf", 96);

TTFConfig config_font52("Marker Felt.ttf", 52);

//fix font "Marker Felt.ttf" into 2 size 96, and 52 (pixel)

Label *titleLeft = Label::createWithTTF(config_font96, "Menu ");

//Create a Label titleLeft with text "Menu" using font config_font96
    
MenuItemFont *startNew = MenuItemFont::create("New Game", CC_CALLBACK_1(MenuLayer::onNewGame, this));

//Create variable menu item startNew with text "New Game", when pressing on this menu item will call the function onNewGame() of the MenuLayer class, the below command is similar to create menu item "Credits"

Menu *menu = Menu::create(startNew, credits, NULL);
//Create a variable menu that contains 2 child menu item  created above startNew and credits

the below block is set position on the screen by command setPostion(); and place objects into layer by this->addChild();

menu->alignItemsVerticallyWithPadding(80.0f); // valign objects of variable menu with distance 80 (pixel??)

-2 below functions onNewGame() and onCredits() perform simple task to call function to create a new Scene when pressing 2 above menu

In conclusion, in this lesson, we know how to:

+Create a  label with font by command:
TTFConfig config_font96("Marker Felt.ttf", 96); 
Label *titleLeft = Label::createWithTTF(config_font96, "Menu ");

+Create an object menu item that can be pressed 
MenuItemFont *startNew = MenuItemFont::create("New Game", CC_CALLBACK_1(MenuLayer::onNewGame, this));

Menu *menu = Menu::create(startNew, credits, NULL);

(Continue...)

Download source file  HERE, extract and copy overwrite into folder Classes of project menu.

Then, you edit file Menu.vcxproj (E:/android/project/menu/proj.win32) as follow for compiling without error


Compile and run

>cocos run -s f:/android/project/menu -p win32

What changes can you see? effect with changing Scene, effect with moving text, and when Clicking 2 menu it will change into another Scene. OK. Now we will go to details of code to see how to do so.

Details of Code

File SceneManager.h, and MenuLayer.h don't have any changes. In this part we see that there are two new classes CreditLayer and PlayLayer to manage 2 operations when clicking 2 menus. You open 2 files CreditLayer.h, and PlayLayer.h

Beside constructor, destructor, init, back function ( for pressing Back button in this Scene ). These 2 objects has only task to create 2 Layers and then attach to some Scene. 

A > Then open file CreditLayer.cpp, view function init() // This function creates an empty layer to attach objects. In this function init () has a code block that notices

auto back = MenuItemFont::create("Back", CC_CALLBACK_1(CreditLayer::back,this)); (1)
auto menu = Menu::create(back, NULL); (2)
menu->setPosition(visibleSize.width/2, visibleSize.height/2);
this->addChild(menu);

(1) This is a familiar command, that create a menu item named back, when pressing this menu item will call function CreditLayer::back() below.
(2) Also a familiar command that creates a Menu containing menu item back that created above.
The below code is to set position for above Menu in the center of the screen, then attach this menu into Layer that is created by init() function

B > Then open file PlayLayer.cpp, we can see that code is completely similar to file CreditLayer.cpp, that creates a back button and then attach to this Layer.

C > Next, we study file MenuLayer.cpp, this file has code similar to previous part, but it add some code to create movement effect for Label. In the init() function, we can see some familiar commands to create Label with Text with defined font style and size, and set Layer at some position. But there is a strange code block as follow:

titleLeft->setPosition(titleLeftPosBegin);
Action *titleLeftAction = Sequence::create(
                            DelayTime::create(delayTime),
                            EaseBackOut::create(MoveTo::create(1.0, titleLeftPosEnd)),
                            NULL);

titleLeft->runAction(titleLeftAction); // titleLeft is a Label
this->addChild(titleLeft);

This code block means: to create an action named titleLeftAction = Sequence::create(). What is clearly this action? View in function Sequene::create(), this function has 3 params passed
DelayTime::create(delayTime) // is the delayed time
EaseBackOut::create(MoveTo::create(1.0, titleLeftPosEnd)) // MoveTo::create(1.0, titleLeftPosEnd) is the function to create an action moving from the beginning point titleLeftPosBegin (calculated in above code block - in source) to the end point titleLeftPosEnd ( also calculated in source), EaseBackOut is a class to create an effect 
NULL : the third param you can study deep here http://www.cocos2d-x.org/reference/native-cpp/V3.0rc0/index.html

The command titleLeft->runAction(titleLeftAction); is to perform the moving action above by calling the function of the object titleLeft ( this is a Label ).

this->addChild(titleLeft); // Attach Label to Layer created by init(); 

The below code block is similar, to create a movement for another Label.

And now, here is the code piece difficult to understand

   for (Node *each : menu->getChildren())
    {
each->setScale(0.0f, 0.0f);
Action *action = Sequence::create(DelayTime::create(delayTime),
                                          ScaleTo::create(0.5f, 1.0f),
                                          NULL);
delayTime += 0.2f;
each->runAction(action);
     }

This is the for loop to navigate item of Menu that is Credits button and New Game button ( 2 buttons are created above in Source, MenuLayer.cpp)

for (Node *each : menu->getChildren()) is rather similar to the loop for (i=0; i<n; i++) basic in C++, but it is exactly a loop to navigate the units of some set.

In loop

each->setScale(0.0f, 0.0f); is a menu button Credits , New Game return ratio 0, disappears, and then, this code block:

Action *action = Sequence::create(DelayTime::create(delayTime),
                                          ScaleTo::create(0.5f, 1.0f),
                                          NULL);
is to create an action to zoom gradually this button up to a defined ratio ScaleTo::create(0.5f, 1.0f),
and then perform the action each->runAction(action);  And the result is that button zoom gradually.

D > We continue studying file SceneManger.cpp, this file is to manage how to create Scenes and how to run, and how to transfer from Scene to scene with the transformed effect ( i.e fade, reverse, rotate,...)

You can see that these effects are defined by corresponding classes in Cocos2dx V3 ( i.e TransitionFlipY, TransitionFade, TransitionZoomFlipX  )

- This lesson is paused here...


1 comments:

Choose an Android item