Learning Cocos2d-x Game Development
上QQ阅读APP看书,第一时间看更新

Project breakup

First, let's look at the structure of Solution Explorer:

In the Solution Explorer pane, we have the following projects:

  • Angle project: As Cocos2d-x uses the openGL ES 2.0 graphics library and Windows uses DirectX to display objects on the screen, the Angle project converts all the openGL ES code to DirectX. For more information on Angle projects, you can visit the MSOpenTech GitHub page at https://github.com/MSOpenTech/angle.
  • CocosDenshion: This is the audio library. Whenever we want to play a sound or an effect, we would make use of this project for the audio to play properly. We will be looking into it when we include music and sound effects in the game.
  • libbox2d: This is a physics framework that can be used to make complex physics-based games. It is written by Erin Catto and it is used by most of the popular 2D physics-based games such as Angry Birds and Cut the Rope, to name a few. You can learn more about Box2D at http://box2d.org.
  • libChipmunk: Similar to Box2d, Chipmunk is also a physics framework that can be used to make physics simulation in your games to make it more realistic and fun. You could either use Box2d or Chipmunk depending on your comfort level. More can be learned at https://chipmunk-physics.net.
  • libExtensions: This contains some third-party plugins and helper projects that you can use out of the box in Cocos2d-x. For example, Spine is a 2D skeletal animation toolkit that can used to make 2D animations in Cocos2d-x, and CocosStudio is used to make UI, animations, and scenes using this simple tool. You can learn more about Spine at CocosStudio at http://www.Cocos2d-x.org/wiki/CocoStudio.

These are the projects that will be included by default in all the projects that you create. The next two projects are the ones that are created depending on what name you gave to the project.

In this case, there is the wp8Game project and the wp8GameComponent project. If you look at other Windows projects such as proj.win32, proj.winrt, or proj.wp8, there will only be one project with the project name. So why are there two projects here?

The short answer is that, in order to integrate ads and in-app purchases into the game, we would need to create an XAML project. If your game doesn't have in-app purchases or ads, you can use the proj.wp8 project instead of proj.wp8-XAML.

You will see that the wp8Game project has a C# in front of it and wp8GameComponent has a ++ sign in front of it in Visual Studio's Solution Explorer. All of the game logic would be written in the component project in C++, which while running will talk to the C# layer and call the ads and in-app purchases in C# when required.

Until we start integrating the ads and in-app purchases, we will mainly be typing in the code in C++ in the component project. But make sure that the wp8Game project is set as the current project by right-clicking on the project and selecting the appropriate option.

Let's look into the classes that actually participate in starting the app and displaying the objects on the screen. We will look into the wp8Game project later, but for now let's expand the wp8GameComponent project.

There are a bunch of dependencies, other renderers, input classes, and the classes folder. In this classes folder, you will find the following three classes:

  • AppDelegate
  • HelloWorldScene
  • AppMacros

Let's look at these in detail.

AppDelegate is the class that is responsible for initiating the application and getting it ready to display the game/application on the screen of the device or on the simulator. If you open up the AppDelegate.cpp file, you will find the following functions:

  • applicationDidFinishLaunching
  • applicationDidEnterBackground
  • applicationWillEnterForeGround

Let's look at these functions in detail.

The applicationDidFinishLaunching function is called when the application is launched. In applicationDidFinishLaunching, there are two variables, CCDirector and CCEGLView. Both the classes are singleton, meaning that only one instance of each is created for this project and that instance is shared when required. Also, it can be accessed from any class at any time, provided the correct header files are used.

CCDirector is a very important class; it keeps a track of which scene is currently loaded and takes care of opening a new scene and replacing the current scene with another scene. Here, we get the shared instance of CCDirector:

CCDirector* pDirector = CCDirector::sharedDirector();

Note

We will go through scenes in a little more depth later in the chapter.

CCEGLView takes care of checking the resolution of the current device this application is running on and creates a view so that objects can be displayed on the screen. Similar to CCDirector, we get the shared instance of it:

CCEGLView* pEGLView = CCEGLView::sharedOpenGLView();

The director also needs to be aware of the view variable, so the newly created view is given to it:

pDirector->setOpenGLView(pEGLView);

Next, the director is told whether we want the frames per second to be displayed on the screen:

// turn on display FPS
pDirector->setDisplayStats(true);

The fps is always displayed at the bottom-left corner of the screen. If we wish to disable it, we can set true to false. In fact, once the game is done and you are ready to release it, make sure that you set it to false.

Next, the animation interval is set. Here, the CCDirector class is told how often the update function should be called:

// set FPS. the default value is 1.0/60 if you don't call this
pDirector->setAnimationInterval(1.0 / 60);

The animation interval is set to 1.0 / 60. So right now, it is set at 60 frames per second. So the game is updated 60 times in a second. So each frame is called approximately every 0.0167 seconds.

Now we take the HelloWorld scene and make the application run with the scene by telling the director to start the application with this scene:

// create a scene. it's an autorelease object
CCScene *pScene = HelloWorld::scene();

// run
pDirector->runWithScene(pScene);

The applicationDidEnterBackground function tells CCDirector that the application has gone into the background, so the animations and sounds of the game should be stopped. This is the function that is responsible for pausing your game when you get a call while playing a game.

The applicationWillEnterForeGround function is similar to applicationDidEnterBackground. The applicationWillEnterForeGround function will tell the director to start the animations and sounds as the application is coming to the foreground.

That is all for the AppDelegate class. Next, we will move on to the HelloWordScene class, where most of the game logic will be written. In HelloWorldScene.h, you will see that it starts with #include cocos2d.h, which is the Cocos2d header. It needs to be included in all the classes that you create if you need access to Cocos2d functions and properties.

In the interface, you will see that the name of the class is HelloWorld and it inherits from CCLayer:

class HelloWorld : public cocos2d::CCLayer

The virtual bool init() function is the first function that is called to initiate the layer. So, this is where you will be initializing the variables and the settings for the game.

In static cocos2d::CCScene* scene(), a new scene is created and the HelloWorld layer is attached to the scene and the function is returned.

The void menuCloseCallback(CCObject* pSender) statement is a callback function that is called when you press the close button on the screen. However, this doesn't work in Windows Phone. But, if you are running this project on an iOS or an Android device, this function will close the application and return to the home screen.

CREATE_FUNC(HelloWorld) is a macro that creates and initializes the HelloWorld class by calling its constructor and calling the init function. We will be creating our own custom create function when we create the enemy class later so that you can see what a create function looks like.

Let's move forward and open up the HelloWorldScene.cpp file. This file includes the HelloWorldScene.h file and uses a USING_NS_CC macro to set the namespace to Cocos2d. You could use using namespace cocos2d; but USING_NS_CC is a macro that includes CCPlatformMacros.h, which itself has a lot of predefined macros in it, so you might have to include it separately if required. But for this book, either can be used:

#include "HelloWorldScene.h"

USING_NS_CC;

Next is the definition for the scene function that returns the current scene after adding the current layer, which is the HelloWorld layer:

CCScene* HelloWorld::scene()
{
    // 'scene' is an autorelease object
    CCScene *scene = CCScene::create();

    // 'layer' is an autorelease object
    HelloWorld *layer = HelloWorld::create();

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

    // return the scene
    return scene;
}

Tip

Downloading the example code

You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

The scene and layer are autorelease instances, meaning that you don't have to delete these pointers manually and release them as they are part of a release pool and will be released automatically.

Next is the init() function, in which you call the init() function of the super class:

if ( !CCLayer::init() )
{
  return false;
}

Then there are two variables, visibleSize and origin, of type CCSize and CCPoint respectively. CCSize is a class with two floats—width and height. You can perform functions such as setting the width and height and you can also check whether two CCSizes are equal. CCPoint is a class with two floats, x and y, which are used to define a point in 2D space. You can also do additional operations such as checking the distance between two CCPoints, get the dot or cross products, and get the angle between the two points.

The visibleSize variable stores the current resolution of the screen and origin stores the origin of the current scene. Both are retrieved from the CCDirector singleton class:

CCSize visibleSize =
  CCDirector::sharedDirector()->getVisibleSize();

CCPoint origin =
  CCDirector::sharedDirector()->getVisibleOrigin();

The origin is always set at the bottom-left corner of the screen by default in landscape and top-left corner in portrait with the right being the positive x direction and up being the positive y direction. This is valid whether you are in landscape mode or portrait mode irrespective of what device you are running or building the game on.

After getting the screen resolution and the origin of the current layer, we can start placing our object onto the layer.

First, the close button is created that will call the menuCloseCallBack function when clicked, causing the application to shut down. For this, an instance of CCMenuItemImage is created, called pCloseItem. It takes four parameters:

  • The image that is shown when the button is not clicked
  • Which image should replace the original once the button is clicked
  • The target class, which in this case is the current class
  • What function should be called when the button is clicked, so in this case, we call the menuCloseCallBack function

Refer to the following code snippet:

CCMenuItemImage *pCloseItem = CCMenuItemImage::
create("CloseNormal.png",
       "CloseSelected.png",
       this,
       menu_selector(HelloWorld::menuCloseCallback));

Next we set the position of the menu item image and place it at the bottom-right corner of the screen. This is done by taking the screen's width, subtracting half of the button's width, and then placing it at half of the button's height above the bottom of the screen. Both the button's height and width are divided by two as the anchor points for the image are at the center of the image:

pCloseItem->setPosition(ccp(
origin.x + visibleSize.width - pCloseItem->getContentSize().width/2 ,
origin.y + pCloseItem->getContentSize().height/2));

Next, for the menu button to be displayed on the screen, the menu button image needs to be added to CCMenu. So, we create an instance of the CCMenu class and add pCloseItem into it. We have to include NULL at the end to tell CCMenu that there are no more items to be added. The position is set to the bottom-left corner by setting the position to CCPointZero. Finally, it is added to this layer's display list with a Z value of 1:

CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
pMenu->setPosition(CCPointZero);
this->addChild(pMenu, 1);

To display the "Hello World" text on the screen, CCLabeITTF is used. A new instance of it is created, called pLabel, and it takes three default values, which are:

  • What text you want to display; this should be within double quotes
  • The name of the font; this should be in double quotes
  • The size of the font

Refer to the following code:

CCLabelTTF* pLabel = CCLabelTTF::create("Hello World", "Arial", 24);

Then the position is set by setting the x position in the middle of the screen and the y position at the height of the screen and subtracting the height of the content size's text from it. Refer to the following code for more clarity:

pLabel->setPosition(ccp(
origin.x + visibleSize.width/2,
origin.y + visibleSize.height - pLabel->getContentSize().height));

Then the label is added to the display list using the addchild function and keeping the z depth 1:

this->addChild(pLabel, 1);

And finally, to display the background image, a CCSprite variable is created called hero and it is given the name and extension of the image to be displayed, in quotes:

CCSprite* hero = CCSprite::create("HelloWorld.png");

Next, its position is set at the center of the screen:

hero->setPosition(ccp(
visibleSize.width/2 + origin.x,
visibleSize.height/2 + origin.y));

Finally, it is added to the display list with z depth as 0:

this->addChild(hero, 0);

The z depth is kept at zero so that it is behind all the objects that would be created.

The AppMacros.h file is used for resource management to handle different screens. We will go in detail later in the book when we make the game compatible with different screen resolutions.