29. September 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!

## 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.

## 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

#### 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.

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:

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:

ios_mac:

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.

#### 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:

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

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:

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.

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().

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();

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));

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:

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!

25. September 2014

Remember in our earlier example where we used a ContactListener to check for a collision between two types of FixtureDef and how ungainly the check was?  Remember when I said there was a much better way of doing this?  Well, welcome the the better way, Filters.

Filters are actually rather simple, except they use bitmasking, a concept that might be somewhat new to you.  I actually went into some detail on the use of bitmasks in this tutorial if you need some details.  Basically its about using individual bits in a number as “on/off” flags.  Basically it allows you to track multiple values in a single variable.  In Box2D, there are a pair of bitmask, the categoryBits and maskBits.  Those names can be a bit confusing but don’t worry about that.

Basically you can think of categoryBits as saying “This is what I am” and maskBits as “This is what I collide with”.  Keep in mind, you can set multiple bits for either, so you can both be multiple things and collide with multiple things.  That may still sound somewhat confusing, so let’s look at an example.  This is a modification of the code from the previous tutorial.  In this case, we want our two sprites to NOT collide with each other, but to collide with the edge that represents the ground in the world.

package com.gamefromscratch;

public class Physics4 extends ApplicationAdapter {
SpriteBatch batch;
Sprite sprite,sprite2;
Texture img;
World world;
Body body,body2;
Body bodyEdgeScreen;

Matrix4 debugMatrix;
OrthographicCamera camera;

final float PIXELS_TO_METERS = 100f;

final short PHYSICS_ENTITY = 0x1;    // 0001
final short WORLD_ENTITY = 0x1 << 1; // 0010 or 0x2 in hex

@Override
public void create() {
batch = new SpriteBatch();

// Create two identical sprites slightly offset from each other vertically
sprite = new Sprite(img);
sprite.setPosition(-sprite.getWidth()/2,-sprite.getHeight()/2 +200);
sprite2 = new Sprite(img);
sprite2.setPosition(-sprite.getWidth()/2 + 20,-sprite.getHeight()/2 + 400);

world = new World(new Vector2(0, -1f),true);

// Sprite1's Physics body
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set((sprite.getX() + sprite.getWidth()/2) /
PIXELS_TO_METERS,
(sprite.getY() + sprite.getHeight()/2) / PIXELS_TO_METERS);

body = world.createBody(bodyDef);

// Sprite2's physics body
BodyDef bodyDef2 = new BodyDef();
bodyDef2.type = BodyDef.BodyType.DynamicBody;
bodyDef2.position.set((sprite2.getX() + sprite2.getWidth()/2) /
PIXELS_TO_METERS,
(sprite2.getY() + sprite2.getHeight()/2) / PIXELS_TO_METERS);

body2 = world.createBody(bodyDef2);

// Both bodies have identical shape
PolygonShape shape = new PolygonShape();
shape.setAsBox(sprite.getWidth()/2 / PIXELS_TO_METERS, sprite.getHeight()
/2 / PIXELS_TO_METERS);

// Sprite1
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = 0.1f;
fixtureDef.restitution = 0.5f;
fixtureDef.filter.categoryBits = PHYSICS_ENTITY;

// Sprite2
FixtureDef fixtureDef2 = new FixtureDef();
fixtureDef2.shape = shape;
fixtureDef2.density = 0.1f;
fixtureDef2.restitution = 0.5f;
fixtureDef2.filter.categoryBits = PHYSICS_ENTITY;

body.createFixture(fixtureDef);
body2.createFixture(fixtureDef2);

shape.dispose();

// Now the physics body of the bottom edge of the screen
BodyDef bodyDef3 = new BodyDef();
bodyDef3.type = BodyDef.BodyType.StaticBody;

float w = Gdx.graphics.getWidth()/PIXELS_TO_METERS;
float h = Gdx.graphics.getHeight()/PIXELS_TO_METERS;

bodyDef3.position.set(0,0);
FixtureDef fixtureDef3 = new FixtureDef();
fixtureDef3.filter.categoryBits = WORLD_ENTITY;

EdgeShape edgeShape = new EdgeShape();
edgeShape.set(-w/2,-h/2,w/2,-h/2);
fixtureDef3.shape = edgeShape;

bodyEdgeScreen = world.createBody(bodyDef3);
bodyEdgeScreen.createFixture(fixtureDef3);
edgeShape.dispose();

camera = new OrthographicCamera(Gdx.graphics.getWidth(),Gdx.graphics.
getHeight());
}

@Override
public void render() {
camera.update();
// Step the physics simulation forward at a rate of 60hz
world.step(1f/60f, 6, 2);

sprite.setPosition((body.getPosition().x * PIXELS_TO_METERS) - sprite.
getWidth()/2 ,
(body.getPosition().y * PIXELS_TO_METERS) -sprite.getHeight()/2 );

sprite.setRotation((float)Math.toDegrees(body2.getAngle()));
sprite2.setPosition((body2.getPosition().x * PIXELS_TO_METERS) - sprite2.
getWidth()/2 ,
(body2.getPosition().y * PIXELS_TO_METERS) -sprite2.getHeight()/2 );
sprite2.setRotation((float)Math.toDegrees(body.getAngle()));

Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

batch.setProjectionMatrix(camera.combined);
batch.begin();

batch.draw(sprite, sprite.getX(), sprite.getY(),sprite.getOriginX(),
sprite.getOriginY(),
sprite.getWidth(),sprite.getHeight(),sprite.getScaleX(),sprite.
getScaleY(),sprite.getRotation());
batch.draw(sprite2, sprite2.getX(), sprite2.getY(),sprite2.getOriginX(),
sprite2.getOriginY(),
sprite2.getWidth(),sprite2.getHeight(),sprite2.getScaleX(),sprite2.
getScaleY(),sprite2.getRotation());
batch.end();
}

@Override
public void dispose() {
img.dispose();
world.dispose();
}
}

When a collision occurs, the collider will check it’s categoryBits against the collided’s maskBits.  If both are true, a collision occurs.  So in this example, both sprites will fall, completely ignoring each other.  However when they run in to the WORLD_ENTITY, a collision will occur.

Now, taking the same scenario, if you wanted to have the sprites collide with each other AND WORLD_ENTITY objects, you would simply change to

fixtureDef.filter.maskBits = WORLD_ENTITY|PHYSICS_ENTITY;

Now this object will have collisions with either kind of entity.

There is one other kind of filter in Box2D, and it's confusing as hell in my opinion. It's basically an override for grouping entities together called groupIndex.  I will let someone else explain how it works:

When checking two fixtures to see if they should collide:

• if either fixture has a groupIndex of zero, use the category/mask rules as above
• if both groupIndex values are non-zero but different, use the category/mask rules as above
• if both groupIndex values are the same and positive, collide
• if both groupIndex values are the same and negative, don't collide

The default value for the groupIndex is zero

So, if you want to have fine tune control over which entities interact with each other, Filter is how you do it.  Ok, let’s keep this part short and sweet.

25. September 2014

So far we’ve covered creating a simple simulation then how to create physics bodies and apply forces to them now we look at dealing with collisions.  Truth of the matter is, most of the work is just done for us.  Let’s just right in with an example, heavily copied and pasted from the previous example.

package com.gamefromscratch;

public class Physics2 extends ApplicationAdapter implements InputProcessor {
SpriteBatch batch;
Sprite sprite;
Texture img;
World world;
Body body;
Body bodyEdgeScreen;
Box2DDebugRenderer debugRenderer;
Matrix4 debugMatrix;
OrthographicCamera camera;
BitmapFont font;

float torque = 0.0f;
boolean drawSprite = true;

final float PIXELS_TO_METERS = 100f;

@Override
public void create() {

batch = new SpriteBatch();
sprite = new Sprite(img);

sprite.setPosition(-sprite.getWidth()/2,-sprite.getHeight()/2);

world = new World(new Vector2(0, -1f),true);

BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set((sprite.getX() + sprite.getWidth()/2) /
PIXELS_TO_METERS,
(sprite.getY() + sprite.getHeight()/2) / PIXELS_TO_METERS);

body = world.createBody(bodyDef);

PolygonShape shape = new PolygonShape();
shape.setAsBox(sprite.getWidth()/2 / PIXELS_TO_METERS, sprite.getHeight()
/2 / PIXELS_TO_METERS);

FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = 0.1f;
fixtureDef.restitution = 0.5f;

body.createFixture(fixtureDef);
shape.dispose();

BodyDef bodyDef2 = new BodyDef();
bodyDef2.type = BodyDef.BodyType.StaticBody;
float w = Gdx.graphics.getWidth()/PIXELS_TO_METERS;
// Set the height to just 50 pixels above the bottom of the screen so we can see the edge in the
// debug renderer
float h = Gdx.graphics.getHeight()/PIXELS_TO_METERS- 50/PIXELS_TO_METERS;
//bodyDef2.position.set(0,
//                h-10/PIXELS_TO_METERS);
bodyDef2.position.set(0,0);
FixtureDef fixtureDef2 = new FixtureDef();

EdgeShape edgeShape = new EdgeShape();
edgeShape.set(-w/2,-h/2,w/2,-h/2);
fixtureDef2.shape = edgeShape;

bodyEdgeScreen = world.createBody(bodyDef2);
bodyEdgeScreen.createFixture(fixtureDef2);
edgeShape.dispose();

Gdx.input.setInputProcessor(this);

debugRenderer = new Box2DDebugRenderer();
font = new BitmapFont();
font.setColor(Color.BLACK);
camera = new OrthographicCamera(Gdx.graphics.getWidth(),Gdx.graphics.
getHeight());
}

private float elapsed = 0;
@Override
public void render() {
camera.update();
// Step the physics simulation forward at a rate of 60hz
world.step(1f/60f, 6, 2);

body.applyTorque(torque,true);

sprite.setPosition((body.getPosition().x * PIXELS_TO_METERS) - sprite.
getWidth()/2 ,
(body.getPosition().y * PIXELS_TO_METERS) -sprite.getHeight()/2 )
;
sprite.setRotation((float)Math.toDegrees(body.getAngle()));

Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

batch.setProjectionMatrix(camera.combined);
debugMatrix = batch.getProjectionMatrix().cpy().scale(PIXELS_TO_METERS,
PIXELS_TO_METERS, 0);
batch.begin();

if(drawSprite)
batch.draw(sprite, sprite.getX(), sprite.getY(),sprite.getOriginX(),
sprite.getOriginY(),
sprite.getWidth(),sprite.getHeight(),sprite.getScaleX(),sprite.
getScaleY(),sprite.getRotation());

font.draw(batch,
"Restitution: " + body.getFixtureList().first().getRestitution(),
-Gdx.graphics.getWidth()/2,
Gdx.graphics.getHeight()/2 );
batch.end();

debugRenderer.render(world, debugMatrix);
}

@Override
public void dispose() {
img.dispose();
world.dispose();
}

@Override
public boolean keyDown(int keycode) {
return false;
}

@Override
public boolean keyUp(int keycode) {

if(keycode == Input.Keys.RIGHT)
body.setLinearVelocity(1f, 0f);
if(keycode == Input.Keys.LEFT)
body.setLinearVelocity(-1f,0f);

if(keycode == Input.Keys.UP)
body.applyForceToCenter(0f,10f,true);
if(keycode == Input.Keys.DOWN)
body.applyForceToCenter(0f, -10f, true);

// On brackets ( [ ] ) apply torque, either clock or counterclockwise
if(keycode == Input.Keys.RIGHT_BRACKET)
torque += 0.1f;
if(keycode == Input.Keys.LEFT_BRACKET)
torque -= 0.1f;

// Remove the torque using backslash /
if(keycode == Input.Keys.BACKSLASH)
torque = 0.0f;

// If user hits spacebar, reset everything back to normal
if(keycode == Input.Keys.SPACE|| keycode == Input.Keys.NUM_2) {
body.setLinearVelocity(0f, 0f);
body.setAngularVelocity(0f);
torque = 0f;
sprite.setPosition(0f,0f);
body.setTransform(0f,0f,0f);
}

if(keycode == Input.Keys.COMMA) {
body.getFixtureList().first().setRestitution(body.getFixtureList().first().getRestitution()-0.1f);
}
if(keycode == Input.Keys.PERIOD) {
body.getFixtureList().first().setRestitution(body.getFixtureList().first().getRestitution()+0.1f);
}
if(keycode == Input.Keys.ESCAPE || keycode == Input.Keys.NUM_1)
drawSprite = !drawSprite;

return true;
}

@Override
public boolean keyTyped(char character) {
return false;
}

// On touch we apply force from the direction of the users touch.
// This could result in the object "spinning"
@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
body.applyForce(1f,1f,screenX,screenY,true);
//body.applyTorque(0.4f,true);
return true;
}

@Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
return false;
}

@Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
return false;
}

@Override
public boolean mouseMoved(int screenX, int screenY) {
return false;
}

@Override
public boolean scrolled(int amount) {
return false;
}
}

Here is the application running

Click to open in new Window (It's probably already run by the time you scrolled down)

You can control it using the following controls:

• Left and Right Arrow:  Apply impulse along X axis
• Up and Down Arrow: Apply force along Y axis.
• [ and ]: Apply torque
• \: Set torque to 0
• SPACEBAR or '2': Reset all
• Click, apply force from point of click
• ESC or '1' toggles display of the sprite graphic on and off

This is basically the same application we created in the previous example, except now there is actually something to collide with.  In this case we created a physics body defined by an edge shape just 50 pixels above the bottom of the screen.  The key difference between our two bodies is bodyEdgeScreen has it’s physics type set to StaticBody.  A static body is exactly what it’s name implies, static, meaning that it doesn’t move.  It participates in the physics simulation ( stuff can hit it ), but it is un affected by the simulation itself.  If this body wasn’t static, gravity would have grabbed it and set it free falling in space.  As you can see, it is created the same way as our other physics body.  The only other major difference is instead of being defined in the physics engine by a box, it is instead represented as an edge defined by two points.  This means our EdgeShape has no volume.

Now that we have collisions occurring a few values became much more important, density, restitution (and not shown, friction).  These are set on the FixtureDef of your Body.  We touched briefly on density in the previous tutorials, it helps determine the overall mass of your object along with the shape.  Restitution can be thought of as, for the lack of a better term, as bounciness.  Restitution helps determine how one body will respond to contact with another physics object.  Rubber for example would have a high restitution, while rock would have a very low restitution.  Friction on the other hand determines how one body slides across another body.

What happens if you want to perform some kind of operation when a collision occurs?  Well fortunately this is quite simple, let’s take a look at another heavily cut and paste example!

package com.gamefromscratch;

public class Physics3 extends ApplicationAdapter {
SpriteBatch batch;
Sprite sprite,sprite2;
Texture img;
World world;
Body body,body2;
Body bodyEdgeScreen;

Matrix4 debugMatrix;
OrthographicCamera camera;

final float PIXELS_TO_METERS = 100f;

@Override
public void create() {
batch = new SpriteBatch();

// Create two identical sprites slightly offset from each other vertically
sprite = new Sprite(img);
sprite.setPosition(-sprite.getWidth()/2,-sprite.getHeight()/2 +200);
sprite2 = new Sprite(img);
sprite2.setPosition(-sprite.getWidth()/2 + 20,-sprite.getHeight()/2 + 400);

world = new World(new Vector2(0, -1f),true);

// Sprite1's Physics body
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set((sprite.getX() + sprite.getWidth()/2) /
PIXELS_TO_METERS,
(sprite.getY() + sprite.getHeight()/2) / PIXELS_TO_METERS);

body = world.createBody(bodyDef);

// Sprite2's physics body
BodyDef bodyDef2 = new BodyDef();
bodyDef2.type = BodyDef.BodyType.DynamicBody;
bodyDef2.position.set((sprite2.getX() + sprite2.getWidth()/2) /
PIXELS_TO_METERS,
(sprite2.getY() + sprite2.getHeight()/2) / PIXELS_TO_METERS);

body2 = world.createBody(bodyDef2);

// Both bodies have identical shape
PolygonShape shape = new PolygonShape();
shape.setAsBox(sprite.getWidth()/2 / PIXELS_TO_METERS, sprite.getHeight()
/2 / PIXELS_TO_METERS);

// Sprite1
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = 0.1f;
fixtureDef.restitution = 0.5f;

// Sprite2
FixtureDef fixtureDef2 = new FixtureDef();
fixtureDef2.shape = shape;
fixtureDef2.density = 0.1f;
fixtureDef2.restitution = 0.5f;

body.createFixture(fixtureDef);
body2.createFixture(fixtureDef2);

shape.dispose();

// Now the physics body of the bottom edge of the screen
BodyDef bodyDef3 = new BodyDef();
bodyDef3.type = BodyDef.BodyType.StaticBody;
float w = Gdx.graphics.getWidth()/PIXELS_TO_METERS;
float h = Gdx.graphics.getHeight()/PIXELS_TO_METERS;

bodyDef3.position.set(0,0);
FixtureDef fixtureDef3 = new FixtureDef();

EdgeShape edgeShape = new EdgeShape();
edgeShape.set(-w/2,-h/2,w/2,-h/2);
fixtureDef3.shape = edgeShape;

bodyEdgeScreen = world.createBody(bodyDef3);
bodyEdgeScreen.createFixture(fixtureDef3);
edgeShape.dispose();

camera = new OrthographicCamera(Gdx.graphics.getWidth(),Gdx.graphics.
getHeight());

world.setContactListener(new ContactListener() {
@Override
public void beginContact(Contact contact) {
// Check to see if the collision is between the second sprite and the bottom of the screen
// If so apply a random amount of upward force to both objects... just because
if((contact.getFixtureA().getBody() == bodyEdgeScreen &&
contact.getFixtureB().getBody() == body2)
||
(contact.getFixtureA().getBody() == body2 &&
contact.getFixtureB().getBody() == bodyEdgeScreen)) {

body.applyForceToCenter(0,MathUtils.random(20,50),true);
body2.applyForceToCenter(0, MathUtils.random(20,50), true);
}
}

@Override
public void endContact(Contact contact) {
}

@Override
public void preSolve(Contact contact, Manifold oldManifold) {
}

@Override
public void postSolve(Contact contact, ContactImpulse impulse) {
}
});
}

@Override
public void render() {
camera.update();
// Step the physics simulation forward at a rate of 60hz
world.step(1f/60f, 6, 2);

sprite.setPosition((body.getPosition().x * PIXELS_TO_METERS) - sprite.
getWidth()/2 ,
(body.getPosition().y * PIXELS_TO_METERS) -sprite.getHeight()/2 );

sprite.setRotation((float)Math.toDegrees(body2.getAngle()));
sprite2.setPosition((body2.getPosition().x * PIXELS_TO_METERS) - sprite2.
getWidth()/2 ,
(body2.getPosition().y * PIXELS_TO_METERS) -sprite2.getHeight()/2 );
sprite2.setRotation((float)Math.toDegrees(body.getAngle()));

Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

batch.setProjectionMatrix(camera.combined);
batch.begin();

batch.draw(sprite, sprite.getX(), sprite.getY(),sprite.getOriginX(),
sprite.getOriginY(),
sprite.getWidth(),sprite.getHeight(),sprite.getScaleX(),sprite.
getScaleY(),sprite.getRotation());
batch.draw(sprite2, sprite2.getX(), sprite2.getY(),sprite2.getOriginX(),
sprite2.getOriginY(),
sprite2.getWidth(),sprite2.getHeight(),sprite2.getScaleX(),sprite2.
getScaleY(),sprite2.getRotation());
batch.end();
}

@Override
public void dispose() {
img.dispose();
world.dispose();
}
}

And when you run it

Click to open in new Window (It's probably already run by the time you scrolled down)

In this example we’ve added another dynamic physics body.  Both bodies fall thanks to gravity, however when the second physics body makes contact with the “ground”, an upward force is applied to both bodies.

The heart of this example is the ContactListener we added to our physics world.  This handler is called for each collision that occurred in the world and allows you to handle the event before and after contact, then before and after the physics engine does the calculations on what to do.  In this example we used the beginContact callback, although truth is, all 4 would have behaved identically.  In each case a Contact object is passed in, which has details on the collision such as the friction, restitution and speed of the collision.  In this case we actually want to check what types of objects collided, which we do using getFixtureA() and getFixtureB() which returns the FixtureDef of the colliding objects.  Since we don’t actually know which collides with which, we test for both directions of collisions.  If the bodies colliding are Body2 and bodyEdgeScreen, we apply our upward force.  Obviously you could handle whatever kind of calculation you wanted at this point.

One very common activity, and something I didn’t cover in this example is tying a physics body back to the object in the real world that this body represents.  In this particular example we’ve simply hard coded things, but in a real life application this isn’t an option.  Fortunately there is an easy elegant solution.  Each physics Body has a property called UserData, which can be basically whatever you want it to be.  Let’s take a quick look at storing the game sprite using UserData of the physics Body.

        //Create the body
body = world.createBody(bodyDef);
//Store the sprite the body represents in UserData
body.setUserData(sprite);
//Access the sprite
((Sprite)body.getUserData()).setPosition(body.getPosition().x,body.getPosition().y);

This provides an easy way to link the object represented with the physics entity itself.

So far we covered dynamic objects, which can be moved and positioned and participate in the physics simulation, and static bodies, that do not move but can participate in the simulation, what what happens if you want a body to be aware of the physics simulation, but not effect it.  For example, what if you wanted to trigger some code when a physics body went off screen, but you didn’t want this to cause a collision.  There is a very simple solution to this, sensors.

        fixtureDef.isSensor = true;

This is all you need to do an now your physics object will no longer cause a reaction when collided with, except whatever you provide in code.  For example, in the earlier example, if you changed fixtureDef3 to be a sensor, the first body will simply fall through it.  However when the second body hits it, it will trigger the code in our ContactListener.

If you thought to yourself, wow, that’s an ugly way to handle tests for collisions between different objects… that whole test in both directions thing will get awfully ugly quickly.  You are 100% correct, fortunately there is a clean solution I will cover shortly.

23. September 2014

In the previous particle tutorial I used something called a tween followed by the instructions “don’t worry about it, I will cover them later”.  Well, welcome to later!

First off, what exactly is a tween?  It’s actually probably exactly what you expect it is, basically it’s “between” turned into a verb.  Tweens are all about transitioning from one state to another, and they are incredibly handy.  Let’s just straight in with an example:

/// <reference path="phaser.d.ts"/>
class SimpleGame {
game: Phaser.Game;
sprite: Phaser.Sprite;

constructor() {
this.game = new Phaser.Game(640, 480, Phaser.AUTO, 'content', {
});
}

}
render() {
}
create() {
{ x: 400 }, 5000, Phaser.Easing.Linear.None, true, 0, Number.MAX_VALUE, true);
}
}

var game = new SimpleGame();
};

This example shows a to() tween, which is it tweens between the initial value and the value you specify.  When creating a tween, you pass in the option you wish to tween, in this case a Phaser.Sprite.  The first value are the properties we wish to tween, in this cases sprite’s x value.  Next we tell it how long to take ( 5 seconds ), then pass in the easing function we want to use, in this case none ( which by the way, would have been the default value ), next is the delay before beginning ( right away ), how many times to perform ( infinite ) the tween, then finally we pass true to bounce.  Bounce says after you are done the tween, go back to the beginning.

And here is the result

As you can see the image moves across the screen until it’s x value is 400.

Now let’s take a look at how the easing function affects the tween.  Instead of no easing function, let’s apply an elastic band type affect.  We use InOut, which means it will ease at the beginning and end of the Tween.

    create() {
Phaser.Easing.Elastic.InOut, true, 0, Number.MAX_VALUE, true);
}

And the result:

Tweens don't have to be limited to positioning items either, you can tween just about any value. For example, let’s instead tween the alpha value of our sprite:

    create() {
}

And the result

You can also chain together tweens to perform a series of transitions:

    create() {
.to({ x: 400 }, 2000)
.to({ y: 250 }, 2000)
.to({ x: 0 }, 2000)
.to({ y: 0 }, 2000).loop().start();
}

Resulting in:

Tweens also have event handlers attached. Here for example is a tween that has an onStart and onComplete event handler, that fire before and after the tween completes respectively.

    create() {
tween.to({ x: 400 });

this.sprite.scale.setMagnitude(0.5);
});
},this);
tween.start();
}

Tweens provide a pretty powerful but simple way of adding actions, either in sequence or parallel, to your game’s contents.

22. September 2014

Today we are going to look at adding game pad support into LibGDX, specifically the XBox 360 controller.  Why the Xbox 360 controller?  Well, it’s the controller that I ( and 90% of other PC gamers it seems ) own.  You should be able to modify the following to work with any gamepad, but it’s left as an exercise for the viewer.

There are two things we need to be aware of right away.  First, Controller support is via an extension, so when you are creating your project, you need to select Controller like so:

Next, LibGDX doesn’t actually support the 360 controller out of the box, it only ships with mappings for the Ouya controller.  Fortunately, thanks to the power of Google, I found someone else to do the work for us!  There is a code sample midway through this thread.  Download the included source and save it to a file named XBox360Pad.java.  Yes, case is important.  So it should look like this:

package com.gamefromscratch;

// This code was taken from http://www.java-gaming.org/index.php?topic=29223.0
// With thanks that is!

{
/*
* It seems there are different versions of gamepads with different ID
Strings.
* Therefore its IMO a better bet to check for:
* if (controller.getName().toLowerCase().contains("xbox") &&
controller.getName().contains("360"))
*
* Controller (Gamepad for Xbox 360)
Controller (XBOX 360 For Windows)
Controller (Xbox 360 Wireless Receiver for Windows)
Controller (Xbox wireless receiver for windows)
XBOX 360 For Windows (Controller)
Xbox Receiver for Windows (Wireless Controller)
Xbox wireless receiver for windows (Controller)
*/
//public static final String ID = "XBOX 360 For Windows (Controller)";
public static final int BUTTON_X = 2;
public static final int BUTTON_Y = 3;
public static final int BUTTON_A = 0;
public static final int BUTTON_B = 1;
public static final int BUTTON_BACK = 6;
public static final int BUTTON_START = 7;
public static final PovDirection BUTTON_DPAD_UP = PovDirection.north;
public static final PovDirection BUTTON_DPAD_DOWN = PovDirection.south;
public static final PovDirection BUTTON_DPAD_RIGHT = PovDirection.east;
public static final PovDirection BUTTON_DPAD_LEFT = PovDirection.west;
public static final int BUTTON_LB = 4;
public static final int BUTTON_L3 = 8;
public static final int BUTTON_RB = 5;
public static final int BUTTON_R3 = 9;
public static final int AXIS_LEFT_X = 1; //-1 is left | +1 is right
public static final int AXIS_LEFT_Y = 0; //-1 is up | +1 is down
public static final int AXIS_LEFT_TRIGGER = 4; //value 0 to 1f
public static final int AXIS_RIGHT_X = 3; //-1 is left | +1 is right
public static final int AXIS_RIGHT_Y = 2; //-1 is up | +1 is down
public static final int AXIS_RIGHT_TRIGGER = 4; //value 0 to -1f
}

Now let's jump right in with a sample:

package com.gamefromscratch;

SpriteBatch batch;
Sprite sprite;
BitmapFont font;
boolean hasControllers = true;
String message = "Please install a controller";

@Override
public void create () {
batch = new SpriteBatch();
sprite.setPosition(Gdx.graphics.getWidth()/2 -sprite.getWidth()/2,
Gdx.graphics.getHeight()/2-sprite.getHeight()/2);

// Listen to all controllers, not just one

font = new BitmapFont();
font.setColor(Color.WHITE);

if(Controllers.getControllers().size == 0)
{
hasControllers = false;
}
}

@Override
public void render () {
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
if(!hasControllers)
font.draw(batch,message,
Gdx.graphics.getWidth()/2 - font.getBounds(message).width/2,
Gdx.graphics.getHeight()/2 - font.getBounds(message).height/2);
else
batch.draw(sprite, sprite.getX(), sprite.getY(),sprite.getOriginX(),sprite.getOriginY(),
sprite.getWidth(),sprite.getHeight(),
sprite.getScaleX(),sprite.getScaleY(),sprite.getRotation());
batch.end();
}

// connected and disconnect dont actually appear to work for XBox 360 controllers.
@Override
public void connected(Controller controller) {
hasControllers = true;
}

@Override
public void disconnected(Controller controller) {
hasControllers = false;
}

@Override
public boolean buttonDown(Controller controller, int buttonCode) {
sprite.setY(sprite.getY() + 1);
sprite.setY(sprite.getY()-1);
sprite.setX(sprite.getX() - 1);
sprite.setX(sprite.getX() + 1);

sprite.scale(-0.1f);
sprite.scale(0.1f);
return false;
}

@Override
public boolean buttonUp(Controller controller, int buttonCode) {
return false;
}

@Override
public boolean axisMoved(Controller controller, int axisCode, float value) {
// This is your analog stick
// Value will be from -1 to 1 depending how far left/right, up/down the stick is
// For the Y translation, I use a negative because I like inverted analog stick
// Like all normal people do! ;)

// Left Stick
sprite.translateX(10f * value);
sprite.translateY(-10f * value);

// Right stick
sprite.rotate(10f * value);
return false;
}

@Override
public boolean povMoved(Controller controller, int povCode, PovDirection value) {
sprite.translateX(-10f);
sprite.translateX(10f);
sprite.translateY(10f);
sprite.translateY(-10f);
return false;
}

@Override
public boolean xSliderMoved(Controller controller, int sliderCode, boolean value) {
return false;
}

@Override
public boolean ySliderMoved(Controller controller, int sliderCode, boolean value) {
return false;
}

@Override
public boolean accelerometerMoved(Controller controller, int accelerometerCode, Vector3 value) {
return false;
}
}

Amazingly enough, LibGDX actually manages to support controllers in their HTML target, so below is the following code running.  Maybe.

Of course, this is gamepad support in HTML5 we are talking about here, so it will only work in a very small subset of browsers and certainly may not work as expected.  However, the fact it runs at all is rather astonishing.  You may need to open the examples in a separate window using the link above to get it to work correctly.  No worries though, on a Desktop target, the above code works perfectly.

In this sample we are taking an event driven approach.  That is, as the controller is updated, it pushes a variety of events to our class.  This is done via the ControllerListener interface.  As you can see from the override’s, there is a great deal of functionality ( motion, sliders, etc ) that is OUYA specific.  Of interest to us are buttonDown, axisMoved and povMoved.  buttonDown is called predictably enough when one of the controller buttons is pressed, this includes face buttons, select, start and the bumpers, but not the triggers.  axisMoved is called for either of the analog sticks, and perhaps confusingly at first, the triggers are moved.  The reason triggers are supported this way is do the the fact there is a range of values instead of just a binary option like when dealing with buttons.  The amount the trigger is depressed is the range along the trigger axis.  Finally there is povMoved, this is your DPad, which really is just a set of 4 buttons.  One last thing to note here… the disconnect and connect events simply never fired for me, the logic may be OUYA specific.

You may notice however that movement using the analog stick is jerky as hell.  This is because event driven approach isn’t really ideal for analog controls.  You have two options here.  Instead of updating the controls each time an event is fired, you update a flag and apply some smoothing logic, to keep movement between events smooth.  Or, much easier, you use polling instead.  Let’s take a look at how you can poll controls in LibGDX.

package com.gamefromscratch;

SpriteBatch batch;
Sprite sprite;
Controller controller;
BitmapFont font;
boolean hasControllers = true;
String message = "Please install a controller";

@Override
public void create () {
batch = new SpriteBatch();
sprite.setPosition(Gdx.graphics.getWidth()/2 -sprite.getWidth()/2,
Gdx.graphics.getHeight()/2-sprite.getHeight()/2);

font = new BitmapFont();
font.setColor(Color.WHITE);

if(Controllers.getControllers().size == 0)
{
hasControllers = false;
}
else
controller = Controllers.getControllers().first();
}

@Override
public void render () {
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
if(!hasControllers)
font.draw(batch,message,
Gdx.graphics.getWidth()/2 - font.getBounds(message).width/2,
Gdx.graphics.getHeight()/2 - font.getBounds(message).height/2);
else {
// Update movement based on movement of left stick
// Give a "deadzone" of 0.2 - -0.2, meaning the first 20% in either direction will be ignored.
// This keeps controls from being too twitchy
// Move by up to 10 pixels per frame if full left or right.
// Once again I flipped the sign on the Y axis because I prefer inverted Y axis controls.

// Poll if user hits start button, if they do, reset position of sprite
sprite.setPosition(Gdx.graphics.getWidth() / 2 - sprite.getWidth() / 2,
Gdx.graphics.getHeight() / 2 - sprite.getHeight() / 2);
batch.draw(sprite, sprite.getX(), sprite.getY(), sprite.getOriginX(), sprite.getOriginY(),
sprite.getWidth(),sprite.getHeight(),
sprite.getScaleX(), sprite.getScaleY(), sprite.getRotation());
}
batch.end();
}
}

Now here is this code running ( sorta, maybe )

Here you can see we simply poll the controller for it’s status each frame.  getAxis returns the amount the controller is depressed in either direction along that axis as a value from –1 to 1.  getButton on the other hand returns a boolean representing if the button is currently pressed or not.  One important thing to keep in mind here, this code is incredibly fragile.  LibGDX controller supports multiple controllers, but in this case I simply check to see if any exist and use the first one I can find.  This means if you have multiple controllers plugged into your PC, all but the first one will be ignored.  Second, this code simply assumes the controller is an XBox 360 controller, no idea what will happen if another controller is used instead.  Most likely the worst case scenarios is buttons might be mismapped or non-existent.

The only other thing of note ( and mentioned in the comments ) is I applied a dead zone value of –0.2 to 0.2 for each analog stick.  This keeps the controller from being overly twitchy and from moving when the user would think the control should be still.  Generally this dead zone value is what you would configure via a sensitivity setting in your game’s settings.  I also flipped the Y axis value because, well, that’s the way it should be! :)