šŸ“œ ā¬†ļø ā¬‡ļø

Cocos2d-x - simple game development

1. Introduction


This article will discuss the development of a prototype game for Android / Linux using Cocos2d-x . Cocos2d-x is a cross-platform framework for creating two-dimensional games and other graphical applications. It is based on cocos2d-iphone , but instead of Objective-C Cocos2d-x uses C ++. Applications can be run on platforms: iOS, Android, Windows Phone, OS X, Windows, Linux.
This article is about developing an application for Android / Linux, the development platform is Ubuntu.
Unfortunately, Cocos IDE exists only under Window and Mac, and under the Linux version is not expected, but since I love Ubuntu very much and this is the platform I work with every day, I use to develop Clion .
Some parts of this article are translations of the relevant parts of the documentation ( http://www.cocos2d-x.org/wiki ).
The article is aimed at those who begin their acquaintance with Cocos2d-x. In it, I will talk about how to create the simplest application with sprites, scenes and how to work with the accelerometer. This may be a start in order to go further in the future, delving into the Cocos2d-x API.

2. Requirements


We define the necessary set of tools that we need.
Ubuntu 14.04 - development platform
Cocos2d-x v3.8.1 - https://cocos2d-x.org/download
CMake 2.8+
JDK 1.6+
Android SDK
Android NDK r9d +
Apache Ant - to build Android-build
Python 2.7.5
Clion 1.1 - www.jetbrains.com/clion

3. Cocos2d-x


Cocos2d-x appeared in 2010, is an open source project, distributed under the MIT license . Cocos2d-x allows you to write in languages ​​such as C ++, Lua and Javascript. Cocos2d-x is fast, simple and has great features. Currently, many games written using this framework are in the top of the AppStore and Google Play.
Big guys like Zynga , Wooga , Glu , Big Fish Games , Konami use Cocos2d-x to develop games.
')
Here I must make a small digression. The fact is that Cocos2d-x allows you to use C ++ for writing code, and all of this will be built for Android and Linux. If you use Cocos2d-JS, then you can write to Javascript. Then in the case of a build for Linux / Ubuntu, the code will be translated into C ++ and then compiled. This entails many different problems (complicates work with third-party libraries, for example). In the case of the web, java-script will be executed (by the way, the build time in this case is zero, which is not bad).
If you use Cocos2d-x, then under the web it does not work, but under Linux and Android the code is compiled directly. For Android, of course, Android NDK is used.


Key features:



References:
http://www.cocos2d-x.org/wiki/Cocos2d-x
http://www.cocos2d-x.org/wiki/About_Cocos2d-x

4. Install and run the application


This part of the article shows how to create and run the first application.

First, we need to download and unpack Cocos2d-x . Or you can use the latest version from the repository:

git clone https://github.com/cocos2d/cocos2d-x.git 

After everything has been successfully downloaded, you need, you need to install all the dependencies. To do this, you can run the script *:

 ~/work/cocos/cocos2d-x-3.8.1/build/install-deps-linux.sh 

* Hereinafter, it is assumed that cocos2d-x-3.8.1 is unpacked into the ~ / work / cocos / cocos2d-x-3.8.1 directory.

Or install them manually:
list
libx11-dev
libxmu-dev
libglu1-mesa-dev
libgl2ps-dev
libxi-dev
g + ± 4.9
libzip-dev
libpng12-dev
libcurl4-gnutls-dev
libfontconfig1-dev
libsqlite3-dev
libglew-dev
libssl-dev
glfw3


To install glfw3, you need to run another script.

 ~/work/cocos/cocos2d-x-3.8.1$ tools/travis-scripts/install_glfw.sh 


After that, run the installation:

 ~/work/cocos/cocos2d-x-3.8.1$ ./setup.py 


Run cmake to create a makefile:

 cd ~/work/cocos/cocos2d-x-3.8.1/build mkdir linux-build cd linux-build cmake ../.. 


Now it remains to run the test application:

 make cd bin/cpp-tests/ ./cpp-tests 


Everything. If everything went well, you should see a test application, something like a demo version. If everything worked out, then you can go further. We need to create a project.
To create an application, run:

 cocos new MyGame -p com.your_company.mygame -l cpp -d NEW_PROJECTS_DIR 

where MyGame is the name, cpp is the language. You can specify js or lua. But we specify cpp.
Now the project has been created, and we will continue to work with it. A blank project contains a label and a picture. You can immediately look at it:

 cocos run -s ~/work/cocos/MyCompany/MyGame/ -p android 

or

 cd ~/work/cocos/MyCompany/MyGame cocos run -p linux 


Here, in fact, you can begin to work.

5. Clion


As I already wrote, Cocos IDE is not for Ubuntu, but we don’t want to write code in notepad? Fortunately, there is a Clion from Jetbrains.

image


Clion supports cmake, which means that simply importing the MyGame project is enough, and you can write code. And not just write, but also debug it! True, it all runs under Linux. But, I think that is enough for the beginning. After debugging, the Android application can always be built via the console.

Learn more about Clion: http://habrahabr.ru/company/JetBrains/blog/255723/

6. Basics


So, we downloaded Cocos2d-x, installed all the tools, imported the project into Clion, started it and ... and now it's time to figure out what's what. Let's start.
Cocos2d-x is a cross-platform game engine. But what is a game engine? The game engine provides the overall functionality that all games should have. It includes components that together allow for faster development. For example renderer (I do not translate some of the terms in the article, since they are generally accepted. I will not use the word "Activity" either), graphics, collision detection mechanism, physics, sound, animation. Cocos2d-x provides a simple API for developing cross-platform applications (or rather, allows you to build an application for different platforms).
Cocos2d-x provides such objects as Scene, Transition, Sprite, Menu, Sprite3D, Audio and others.

Main components

It may not seem so at the beginning, but actually getting started with Cocos2d-x is very simple. The core of Cocos2d-x is Scene, Node, Sprite and Action. Let's see what them them what.

Most games look something like this:



Here are all these components:



Director

Director in Cocos2d-x is like a director on the set. He controls all the objects and tells them what they should do. Director manages scene changes and transition effects, he is a singleton and is accessible from everywhere (although the movie is probably not the case).

Scene

Your game will most likely have a menu, several levels, and a few more screens (ā€œYou lost!ā€). Each such screen is a scene (Scene). Again, like in the movies. Each movie is divided into scenes - separate parts of one story. The scene is rendered by the Renderer object. Renderer is responsible for rendering sprites and other objects of the scene. For a better understanding of this process, let's talk about Scene Graph.

Scene graph

Scene Graph is a data structure that is used in Scene. Scene Graph contains Nodes. By the way, Scene Graph is called Scene Graph, but in reality it is a tree.



This already looks a bit complicated. You have to ask, what the hell do I need to know about how Scene works inside, if I just need a moving man? This is important for understanding how the Scene is drawn. When adding sprites and animations to your games, you need to be sure that you get the result you want.
Cocos2d-x performs a symmetric tree traversal (in which the left subtree is visited first, then the node, then the right subtree). This means that the right-hand part of the tree will be rendered last, and this means that it will be visible ā€œfrom aboveā€ (that is, visually the rest will be under it).



Illustrating this is very easy, let's just take a look at this scene:



Which is simplified (some of the objects are not sheets, but branches) can be represented as a tree:



An attribute associated with an order is a z-order. The left side of the tree has a negative z-order, while the right is positive. You can keep this in mind to avoid mistakes. Plus, you can add items in any order with the specified z-order, then the items will be sorted automatically.

You can consider Scene as a collection of objects (Node). We split the scene shown above to view the scene graph:



The scene on the left is the nodes that are put together (Node) with different z-order, which determine the order in which they are drawn.

You can add an element to the scene by calling the API:

 //    z-order āˆ’2, //       scene->addChild(title_node, āˆ’2); //    z-order ,     — 0 scene->addChild(label_node); //    z-order 1, //       scene->addChild(sprite_node, 1); 


Sprites

All games use sprites. These are the things that move around the screen. You can manage them. The protagonist of the game, most likely, is a sprite. It is important to note: not every graphic element of the game is a sprite. If the item does not move around the screen, then this is just a Node.
Take another look at the scene from the game:



Sprites are key elements of the game. Creating a sprite is very easy:

 //   auto mySprite = Sprite::create("mysprite.png"); //     mySprite->setPosition(Vec2(500, 0)); //   mySprite->setRotation(40); mySprite->setScale(2.0); //  addChild(mySprite); //    . 


Actions

Creating a scene with adding sprites to the screen is only part of the task. After all, we still need to make it all move. For this and there are actions (Actions). Movement, turns, rotation are all actions. The actions are very similar to the ValueAnimator in the Android API.

 auto mySprite = Sprite::create("Blue_Front1.png«); //   50     10 ,   : auto moveBy = MoveBy::create(2, Vec2(50,10)); mySprite->runAction(moveBy); //    : auto moveTo = MoveTo::create(2, Vec2(50,10)); mySprite->runAction(moveTo); 


Coordinate system

It should be noted that Cocos2d uses Cartesian coordinate system. That is, the point (0, 0) is at the bottom left. This distinguishes Cocos2d, say, from the same Android API.

7. The idea of ​​the game


Next, we will create a prototype of the game to illustrate working with Cocos2d. The idea of ​​the game is very simple: objects randomly move around the screen, say, emoticons (and why not?), And there is someone who should eat them. And from the sad smiles on the contrary, try to hide. Moreover, the management eater occurs due to the deviation of the phone in different directions. Thus, we use sprites, actions, scene changes, work with the accelerometer.
It is clear that the idea is very simple and boring, but we do not set ourselves the task of making a million (but only for now, right?), And we need to figure out what is happening in Cocos2d, and this idea is quite appropriate. Well, let's start!

8. Adding sprites


We take as a basis the application MyGame, which we created at the beginning of the article. We can use smiles that you can easily find on the Internet, or you can replace them with something else. Any balls.
All resources must be put in the Resources directory.

Add the following code to the init () method:

 for (int i = 0; i < SMILES_COUNT; i++) { std::string result = «emoji-» + itos(i); Sprite *sprite = Sprite::create(result); if (sprite != NULL) { this->addChild(sprite); listSprites.push_front(sprite); } } 


listSprites is a list of all emoticons, it is useful to us to add movement around the screen. Let's make one more thing so that they rotate a little, in the process of movement:

 Point *sizeStart = randomEndPoint(); //   Point *sizeStop = randomEndPoint(); //   auto rotateAction = RotateTo::create(2, 90); //  90    . auto moveAction = MoveTo::create(2, *sizeStop); sprite->setPosition(*sizeStart); auto mySpawn = Spawn::createWithTwoActions(rotateAction, moveAction); auto seq = Sequence::create(mySpawn, CallFunc::create(callback), nullptr); sprite->runAction(seq); 

Here we create Spawn and Sequence to execute two actions at the same time, and plus to this, in Sequence we pass a callback - a link to the function that will be called when the action is executed. This will allow us to restart the action every time so that the sprites move endlessly. We need to create such an action for each sprite.
The randomEndPoint method returns a point on the screen border, selected at random.
Now we have a lot of moving sprites:



We also need to add a devourer, but this is done in a similar way; we will not dwell on this.

9. Resolution of collisions


Now we need to write some code to resolve the collisions. That is, to find the moment when small smiles will touch the devourer.
To do this, override the onUpdate method:

 void HelloWorld::update(float dt) { ... } 


To call this method when refreshing the screen, call scheduleUpdate () :

 void HelloWorld::init(float dt) { this->scheduleUpdate(); ... } 


Now each time the screen is updated (and the sprites' positions change, respectively), the update method will be called. For simplicity, you can write something like this:

 void HelloWorld::init(float dt) { if(spriteSmile->getPosition().distance(eaterSprite->getPosition()) < spriteSmile->getBoundingBox().size.width/2 + eaterSprite->getBoundingBox().size.width/2){} } 


When a conflict is found, you can count the points and restart the Action:

 void HelloWorld::init(float dt) { if(spriteSmile->getPosition().distance(eaterSprite->getPosition()) < spriteSmile->getBoundingBox().size.width/2 + eaterSprite->getBoundingBox().size.width/2){ score—; spriteSmile->stopAllActions(); spriteSmile->setPosition(0, 0); runActionForSmile(spriteSmile); } } 


10. Accelerometer


Working with an accelerometer is as easy as resolving collisions, even easier.
To begin with, we will subscribe for the necessary event:

 void HelloWorld::init(float dt) { ... this->setAccelerometerEnabled(true); ... } 


To get accelerometer values, override the onAcceleration method:

 void HelloWorld::init(float dt) { void GameScene::onAcceleration(cocos2d::Acceleration *acc, cocos2d::Event *unused_event) { Director *director = Director::getInstance(); auto viewSize = director->getWinSize(); float minSize = MIN(viewSize.width, viewSize.height); double targetSpeedY = acc->y * minSize*2; double targetSpeedX = acc->x * minSize*2; eaterPointsPerSecY = (eaterPointsPerSecY * .8f) + (targetSpeedY * .2f); eaterPointsPerSecX = (eaterPointsPerSecX * .8f) + (targetSpeedX * .2f); } } 


Calculating eaterPointsPerSecX and eaterPointsPerSecY in the update method, call setPosition () :

 float diffY = (eaterPointsPerSecY * dt)*1.3f; float diffX = (eaterPointsPerSecX * dt)*1.3f; float newY = eaterSprite->getPosition().y + diffY; float newX = eaterSprite->getPosition().x + diffX; eaterSprite->setPosition(newX, newY); 


Of course, in a real game, you also have to watch out for our devourer to go beyond the screen. But for now let's stop on this.
So, we created flying emoticons, added an eater, we manage it with an accelerometer ... left, add a ā€œGame Over!ā€ Screen.

11. Game Over!


Here we need a new scene. You can spy in HelloWorld and create it on the model. So we will do:

 // GameOverScene.h #include «cocos2d.h» class GameOverScene : public cocos2d::Layer { public: virtual bool init(); static cocos2d::Scene *createScene(); void startAgainCallback(cocos2d::Ref *pSender); CREATE_FUNC(GameOverScene); }; 

 // GameOverScene.cpp #include <ui/UIDeprecated.h> #include Ā«GameOverScene.hĀ» #include Ā«GameScene/GameScene.hĀ» using namespace std; using namespace cocos2d; using namespace cocos2d::ui; Scene *GameOverScene::createScene() { auto scene = Scene::create(); GameOverScene* layer = GameOverScene::create(); scene->addChild(layer); return scene; } bool GameOverScene::init() { ////////////////////////////// // 1. super init first if (!Layer::init()) { return false; } Size visibleSize = Director::getInstance()->getVisibleSize(); Vec2 origin = Director::getInstance()->getVisibleOrigin(); auto gameOVerLabel = Label::createWithTTF("Game over!Ā«, Ā«fonts/Comfortaa-Bold.ttfĀ», 24); gameOVerLabel->setTextColor(Color4B::WHITE); auto startAgainLabel = Label::createWithTTF("Play againĀ«, Ā«fonts/Comfortaa-Bold.ttfĀ», 30); startAgainLabel->setTextColor(Color4B::ORANGE); auto playAgainItem = MenuItemLabel::create(startAgainLabel, CC_CALLBACK_1(GameOverScene::startAgaingCallback, this)); auto menu = Menu::create(playAgainItem, NULL); gameOVerLabel->setPosition(visibleSize.width/2, visibleSize.height/2 + gameOVerLabel->getContentSize().height * 3); menu->setPosition(visibleSize.width/2, gameOVerLabel->getPosition().y — gameOVerLabel->getContentSize().height); this->addChild(gameOVerLabel); this->addChild(menu); } void GameOverScene::startAgaingCallback(Ref *pSender) { Director::getInstance()->replaceScene( TransitionFade::create(0.5, HelloWorld::createScene(), Color3B(255, 255, 255))); } #endif //MYGAME_GAMEOVERSCENE_H 

Almost everything that is written here, we already know.
Here, by analogy with HelloWorld, we create a label that is a menu item, that is, we can handle the onClick event. When creating MenuItemLabel, we pass one of the parameters to the link to the startAgaingCallback function, in which we change the scene. Note that changing the scene is also using the TransitionFade effect.
In the same way, we can change the game scene on GameOverScene:

 void HelloWorld::update(float dt) { if(score <= 0){ Director::getInstance()->replaceScene(TransitionFade::create(0.5, GameOverScene::createScene(score), Color3B(255,0,0))); }} 


Gameover!

Links
www.cocos2d-x.org
www.jetbrains.com/clion
habrahabr.ru/post/126582
www.cocos2d-x.org/programmersguide
www.raywenderlich.com/33752/cocos2d-x-tutorial-for-ios-and-android-space-game

Source: https://habr.com/ru/post/270133/


All Articles