Building Portable Games in C++

Datetime:2016-08-23 04:31:52          Topic: C++  Cocos2d-X           Share

Our game, Ready Steady Bang, was written using cocos2d-iphone, which we were considering using for our next game, Ready Steady Play. Then I remembered the C++ gaming framework cocos2d-x and its promise of cross-platform compilation.

In this article, I break down how I developed the Ready Steady Play game using cocos2d-x and discuss the porting travails of moving the final code from iOS to Android and Windows Phone 8. I used v2.2.x of cocos-2dx, but most of this text should be applicable for v3.x. I wanted to write this as a lesson to any budding (or even experienced) game developer to show how to get started and to map out what might be the major pitfalls along the way. While I've tried to make it comprehensive, a single article cannot cover every step of the design and development process.

If you don't want to delve into C++ you can always opt for something like cocos2d-js, where you can make a cocos2d-x game using only JavaScript APIs. However, this article focuses solely on cocos2d-x projects.

Prerequisites

The following prerequisites and are not really required, but are highly recommended.

  • Intermediate level of object-oriented programming and C++.
  • Understanding of run loops.
  • Beginner level of shell scripting and understanding of Makefiles.
  • Experience using IDEs and looking up documentation. The cocos2d-x documentation is lacking, but there are enough guides out there to help you with any specific problems.
  • Beginner level  knowledge of SCM. I'll use git, but feel free to use your own SCM product.

Setting Up the Project

  1. Create an empty git repository in the root folder.
  2. Submodule cocos2d-x using the latest tag/release. I ended up forking the project so that I could make adjustments that suited Ready Steady Play.
  3. Take the C++ project template and copy it into the root folder (a great way to do this is by using the create_project.py script in the tools/project-creator folder.)

This initial setup creates the folders required to develop the game. The contents of your root folder should be:

  • Classes , which contains all the game logic files that you will be writing.
  • cocos2d-x , which is the submodule created in step two above.
  • proj.android/ios/mac/... These .proj folders are set up for you by cocos2d-x so that you can focus on creating the game and not on porting. That doesn't mean that it's an effortless process, but you're off to an easy start.
  • Resources , which is where all the assets such as sound files, images, fonts, etc. are placed.

I come from an iOS development background, so the majority of the coding work I did was in the proj.ios folder. I know my way around Xcode like the back of my hand: It has the fastest build time of all the development environments I've used for the project (the others being Eclipse and Visual Studio Express 2013) and the simulator is perfect for quick and easy testing.

Understanding cocos2d-x

The cocos2d-x system is fairly complex, but most of it should be running in the background without you needing to delve into it. A lot of the structure is taken from iOS development, so thankfully, I could get my head around it quickly. If you come from an Android or Windows Phone 8 background, it probably won't take you too long either.

To start an application running, you'll come across the following classes:

  • CCDirector , this is the big boss of your application. The director is responsible for passing along render calls, user interaction events, and much more. Most of the time you will only be using the director to present different scenes in your game.
  • CCEGLView , the view is responsible for rendering the game on the device screen. Other than the initial setup, you probably won't ever need to worry about it.
  • CCFileUtils , every operating system has its own way of storing and managing files. This is what you use if you want to perform any kind of file handling operations, although more often than not, this is transparent to you. When the app starts, you provide it with the search paths , which I'll explain shortly.
  • CCScene , this is the base node that the director will display. I'll describe it in more detail when I discuss node hierarchy .

Design Resolution and Policy

When you start a cocos2d-x game, one of the first calls you need to make is:

CCEGLView::sharedOpenGLView()-<setDesignResolutionSize(
    designResolutionSize.width, designResolutionSize.height, designPolicy);

Ready Steady Play was designed for an iPad retina screen, which means that all images and sizing were based on a design resolution of 1536×2048 pixels. But the important part is the design policy . The policy dictates how the game is displayed on screens of varying aspect ratios. The following are the definitions of the different design policies, taken from CCEGLViewProtocol.h :

enum ResolutionPolicy
{
	// The entire application is visible in the specified area without trying to
	// preserve the original aspect ratio.
	// Distortion can occur, and the application may appear stretched or
	// compressed.
	kResolutionExactFit,
	// The entire application fills the specified area, without distortion but
	// possibly with some cropping, while maintaining the original aspect ratio of
	// the application.
	kResolutionNoBorder,
	// The entire application is visible in the specified area without distortion
	// while maintaining the original aspect ratio of the application. Borders can
	// appear on two sides of the application.
	kResolutionShowAll,
	// The application takes the height of the design resolution size and modifies
	// the width of the internal canvas so that it fits the aspect ratio of the
	// device no distortion will occur however you must make sure your application
	// works on different aspect ratios
	kResolutionFixedHeight,
	// The application takes the width of the design resolution size and modifies
	// the height of the internal canvas so that it fits the aspect ratio of the
	// device no distortion will occur however you must make sure your application
	// works on different aspect ratios
	kResolutionFixedWidth,

	kResolutionUnKnown,
};

When designing for mobile phones of varying sizes, the first three options are not ideal. You don't want your game being squashed ( ExactFit ), cropped ( NoBorder ) or having black borders ( ShowAll ). We opted for FixedHeight as it is far less drastic having a wider screen than a shorter one, especially considering that we use both portrait and landscape modes. Take the second game in Ready Steady Play, Hobby Hurdles, as an example when played on an iPhone 5 screen:

iPhoneGames FixedHeight.

iPhoneGames FixedWidth.

In FixedWidth mode, it becomes almost impossible to fit anything on the screen, while in FixedHeight the game is slightly zoomed out. When compared between devices it might look a bit strange, but most players use just one device and they won't know the difference.

Content Scale Factor

Once the design resolution and policy are set up, you need to tell cocos2d-x which image resources you intend to use, which will define the content scale factor. The standard setup for cocos2d-x is to have three different sizes for images: HDR (High Definition Retina), HD (High Definition), and SD (Standard Definition). As mentioned before, we designed Ready Steady Play for a retina iPad screen, so our size definitions are:

HDR :    1536×2048

HD :      768×1024

SD :      384×512

When the app starts, we choose the appropriate images resource folder based on screen size, then we calculate the content scale factor by calling:

director->setContentScaleFactor(resource.size.width/designResolutionSize.width);

Search Paths

The search paths are used by CCFileUtils to find the required resources, particularly images and sound files. The Resources folder (described earlier) should have one folder for each of your resource definitions (HDR/HD/SD), where each one has identical images resized accordingly. For example, if you have an image whose path is Resources/HDR/Button.png and whose size is 100×100 pixels, then there will be an image at Resources/HD/Button.png sized 50×50 and another at Resources/SD/Button.png sized 25×25.

When the application begins, you provide CCFileUtils with the paths to search in the Resources folder. Using the above example, if you provide it with "HD" and then make a call to:

CCTextureCache::sharedTextureCache()->addImage("Button.png")

You will get back a texture using the image at Resources/HD/Button.png .





About List