Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon


29. сентября 2014

 

 

Welcome to the GameFromScratch.com Cocos2d-x tutorial series.  Cocos2d-x is a cross platform, C++ based port of the popular Cocos2D ObjectiveC game development library. Using the most recent version of Cocos2D-x you can target Windows, Mac, Linux, iOS and Android.  Previous versions enabled you to target even more targets including Blackberry and Tizen.  The history of Cocos2D-x is actually very important, as it factored in many of the design decisions that the library has taken.

 

This series will walk through the all aspects of using Cocos2d-x to create a game.  This particular part covers the process of getting Cocos2d-x installed, creating an initial project and looks at a bare bones Hello World example.

 

Cocos2D History

 

As I mentioned earlier, the history of Cocos2D is fairly important to understanding how it works, so we are going to start of with a quick, hopefully not-boring, history lesson.  I promise you, this will be the only history lesson in this entire series!  Unless of course I do more of them…  If you want a more thorough history, you can always check out the wiki.

 

Ok… history time.

 

Way back in 2008, Cocos came to be, named after the town of Los Cocos, Argentina, in case you were wondering where exactly the name came from.  It started from a gathering of Python developers in, you guessed it, Los Cocos.  As you may be able to guess from the fact it was started by a bunch of Python developers, Cocos started off being written in Python.

 

Then came along this little phone named the iPhone, and a version of Cocos2D was ported to ObjectiveC for use on iOS, the aptly named cocos2d-iphone.  A number of Cocos2d-iphone developed apps started appearing on the iPhone, including StickWars, which hit number 1 on the App Store.  Now we hit the fast forward button on history and see that Cocos2d is ported to a number of platforms.

 

One of those ports was of course Cocos2d-x, which was a port of Cocos2D to C++, the subject of our tutorial here.  Cocos2d-x itself also spawned a number of ports, including HTML and XNA.  Along the way a number of tools were developed as well, including an editor named CocosStudio (itself the spawn of a number of child projects ) and CocosCodeIDE and IDE for Lua and JavaScript scripting in Cocos2d-x.

 

So, why does this all matter?

 

Well, it’s important that you be aware that Cocos2d-x is a port of an Objective-C library which itself was a port of a Python library.  Each language and platform has had an effect on the development of Cocos2d-x, for better or worse.  You will run into some concepts and think “why the hell did they do this?”.  More often than not, it’s Cocos2D’s history that provides the reason.

 

One final important thing to realize with Cocos2d-x, a number of the most active developers behind the project are not primarily English speakers.  Cocos2D-x is extremely popular in China for example.  This is by no means a negative, but we aware sometimes language can be a bit of a barrier when looking for help and reading documentation.

 

 

What Version are you using?

 

At the point I am writing this, I am using Version 3.3beta 0 to create tutorials, and as new versions are released I will try to stay with the most recent version.  This is because I am trying to future proof this series as much as possible.  In all honesty, I know this is going to be quite annoying as well, when I created by cocos2d-html5 tutorial series, the number one problem was version changes.  Cocos2d-x is a library that get’s refactored quite a bit, so if you are far in the future and some code I provided doesn’t work, this is probably why.  Always make sure to read the comments at the bottom of each part, it may contains clues to the problem you are facing.

 

So then, what version should you use?  That answer is a bit trickier.  You have a choice between Cocos2d 2.x, 3.0 or 3.x right now.  The 2.x version is obviously the older version and less actively developed, if at all (edit – according to this thread, 2.x is no longer being supported).  That said, 2.x also supports the most platforms, including Windows Phone, Marmalade, Tizen, Blackberry and more.  Additionally, as of writing, every single book targets 2.x.  3.2 is the (currently) stable release of the most current version, while 3.x is the development version.

 

Again, I will be using the most current version as I go, and if history has taught me anything, this is going to lead to tons of issues! ;)  Warning, Here be dragons!

 

HTBD

 

 

 

Setting Up Cocos2D-x

 

In order to get started with Cocos2d-x, you need to have a couple things installed already, depending on platform you are developing on. 

 

Obviously you need a C++ compiler.  If you are working on Windows, Visual Studio 2013 is currently the recommended version.  You can download a free version named Visual Studio Express for Windows Desktop  ( note, there is also a version called Visual Studio Express for Windows, you do NOT want this version… yeah, brilliant naming by Microsoft there eh? ).  Of course if you have a complete version installed it will work fine as well.  You can also use older versions of Visual Studio, back to 2010 I believe, but this series will assume you are using the most recent version.

 

On Mac OS, Xcode is the obvious solution.  It’s also free, so that’s nice.  As of writing Xcode 6 is currently in late beta, but will work just fine.  Xcode 5 should also work just fine.  Personally I am not a huge Xcode fan and use AppCode for development on Mac, but it is not a free tool.  You may see it on occasion in screenshots, so I figured I would put it out there.  By default Xcode does not install the command line tools, so I would install those as well, you can find instructions here and official documentation here.

 

You also need to have Python installed.  Don’t worry, Python isn’t used to code in Cocos2d-x, but some of the tools require it, including the tool you use to create your project, so obviously this install is pretty important.  Another important note, so I’m going to use bold and shout at you for a second.  YOU NEED TO INSTALL PYTHON 2.7x!  The newest version, Python 3.x does not work and you will be wasting your time.  So go ahead download Python 2.7.x here.  On Windows you want to make sure Python is added to the PATH environment variable.  If it isn’t, you can get instructions here.

 

Finally if you are intending to develop for Android, you need to have a version of the Android SDK, ANT and Android NDK installed.  You need at least version 9 of the NDK ( 10 is the current as of writing.  EDIT – NDK 10 currently doesn’t work!  Read here for details.  Here for the ticket.  There is a work-around, but using NDK 9 is probably your easiest bet ) to work with Cocos2d-x.  Now to make life slightly more complicated, if you are on Windows, the Android NDK also requires Cygwin 1.7 or higher to be installed.  Fortunately, Cygwin has no further requirements.  When downloading the Android SDK, do not download the ADT package, but instead scroll further down the page and install using the “Get the SDK for an existing IDE” link.  As an FYI, the SDK is the Java SDK along with the tools needed for Android development, the NDK is the C++ toolchain for Android development, while Ant is a Java build system.

 

Please note, Cocos2d-x and be used with other IDE’s such as Eclipse or Qt Creator, but I will not be covering the process in this tutorial.

 

Oh and of course you need to download cocos2d-x itself!  Simply download and extract the library somewhere on your system.

 

 

Creating a Cocos2d-x project

 

Ok, now that you’ve got everything installed and configured, it’s time to create a project.  Open up a terminal window or command line and change to the directory you extracted cocos2d-x.

 

MacOS  Cocos2d Config and New Project Instructions:

 

Enter:

./setup.py

source ~/.profile

cocos new -l cpp -p com.gamefromscratch.gamename -d ~/Documents/Projects/cocos2d gamename

Ss6

 

Windows Cocos2d Config and New Project Instructions:

 

Open a command prompt and CD to the directory you extracted Cocos2D to.  Run the command:

python setup.py

 

If you get an error about not being able to find Python, that PATH is not configured correctly.  Depending if you have certain environment variables set or not, the install may now ask you the install directory of your Android NDK, SDK as well as Ant, provide them.  If you’ve not installed the NDK and SDK before now, do so before performing this step.

 

The next step depends on your operating system version.  If you are running Windows XP ( and possibly Vista ), you now need to restarted your computer for the changes to take effect.  If you are running Windows 7 or 8.x, simply close your command prompt and open a new one.

 

Now type:

cocos new -l cpp -p com.gamefromscratch.gamename -d C:\path\to\game\here gamename

 

Creating a New Project:

 

The tool to create cocos projects is “cocos” and it resides in [cocosSDKfolder]/tools/cocos2d-console/bin.  -l is an L by the way, this is where you specify the language for the project you want to create.  The options are cpp and lua currently, in this case we want cpp.  -p is for specifying the package, mostly for Android I assume.  This uses Java’s standard reverse domain name format.  Don’t worry if you don’t have a website, make something up.  The -d parameter is the directory where you want to create the project.

 

Now that our project is (hopefully!) created, lets take a look at what it’s created for us.

 

Ss1

 

Here you can see it has created a number of key directories for you, we will take a closer look at each one.

 

Each folder prefixed with proj. is where project files and platform specific code goes, be it android, iOS and Mac, linux, Windows or Windows Metro ( or.. what was previously known as Metro ). 

 

The cocos2d folder however is where the cocos SDK itself is copied.  This is a complete copy of Cocos2d, including docs, libraries, headers, etc.  Just a warning, this folder is 250MB in size and will be created for each cocos2D project you create using cocos new!  You can set up your projects to use a common install of cocos2d-x, by specifying the engine path when calling cocos new.  Just be aware, if you are tight on space and are going to be making a number of cocos2d-x projects, you may want to look into this further.

 

The resources folder is a common repository for all the various assets that your game will use, such as graphics, sound, etc.  The Classes folder is perhaps most important of all, this is where your non platform specific code goes!  Right now the contents should look like:

Ss2

 

These code files create a simple application to get you started, although we are ultimately going to replace the contents.  The expression AppDelegate comes from Mac programming, so if you are a Windows or Linux developer, it might be a bit alien to you.  An AppDelegate is a helper object that goes with the main window and handles events common to applications such as starting up, minimizing and closing.  You won’t really spend much time here, that instead is where the Scene file comes in.  We will look at code shortly so each piece will make a bit more sense.

 

Now let’s look at the platform specific portions for both win32 and ios_mac.

 

win32:

Ss3

 

ios_mac:

Ss4

 

As you can see, each folder contains all the platform specific code, resources and most importantly, project files for each platform.  In the case of ios_mac, it further contains platform specific folders for each platform.

 

All platforms have their own unique entry point ( main, WinMain, etc ) and different ways of handling different things.  Most of this is just relevant on start up and cocos2d-x takes care of this for you.  However at some point in the future you may need to add platform specific code, such as perhaps an ad network that only works on iOS.  This is where you would add platform specific code.  That said, 99% of your game logic should be put in the common Classes folder.  This make’s it so you can write your code in one platform, then simply open up the project files for another platform and run your game.  This is how you are able to handle many platforms with a single code base using cocos2d-x.

 

Getting Started — MacOS/XCode

 

To get started developing on MacOS, double click the .xcodeproj in the folder proj.ios_mac.  This should automatically load Xcode for you.  Now at the top bar you should be able to select which project you want, iOS or Mac.  As iOS requires the simulator or a device to execute, initially developing on the Mac can be a great deal quicker.

 

Ss5

 

Getting Started — Windows/Visual Studio

 

To get started developing on Windows, double click the .sln file in the folder proj.win32.  This will load Visual Studio for you.  Simply press Play (Local Windows Debugger) to start the compilation process:

image

 

Once you’ve selected, simply click the Play icon.  Your project will now compile and a few minutes later you should see:

Ss7

 

If you are new to C++, don’t worry, the first compilation is always the nastiest.  From now on when you press play, the compilation should be many times faster.

 

You can also run directly from the terminal using the cocos utility, like so:

 Ss8

Use -p ios to run iOS.  This command requires you to have installed the command line tools mentioned earlier.  Running from the terminal makes it so you don’t have to open the Xcode IDE if you prefer.

 

 

Hello World

 

Now let’s take a look at the minimal useful cocos2d-x application.  While the cocos new created project creates a Hello World application of sorts, it’s a pretty sloppy starting point.  First, it has needlessly complications for an app that is supposed to be a minimum example, it’s commented in a manner that only makes sense if you come from an Objective-C background and finally, it even uses deprecated methods.

 

Therefore we are going to look at a cleaner Hello World sample.  We simply replace the code in each file with the code I provide below.  Don’t worry, all of the functionality we hack out will be covered in future tutorials.

Let’s start with the AppDelegate class.

 

AppDelegate.h

#pragma once

#include "cocos2d.h"

class  AppDelegate : private cocos2d::Application
{
public:
    AppDelegate();
    virtual ~AppDelegate();

    virtual bool applicationDidFinishLaunching();
    virtual void applicationDidEnterBackground();
    virtual void applicationWillEnterForeground();
};

 

 

AppDelegate.cpp

#include "AppDelegate.h"
#include "HelloWorldScene.h"

USING_NS_CC;

AppDelegate::AppDelegate() {

}

AppDelegate::~AppDelegate() 
{
}

bool AppDelegate::applicationDidFinishLaunching() {
    auto director = Director::getInstance();
    auto glview = director->getOpenGLView();
    if(!glview) {
        glview = GLViewImpl::create("Hello World");
        glview->setFrameSize(640, 480);
        director->setOpenGLView(glview);
    }

    auto scene = HelloWorld::createScene();
    director->runWithScene(scene);

    return true;
}

void AppDelegate::applicationDidEnterBackground() {
}

void AppDelegate::applicationWillEnterForeground() {
}

 

The biggest change I have made from the default implementation is to remove all but the barest requirements of an application.  You may notice I’ve also replaced the include guards with pragma once statements.  Some people will find this controversial because pragma once isn’t standard and therefore unportable.  This may be true, if you are using a compiler from 1985.  If on the other hand you are using any modern C++ compiler, pragma once is supported.  Include guards and pragma once perform the same task, except pragma once is more concise and less error prone.  If you want to switch back to include guards, feel free.  From this point on, I will however, not be using them.

 

OK, back to the code itself.  Our AppDelegate header is pretty straight forward, it declares a constructor, destructor and three methods, applicationDidFinishLaunching, applicationDidEnterBackground and applicationWillEnterForeground.  All three of these methods are pure virtual functions from ApplicationProtocol, from which Application ( and in turn AppDelegate ) inherit, so we must provide an implementation of each, even if it’s empty.

 

Now onto AppDelegate.cpp.  First we start off with the macro USING_NS_CC; which is just short for “using namespace cocos2d”.  Personally I don’t see a big win in using a macro over typing using namespace cocos2d, but generally I find many uses of macros unagreeable.  This however is the style the cocos team went with, so I will follow along.  As you can see, both or constructor, destructor, applicationDidEnterBackground and applicationWillEnterForeground all have empty implementations, so applicationDidFinishLaunching is where all of our logic resides.

 

If these names seem a bit long winded to you, they have been taken directly from the iOS world.  Basically the enterBackground/enterForeground methods are called when your application gains and loses focus, while applicationDidFinishLaunching is called when your application is loaded ( at the end of the loading process ).  Here we get an instance of the Director singleton, then use it to either get the GLView, or create a GLViewImpl, which is a default implementation of GLView.  Basically GLView is the OpenGL representation of your window or screen, depending on what kind of device you are running.  We then set the resolution of the window ( this is not required, I just wanted a smaller resolution for screen shots ) by calling setFrameSize() then set the view as active by calling Director’s setOpenGLView().  Now that we have a window, we create an instance of our scene calling createScene() and once again, use the Director to set this scene active using runWithScene().

 

Aren't Singletons bad?

You may notice in the above code that Director is very important to the operation of Cocos2d-x.  Director is an implementation of a design pattern known as a Singleton, or as some would say, an anti-pattern.  If you’ve spent much time on programming forums, you will see thread after thread calling Singletons evil.  In a nutshell, a singleton is a delayed, but guaranteed to be instantiated global variable in a pretty dress.  Sometimes too, a global variable is just what you need, which is why you will find a number of game engines make use of singletons to provide globally available interfaces.  At this point the matter is pretty much moot, if you use Cocos2d-x, you use Director, or you don’t use Cocos2d-x.

One of the major source of bugs with Singletons, especially in C++, is multithreading.  When you have this global instance being access from all kinds of locations and controlling so many things, how do you handle concurrent requests?  Well have I got good news for you!  You don’t. :)

That’s because Cocos2d-x isn’t thread safe.  Or more accurately, Cocos2d-x’s memory management ( anything derived from cocos2d::Ref ) and OpenGL rendering aren’t thread safe.  To make this clear, you can use threads in a Cocos2d-x application, but you need to be very careful what those threads interact with.  Other than the threading problems, some of the biggest problems that come from using Singletons are related to code maintenence, as you are coupling so many systems together.  Fortunately, this is the cocos2d-x team’s problem to deal with, not yours.  Unless of course you are on the Cocos2d-x team that is.

 

Now let's take a look at our scene, HelloWorldScene.

 

HelloWorldScene.h

#pragma once

#include "cocos2d.h"

class HelloWorld : public cocos2d::Layer
{
public:
    static cocos2d::Scene* createScene();
    virtual bool init();  
    
    CREATE_FUNC(HelloWorld);
};

 

HelloWorldScene.cpp

#include "HelloWorldScene.h"

USING_NS_CC;

Scene* HelloWorld::createScene()
{
    // 'scene' is an autorelease object
    auto scene = Scene::create();
    auto layer = HelloWorld::create();

    scene->addChild(layer);

    return scene;
}

bool HelloWorld::init()
{
    if ( !Layer::init() )
    {
        return false;
    }
   
    auto label = Label::createWithSystemFont("Hello World", "Arial", 96);
    label->setAnchorPoint(cocos2d::Vec2(0.0, 0.0));
    this->addChild(label, 1);

    return true;
}

 

In our header once again I’ve replaced the header guard with pragma pack.  We are declaring our scene class HelloWorld, which inherits from Layer which is a Node which can receive input events, such as touch, keys and motion.  We declare createScene() which returns a static Scene pointer.  As you may recall, we called this method earlier in AppDelegate to create our scene.  We also override the method init that we inherited from Node and is where we do our initialization logic.  Finally there is a bit of macro magic in the form of CREATE_FUNC(HelloWorld).

Let’s take a quick look at exactly what this macro is doing:

 

#define CREATE_FUNC(__TYPE__) \
static __TYPE__* create() \
{ \
    __TYPE__ *pRet = new __TYPE__(); \
    if (pRet && pRet->init()) \
    { \
        pRet->autorelease(); \
        return pRet; \
    } \
    else \
    { \
        delete pRet; \
        pRet = NULL; \
        return NULL; \
    } \
}

 

Granted, it’s not always the easiest code to read, as this is code for generating code, but essentially after this macro runs, we’ve got:

static HelloWorld* create(){
    HelloWorld *pRet = new HelloWorld(); 
    if (pRet && pRet->init())
    { 
        pRet->autorelease();
        return pRet; 
    } 
    else 
    { 
        delete pRet; 
        pRet = NULL; 
        return NULL; 
    }
} 

 

So, essentially, the macro is creating a create() function that allocates an instance of our class, calls the init method that we provided and then, most importantly, calls autorelease() we inherited from Ref.  I will cover why this is important in a few minutes, depending of course on how fast you read. :)

 

Now on to HelloWorldScene.cpp.  The createScene() method is pretty straight forward.  We create a Scene object, then an instance of our HelloWorld class ( which inherits from Layer ) and add our layer to the scene then return the scene ( which our AppDelegate then passed to Director->runScene() ).

In init() we perform the bulk of our logic.  First we call our base classes init function ( which is very important to do ), then create a Label using createWithSystemFont(), which predictably enough, using the built in system font (in this case Arial ) to create the Label’s text.  We then set the Labels anchor point to the bottom left, which means this node will be positioned relative to it’s bottom left corner.  I will cover anchor points in more detail in the next tutorial, so ignore this for now.  Finally we add the freshly created Label to our layer.  Finally we return true to indicate that initialization worked as expected.

 

Now if run our “game”, we should see:

image

 

 

Aren't we leaking memory like mad?

So you may have noticed we create all kinds of pointers using create() calls, but never once called delete.  As you can see in the code generated by the CREATE_FUNC, we are creating a new instance of our class, but we never do delete it.  Aren’t we leaking memory here?  Thankfully the answer is no and the reason is in the call to init() and autorelease() that the macro made and why it was so important we called our base classes init() in our own init method.

This is another legacy of Cocos2d-x’s Objective-C roots.  Objective-C provides a form of memory management via ARC, Automatic Reference Counting.  Basically each time something references an object, it’s count is increased, each time something reference an object goes away, the count is decreased, when the count hits zero, the object is released.  In many ways, this is pretty much the same functionality C++ smart pointers provide, but Cocos2d predates the standardization of smart pointers.

There is more to their usage that we will cover later on.  For now though, you can safely assume any cocos2d object created with a create() function, that inherits from Ref, does not need to be delete.  In fact, such objects must not be deleted!

 

In the next part we will take a look at working with graphics in Cocos2d-x.  Don’t worry, it will be much less verbose and much heavier in code!

Programming , ,

blog comments powered by Disqus

Popular Comments

The Unreal Engine 4 Rosetta Stone
Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon


21. April 2014

 

Comprehending any large code base is never a simple factor.  This is especially true of C++ with hits heavily used (and abused) typedef system.  The Unreal Engine has a very well defined and consistent naming convention but trying to crack it can take a bit of effort, as it’s explained piecemeal throughout the documentation. RosettaStone That is, until I found the Coding Standard document, which frankly is the very first page a C++ programmer working with UE4 should start with.  This document is the titular Rosetta Stone, the method that makes reading UE code possible.

 

Understanding their naming conventions will help you a great deal when trying to work through code samples.  A few of their choices strike me as a bit unusual, especially if you were raised on Hungarian like I was.  Here are the naming convention:

  • The first letter of each word in a name (e.g. type or variable) is capitalized, and there is usually no underscore between words. For example, Health and UPrimitiveComponent, but not lastMouseCoordinates or delta_coordinates.

  • Type names are prefixed with an additional upper-case letter to distinguish them from variable names. For example, FSkin is a type name, and Skin is an instance of a FSkin.

    • Template classes are prefixed by T.

    • Classes that inherit from UObject are prefixed by U.

    • Classes that inherit from AActor are prefixed by A.

    • Classes that inherit from SWidget are prefixed by S.

    • Classes that are abstract interfaces are prefixed by I.

    • Most other classes are prefixed by F, though some subsystems use other letters.

  • Type and variable names are nouns.

  • Method names are verbs that describe the method's effect, or describe the return value of a method that has no effect.

Variable, method, and class names should be clear, unambiguous, and descriptive. The greater the scope of the name, the greater the importance of a good, descriptive name. Avoid over-abbreviation.

All variables should be declared one at time so that a comment on the meaning of the variable can be provided. Also, the JavaDocs style requires it. You can use multi-line or single line comments before a variable, and the blank line is optional for grouping variables.

All functions that return a bool should ask a true/false question, such as "IsVisible()", or "ShouldClearBuffer()". All boolean variables must be prefixed with a "b" character (e.g. "bPendingDestruction", or "bHasFadedIn").

A procedure (a function with no return value) should use a strong verb followed by an object. An exception is if the object of the method is the object it is in; then the object is understood from context. Names to avoid include those beginning with "Handle" and "Process"; the verbs are ambiguous.

Though not required, we encourage you to prefix function parameter names with "Out" if they are passed by reference and the function is expected to write to that value. This makes it obvious that the value passed in this argument will be replaced by the function.

 

This explains all the AClass and UProperty you will encounter through out the code, and explains the far to common FSomethings you see in the code..

 

There are a few things I find unwieldy about these choices.  First, I am so used to instances starting with lower case that this seems like Anathema to me.  Second, if you are going to prefix with all capital letters, why not BBoolValue instead of bBoolValue, this seems inconsitent to me.  Next, why F for types? Finally why SWidget and S instead of Widget and W?  WButton makes a ton more sense than SButton for example.

 

At the end of the day it doesn’t really matter, the most important thing is to be consistent, which they have.  Now with a thorough understanding of their naming convention, groking the code is a heck of a lot easier.

 

Also of great important are the C++ type usage guidelines.  This is both a power and flaw of working with C++, there are more types than grains of sand in the desert, so knowing which to use is critical.

 

Portable Aliases for Basic C++ Types

  • bool for boolean values (NEVER assume the size of bool). BOOL will not compile.

  • TCHAR for a character (NEVER assume the size of TCHAR)

  • uint8 for unsigned bytes (1 byte)

  • int8 for signed bytes (1 byte)

  • uint16 for unsigned "shorts" (2 bytes)

  • int16 for signed "shorts" (2 bytes)

  • uint32 for unsigned ints (4 bytes)

  • int32 for signed ints (4 bytes)

  • uint64 for unsigned "quad words" (8 bytes)

  • int64 for signed "quad words" (8 bytes)

  • float for single precision floating point (4 bytes)

  • double for double precision floating point (8 bytes)

  • PTRINT for an integer that may hold a pointer (NEVER assume the size of PTRINT)

Don't use the C++ int type in portable code, since it's dependent on the compiler how large it is.

 

So if you are just starting out with C++ programming in Unreal, start here, it will make the journey a lot easier.

 

Finally C++ 11 guidelines are also important.  C++11 support across compilers is by no means universal but many of the features of C++11 are pretty damned useful.  Keep in mind, these guidelines are for Unreal staff working on the engine, not the end user working with the engine, so if you are say… only using Visual C++ 13, then feel free to use whatever features you want.  If you want to target as many platforms as possible though, you should be mindful of these instructions:

 

C++ 11 and Modern Language Syntax

Unreal Engine is built to be massively portable to many C++ compilers, so we're careful to use features that are compatible with the compilers we can imagine supporting. Sometimes features are so useful that we'll wrap them up in macros and use them pervasively (such as the 'override' keyword), but usually we'll wait until all of the compilers we could imagine supporting are up to the latest standard.

We are utilizing certain C++ 11 language features that appear to be well-supported across modern compilers, such as the "auto" keyword, range-based-for and lambdas. In some cases we're able to wrap up usage of these features in preprocessor conditionals (such as rvalue references in containers.) However, certain language features we may opt to avoid entirely until we're confident we won't be surprised by a new platform appearing that cannot digest the syntax.

Unless specified below as a modern C++ compiler feature we are supporting, you should refrain from using compiler-specific language features unless they are wrapped in preprocessor macros or conditionals and used sparingly.

The 'auto' Keyword

The 'auto' keyword is supported by all compilers UE4 targets and you are encouraged to use it in your code where it makes sense to do so.

Remember you can and should use const, & or * with auto just like you would with the type name. With auto, this will coerce the inferred type to be what you want.

We encourage use of the auto keyword for iterator loops (eliminates boilerplate), and also when you are initializing a variable to a new instance (eliminates redundant type name.) Some of the other uses are more contentious, but feel free to use it however you want for now and we can learn and improve best practices as we go.

Tip: If you hover over a variable in Visual Studio, it will usually tell you the inferred type.

Range Based For

This is allowed in all engine and editor code and encouraged where it can help to keep the code easier to understand and more maintainable.

Lambdas and Anonymous Functions

Lambdas are now allowed, however we are cautious about use of stateful lambdas that capture stack variables -- we're still learning about where those are appropriate. Also, stateful lambdas cannot be assigned to function pointers which we tend to use a lot. We expect to update this documentation in the future as we establish best practices.

 

So, basically ranged based for loops, stateless lambdas good, stateful lambda bad and auto is a maybe.  For the remaining features that aren’t cross platform like override, they’ve provided preprocessor conditionals to work with them.  I really wish they listed them all here though.

Programming ,

blog comments powered by Disqus

Month List

Popular Comments