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 http://esotericsoftware.com/ and 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.