Bullet Physics Tutorial: Getting Started

Kirill Muzykov Kirill Muzykov
Learn how to integrate the Bullet physics engine into your games!

Learn how to integrate the Bullet physics engine into your games!

In this Bullet physics tutorial, you’re going to learn how to use the Bullet physics engine in your iOS games.

Bullet physics is a powerful open source physics engine. It has been used in many Hollywood movies like Megamind and Shrek 4, and popular games like the Grand Theft Auto series.

Bullet physics differs from other physics engines you may have heard of like Box2D, Chipmunk, or Sprite Kit’s physics engine, because this physics engine is 3D, not 2D! Bullet physics has a long list of cool features, including 3D collision detection, soft body dynamics and rigid body dynamics. If you don’t know what those things entail, you will soon!

In this tutorial, you will add Bullet physics into a very simple OpenGL iOS breakout game. Step by step, you will replace the old custom code for ball movement and collisions with new code that calls on the Bullet physics library to do a real physics simulation.

By the time you’re finished, you’ll have learned how to:

  • Download and build Bullet physics engine source code.
  • Set up an Xcode project to use the Bullet physics libraries.
  • Set up a physics simulation, create physical objects and make them move and rotate.
  • Detect collisions, get collision information and destroy objects.

This Bullet physics tutorial assumes you are familiar with at least the basics of OpenGL development on iOS. If you are completely new to OpenGL or iOS development, check out our Beginning OpenGL ES 2.0 with GLKit tutorial series first.

Getting Started with Bullet

Start by downloading the starter project for this tutorial. Unzip the project, and build and run. You will see a very simple Breakout game like the following (you can move the paddle by dragging):

Breakout Game

After you play the game a bit, check out the sample project. Here’s a quick tour of the code:

  • RWGameScene.m: The main gameplay code for the game is in here. initWithShader: adds all of the objects to the scene, and updateWithDelta: performs the movement, collision handling, and win/lose detection.
  • RWNode.m: This class contains the OpenGL code to render a model. It has various subclasses (RWBall, RWPaddle, etc) that pass in a list of vertices for each model. The models were created in Blender, and Ray wrote a command-line tool to generate header files with the vertices from the OBJ files exported from Blender.

Once you have a good understanding of how this project is put together, move the starter project to your desktop so it’s in a known location. You should wind up with something like this:

Setting_up_root_folder

Downloading the Bullet Source Code

Now let’s download some bullets. :] Well, in fact, only one Bullet, but it’s packed with all the source code.

Visit https://code.google.com/p/bullet/downloads/list and grab the latest version of Bullet. At the time of writing this tutorial, this is bullet-2.82-r2704.tgz, but it may have been updated by the time you read this so just download the latest.

Note: Make sure to get the file with the Unix line endings, since Mac OS X is Unix based.

Bullet download list

After the download is complete, unpack the archive contents to your BulletBreakout folder.

You’ll have something like this:

Bullet copying source code to root folder

Installing the Build Tool

Bullet uses the CMake build tool to build its codebase, so you need to have this tool downloaded and installed. If you already have CMake, you can skip this section.

Note: You can test to see if you have cmake installed by typing cmake in a Terminal window. If you see a bunch of help output, you have it installed!

Visit http://www.cmake.org/cmake/resources/software.html and download the .dmg package called Mac OSX 64/32-bit Universal (for Intel, Snow Leopard/10.6 or later) from the Binary distributions category.

cmake_download

When the download completes, double-click on the cmake-2.8.12-Darwin64-universal.dmg file and it will mount a disk with the installation package.

cmake_install_package

Double-click on the installation package cmake-2.8.12-Darwin64-universal.pkg and it will open the installer.

cmake_installer_window

Simply follow the installation steps until the installation completes.

Now you have CMake installed and you can proceed to building the Bullet source code.

Building Bullet

To build the source code, follow these steps:

Open Terminal, and change to the build subdirectory of the bullet subdirectory inside your BulletBreakout project folder. For me, it looks like this, but if you downloaded a more recent version yours may be slightly different:

>cd ~/Desktop/BulletBreakout/bullet-2.82-r2704/build/

Then run the ios_build.sh shell script with the following command:

>./ios_build.sh

After the script finishes running, you should see a ** BUILD SUCCEEDED ** message.

Bullet build succeeded

That’s it! You’re ready to integrate Bullet into your game.

Adding Bullet Libraries to an Xcode Project

In this section, you’re going to add the Bullet libraries to the Breakout game project. Open the Breakout project in Xcode, and then open a Finder window next to Xcode and navigate to the build/xcode4ios folder inside your bullet subdirectory.

Bullet library directory

Drag the following projects over to the Breakout project name in Xcode:

  • LinearMath.xcodeproj
  • BulletDynamics.xcodeproj
  • BulletCollision.xcodeproj

Here’s how it should look:

Dragging libraries into Xcode

When you’re done, you should have something like this:

Bullet projects added in Xcode

Now you need to add a header search path to the main project so your project knows where to find the Bullet headers. To do so, click your Breakout project in the project navigator, and select the Breakout target. Navigate to the Build settings tab, and double click the Search Paths\User Header Search Paths entry.

Use the + button to add a new entry, and add the path to the src subdirectory of your Bullet folder. For me, this was $(SRCROOT)/bullet-2.81-rev2613/src (don’t add quotes), but remember yours may be slightly different if you downloaded a more recent version of Bullet.

Adding bullet header search path to Xcode project

Finally, you need to link your project with the Bullet libraries. First you need to add the Bullet projects as dependencies of your project so that they will be built before you build your project. To do this, select your Breakout project and target, select the Build Phases tab, and inside the Target Dependencies section click the + button. Select the three Bullet projects, and click Add.

Adding Bullet projects as dependencies

Next, still in the Build Phases tab, expand the Link Binary With Libraries section. Click the plus (+) button at the bottom of the section, as shown in the picture below.

linking_with_libraries_1

In the pop-up dialog, select the three Bullet libraries you added earlier. You can click on the first one and then SHIFT+click on the third one to select all three. Click the Add button.

linking_with_libraries_2

You should wind up with something like this:

link_with_libraries_3

Now Clean (Product/Clean) and Build the project. If you’re targeting the Simulator, you won’t have any errors, but if you’re targeting an iOS device, you may see one or more warnings that later will become errors. You’re going to fix those now.

oh_no_warnings2

Fixing Architecture Configuration Errors

As mentioned in the previous section, you may see one or more errors that look like this:

build_warnings

These only appear when you build targeting a device, but since sooner or later you will want to build your project for devices (archiving for App Store submission also counts), you’ll have to fix them.

You are getting these errors because Bullet projects, which you imported as sub-projects, have outdated architecture settings. When you target a device the libraries cannot be built, and this means that you don’t actually get the libraries as a result of building those projects and cannot use them.

For now these are only warnings, because you haven’t written any code that uses Bullet in your project yet. But as soon as you do, the warnings will become errors, because the linker won’t be able to use the libraries you’re referencing.

Follow these steps to fix those errors:

  1. Click on the BulletCollision.xcodeproj project in Navigator.
  2. Select the BulletCollision target if it is not already selected by default.
  3. Make sure the Build Settings tab is opened.
  4. Click on the Architectures list item and change the armv7 setting to Standard architectures (armv7, armv7s) from the drop-down list.
  5. Then double-click on armv7 on the Valid Architectures line.
  6. In the dialog that opens, add lines for armv7s and arm64.

fixing_errors

Now follow the same steps for the BulletDynamics.xcodeproj and LinearMath.xcodeproj projects.

Once you have changed the architecture settings for all three libraries, build the project. This time,
you should get no errors or warnings on your project (you may get some warnings from the Bullet code itself, but that is OK).

got_libraries

Physics Worlds

Very soon now, you’ll actually write some code. And in so doing, you’ll create a whole new world!

You’re not going to use anyone’s rib, or fly on a magic carpet like Aladdin. :] You’re going to create a world for your physics objects.

A whole new (physics) world!

A whole new (physics) world!

When speaking about a physics engine, the world itself is an object, one that plays a special role in the simulation. You can think of the world as a container for the other physics objects. In addition to holding all the objects, the world is responsible for simulating the physics of how the objects interact.

The usual approach for this simulation is the so-called stepping the world technique. Real physical time seems to be infinitely divisible – given any two moments, you can imagine describing a third moment in between them. But since no computer can simulate an infinite number of moments, your physics engine will simulate a regular sequence of moments, just like the ticking second hand of a clock.

This simply amounts to implementing a method, update:(float)deltaTime, that updates the positions and orientations of all the objects in the world to reflect how they moved over deltaTime.

In essence, you are passing delta time, the time since the last update, to the world and asking it to simulate what happened during that interval. Each such call is called a step. During a step, many things can happen: an object might change position or rotation due to some force applied, several objects might collide and so on.

Enough theory – it’s time to create the world!

Creating the World

Rename the RWGameScene.m file to RWGameScene.mm – that is, change the extension to .mm. You’re going use some C++ in your code and renaming the file to .mm will notify Xcode to compile this file using Objective-C++ and support your C++ code.

Add the btBulletDynamicsCommon.h header at the top of RWGameScene.mm:

#include "btBulletDynamicsCommon.h"

In the @implementation part, add several instance variables. You’ll find out what they’re for later on.

@implementation RWGameScene {
    //Skipped...
 
    //New variables
    btBroadphaseInterface*                  _broadphase;
    btDefaultCollisionConfiguration*        _collisionConfiguration;
    btCollisionDispatcher*                  _dispatcher;
    btSequentialImpulseConstraintSolver*    _solver;
    btDiscreteDynamicsWorld*                _world;
}

Build your project now. If the project builds without any other errors, continue adding code. If you find errors other than the ones mentioned above, please check that you’ve followed all the steps above correctly. At this point you should only get other errors if you haven’t properly included the Bullet libraries or didn’t specify search paths.

Note: It is important to build projects as frequently as you can to detect errors as soon as possible. For instance, right now you might see a couple of warnings regarding Conversion from string literal to ‘char *’ is deprecated’. These are from code from the starter project. You can ignore them, or you can fix them by changing two method parameters and an instance variable declaration from char * to const char *.

Add the following function somewhere in RWGameScene.mm:

-(void)initPhysics
{
    //1
    _broadphase = new btDbvtBroadphase();
 
    //2
    _collisionConfiguration = new btDefaultCollisionConfiguration();
    _dispatcher = new btCollisionDispatcher(_collisionConfiguration);
 
    //3
    _solver = new btSequentialImpulseConstraintSolver();
 
    //4
    _world = new btDiscreteDynamicsWorld(_dispatcher, _broadphase, _solver, _collisionConfiguration);
 
    //5
    _world->setGravity(btVector3(0, -9.8, 0));
}

Here is an explanation of what this method does:

  1. You instantiate the broad phase algorithm implementation.

    Collision detection is done in two phases: broad and narrow. In the broad phase, the physics engine quickly eliminates objects that cannot collide. For example, it can run a quick check to using the bounding boxes of objects, eliminating those that don’t collide. It then passes only a small list of objects that can collide to the narrow phase, which is much slower, since it checks actual shapes for collision.

    Bullet has several built-in implementations of the broad phase. In this tutorial, you’re using the dynamic AABB tree implementation – i.e. btDbvtBroadphase.

    You can read more about the broad phase here.

  2. collisionConfiguration is responsible for full, not broad, collision detection. In other words, this is where the more fine-grained and accurate collision detection code runs. You could create your own implementation, but for now you’re using the built-in configuration again.
  3. Here is an excerpt from the Bullet “Hello World” sample, which has a good explanation of _solver:

    This is what causes the objects to interact properly, taking into account gravity, game logic supplied forces, collisions, and hinge constraints. It does a good job as long as you don’t push it to extremes, and is one of the bottlenecks in any high performance simulation. There are parallel versions available for some threading models.

    You’re going to use the btSequentialImpulseConstraintSolver solver, which the “Hello World” sample uses.

  4. Finally you create the world, passing in the configuration options you created earlier.
  5. The last step is to set the world’s gravity. For now, it will be same gravity as we have here on Earth. The y-vector points up, so btVector3(0, -9.8, 0), which is a 3-component vector (x,y,z), will point down with a magnitude of 9.8.

That’s almost it for the world. Fortunately it isn’t going to require seven days. :]

Now you need to add a call to your initPhysics method. Add it somewhere at the beginning of the initWithShader: function in RWGameScene.mm:

- (instancetype)initWithShader:(GLKBaseEffect *)shader {
    if ((self = [super initWithName:"RWGameScene" shader:shader vertices:nil vertexCount:0])) {
 
        // Add call here
        [self initPhysics];
 
        //Rest of the function is skipped....
}

And as a final step, you need to free the storage of everything created with the C++ new operator. Remember, things you allocate with new are not managed by ARC – it’s up to you! So add a dealloc method somewhere in RWGameScene.mm:

- (void)dealloc
{    
    delete _world;
    delete _solver;
    delete _collisionConfiguration;
    delete _dispatcher;
    delete _broadphase;
}

Build and run the game. You won’t see any changes, but if the game doesn’t crash then everything works fine. You’ve created your world!

kid_world

Rigid Bodies

I’ll use the definition of a rigid body from the Bullet wiki:

A “rigid body” is what it sounds like – an item of fixed mass, size, and other physical properties. It’s the base individual item in physics simulations.

In addition to rigid bodies, Bullet supports soft bodies:

Imagine a rigid body, but squidgy. The mass doesn’t change, but the shape of it can.

In this tutorial, you’re going to use only rigid bodies. After all, in Breakout the boxes and ball aren’t squishy! From here forward, when I say body or physics body, I mean a rigid body.

Okay, back to your game. Now that there is a world, you need to fill it with objects. Every simulated object must have a body. You’ll have several physics-enabled objects with rigid bodies:

  • Ball
  • Paddle
  • Border
  • Brick

All of these objects will share common code, so it would be nice if they could have a common parent class, but you also want to keep their existing properties.

The best way to do this is to create a special class called PNode (for “physics node”) and inherit it from RWNode. All physics objects will inherit from PNode and will have the best of both worlds! Just as RWNode represented a visual object for your earlier custom code describing object interactions in the game, the PNode superclass will represent the basic idea of a physical object, to be manipulated by the Bullet physics simulation engine.

Creating the PNode Class

Switch to Xcode if you don’t have it open already and create a new Objective-C class called PNode. Make it a subclass of RWNode and put it in the Nodes group alongside RWNode.

pnode_creation

Right after that, rename PNode.m to PNode.mm. Yes, you’re going to write some C++ code again.

Open PNode.h and include this header at the top, right after #import “RWNode.h”:

#import "RWNode.h"
#include "btBulletDynamicsCommon.h"

Add the following init method right after the @interface line:

- (instancetype)initWithName:(char *)name
                        mass:(float)mass   //1
                      convex:(BOOL)convex  //2
                         tag:(int)tag      //3
                      shader:(GLKBaseEffect *)shader
                    vertices:(Vertex *)vertices
                 vertexCount:(unsigned int)vertexCount
                 textureName:(NSString *)textureName
               specularColor:(GLKVector4)specularColor
                diffuseColor:(GLKVector4)diffuseColor
                   shininess:(float)shininess;

I’ve marked new parameters with numbered comments. Here is some brief information about each of them:

  1. mass is pretty obviously the mass of the object, but it has another not-so-obvious significance. In Bullet, you can have three types of objects, depending on their mass:
    • The mass of a static object equals zero. These are immovable objects. In your game, the border is a static object.
    • The mass of a kinematic object also equals zero, but you can move such objects with code by explicitly setting their position and rotation. In your game, the paddle and bricks are kinematic objects.
    • The mass of a dynamic object is non-zero. You move such objects by applying a force to them. In your game, the ball is a dynamic object. You’ll set its direction and velocity and let the physics engine do the work. When the ball hits a border or a brick, it will bounce back, but it can never affect the positions of the border, brick or paddle since they are immovable.
  2. convex is a flag describing whether the current physics object is convex or concave. You should always try to use convex objects because physics engines work much faster with them. You can always decompose a concave object into several convex objects.

    For the sake of this tutorial, though, you’ll implement the creation of both convex and concave objects. Since creating convex objects in Bullet differs from creating concave objects, you need a flag.

  3. You are using tag in collision detection to determine what types of objects collided.

Now add two properties right below init in PNode.h:

//1
@property (nonatomic, readonly) btRigidBody* body;
//2
@property (nonatomic, assign)   int tag;

Here are descriptions of these properties:

  1. body is the reference to a rigid body that you’ll create and store in PNode. Using this property, you’ll allow the game scene to work with the physics body of the node.
  2. tag gets you access to the tag value you used to create the current PNode.

It’s time to switch to PNode.mm. Add a new private instance variable:

@implementation PNode {
    btCollisionShape* _shape;
}

_shape describes the shape of the physics body. btCollisionShape is an abstract class, and there are several different implementations of collision shapes. For example, you can describe the shape of an object as a sphere using btSphereShape or you can create complicated shapes with btBvhTriangleMeshShape, specifying vertices of triangles just like you do when rendering complex objects in OpenGL.

Of course, physics engines work faster with simple shapes, so you should try to use as many spheres and planes as possible. In this tutorial, though, you’ll reuse the vertices of the models exported from Blender and create complicated physics shapes with only few lines of code.

You can read more about collision shapes here.

Creating a Body

Body creation consists of two steps:

  1. Create the shape using one of the Bullet classes.
  2. Create the body construction info and use it to actually create the body.

Start with the shape creation method by placing the following in PNode.mm:

-(void)createShapeWithVertices:(Vertex *)vertices count:(unsigned int)vertexCount isConvex:(BOOL)convex
{
    //1
    if (convex)
    {
        //2
        _shape = new btConvexHullShape();
        for (int i = 0; i < vertexCount; i++)
        {
            Vertex v = vertices[i];
            btVector3 btv = btVector3(v.Position[0], v.Position[1], v.Position[2]);
            ((btConvexHullShape*)_shape)->addPoint(btv);
        }
    }
    else
    {
        //3
        btTriangleMesh* mesh = new btTriangleMesh();
        for (int i=0; i < vertexCount; i += 3)
        {
            Vertex v1 = vertices[i];
            Vertex v2 = vertices[i+1];
            Vertex v3 = vertices[i+2];
 
            btVector3 bv1 = btVector3(v1.Position[0], v1.Position[1], v1.Position[2]);
            btVector3 bv2 = btVector3(v2.Position[0], v2.Position[1], v2.Position[2]);
            btVector3 bv3 = btVector3(v3.Position[0], v3.Position[1], v3.Position[2]);
 
            mesh->addTriangle(bv1, bv2, bv3);
        }        
		   _shape = new btBvhTriangleMeshShape(mesh, true);
    }
}

Here’s an explanation of createShapeWithVertices::

  1. It takes different approaches to create convex and concave shapes, which is why you need that flag in init as well as this check.
  2. In case of a convex object, you use btConvexHullShape. This class allows you to add all points of the object and uses them to automatically create the minimum convex hull for it.
  3. In case of a concave object, you use a more complicated class called btBvhTriangleMeshShape. This class requires the creation of a mesh object consisting of triangles. In this step, you gather triangles by grouping vertices from the list of vertices. Then you create a mesh and create a shape object from this mesh.

Next you need to write a method creating the body of the object. Place the following method in PNode.mm, right below createShapeWithVertices:

-(void)createBodyWithMass:(float)mass
{
    //1
    btQuaternion rotation;
    rotation.setEulerZYX(self.rotationZ, self.rotationY, self.rotationX);
 
    //2
    btVector3 position = btVector3(self.position.x, self.position.y, self.position.z);
 
    //3
    btDefaultMotionState* motionState = new btDefaultMotionState(btTransform(rotation, position));
 
    //4
    btScalar bodyMass = mass;
    btVector3 bodyInertia;
    _shape->calculateLocalInertia(bodyMass, bodyInertia);
 
    //5
    btRigidBody::btRigidBodyConstructionInfo bodyCI = btRigidBody::btRigidBodyConstructionInfo(bodyMass, motionState, _shape, bodyInertia);
 
    //6
    bodyCI.m_restitution = 1.0f;
    bodyCI.m_friction = 0.5f;
 
    //7
    _body = new btRigidBody(bodyCI);
 
	//8
    _body->setUserPointer((__bridge void*)self);
 
    //9
    _body->setLinearFactor(btVector3(1,1,0));
}

This code definitely won’t suffer from a little description:

  1. You specify the object’s rotation. Bullet uses quaternions to represent object rotation. Quaternions are a complicated topic and this tutorial will not cover them. For now, just remember that a quaternion holds information about the object’s rotation.

    I strongly advise you to understand quaternions, since most 3D games use them for rotations. There is a good tutorial from Ray that covers rotations and quaternions here.

  2. You specify the object’s position. At this point, both position and rotation are set to zero in super init, but it’s better to use property values in case you change position and rotation initialization in RWNode’s init.
  3. MotionState is a convenient class that allows you to sync a physical body and with your drawable objects. You don’t have to use motion states to set/get the position and rotation of the object, but doing so will get you several benefits, including interpolation and callbacks.

    For the sake of simplicity, you won’t use motion state in this game, so here you just create and use the default implementation. You can read more about motion states
    here.

  4. You set the mass and inertia values for the shape. You don’t have to calculate inertia for your shape manually. Instead you are using a utility function that takes a reference, btVector3, and sets the correct inertia value using the shape’s data.
  5. To create a body, you have to fill out ConstructionInfo. This structure contains all the required properties to construct the body. Think of it as a convenience. You pass one structure to the constructor instead of having dozens of parameters, most of which you will set to default values.
  6. ConstructionInfo takes only a couple of important parameters and sets all other properties to default values. You need to change a few properties. bodyCI.m_restitution sets an object’s bounciness. Imagine dropping a ball – a sphere – to the floor:

    • With a value of 0.0, it doesn’t bounce at all. The sphere will stick to the floor on the first touch.
    • With a value between 0 and 1, the object bounces, but with each bounce loses part of its energy. The sphere will bounce several times, each time lower than the previous bounce until finally it stops.
    • With a value of more than 1, the object gains energy with each bounce. This is not very realistic, or at least I can’t think of a real-life object that behaves this way. Your sphere will bounce higher than the point from which it was dropped, then it will bounce even higher and so on, until it bounces right into space.

    Setting the property bodyCI.m_friction to non-zero will make the ball spin, just like it would in real life if you launch the ball into a wall at some angle other than 90 degrees.

  7. You’ve gathered everything to create a body, and here you’re doing just that. There’s not much of interest here, since you’re just passing ConstructionInfo holding all the parameters you set earlier.
  8. Here you save a reference to the PNode class in the body object. When you process collisions, I’ll show you how to get it back.

    This is important moment. Sometimes you only have access to a physics body – for example, when Bullet calls your callback and passes you the body – but you want to get the node object that holds this body. In this line, you’re making that possible.

  9. Here’s another interesting moment. You’re limiting object movement to a 2D plane (x,y). Breakout is actually a 2D game with 3D models, and all objects have to be in one plane to make collisions work. This keeps your ball and other objects from bouncing somewhere along the z-axis.

Initializing the PNode Class

Now that you have all the methods to construct a body, it’s time to write the init method. Add it right after the instance variable declarations in PNode.mm:

- (instancetype)initWithName:(char *)name
                        mass:(float)mass
                      convex:(BOOL)convex
                         tag:(int)tag
                      shader:(GLKBaseEffect *)shader
                    vertices:(Vertex *)vertices
                 vertexCount:(unsigned int)vertexCount
                 textureName:(NSString *)textureName
               specularColor:(GLKVector4)specularColor
                diffuseColor:(GLKVector4)diffuseColor
                   shininess:(float)shininess
{
    //1
    if (self = [super initWithName:name shader:shader vertices:vertices vertexCount:vertexCount textureName:textureName specularColor:specularColor diffuseColor:diffuseColor shininess:shininess])
    {
 
        //2
        self.tag = tag;
 
        //3
        [self createShapeWithVertices:vertices count:vertexCount isConvex:convex];
 
        //4
        [self createBodyWithMass:mass];
    }
    return self;
}

This method is fairly simple, since you’re calling methods you created earlier.

  1. You call the parent init and simply pass through all the properties not related to physics.
  2. You save the tag value in a property.
  3. You create the shape object from the passed vertices array using the function you created above.
  4. Finally, you create a body using the specified mass.

Now you only need to add a dealloc to clean up your C++ resources and you’ll be done with this section.

Add the dealloc method at the end of PNode.mm:

- (void)dealloc
{
    if (_body)
    {
        delete _body->getMotionState();
        delete _body;
    }
 
    delete _shape;
}

Build and Run the project. You still won’t see anything different, but don’t worry – you’re going to change that in the next section of the tutorial.

Making the Ball Fall

It’s time to see Bullet physics in action!

Before you modify the ball node to use physics, you need to create a tag for it, since PNode’s init requires one.

Switch to PNode.h and add the following #defines right before the @interface line:

#define kBallTag    1
#define kBrickTag   2
#define kPaddleTag  3
#define kBorderTag  4

This way, you’ve defined tags for all the game objects.

Modifying a Node to Use Physics

Go to RWBall.h and change it to the following.

//1
#import "PNode.h"
 
//2
@interface RWBall : PNode
 
- (id)initWithShader:(GLKBaseEffect *)shader;
 
@end

You’ve made just two simple changes:

  1. You import PNode.h instead of RWNode.h, since you’re going to inherit from PNode.
  2. You change the parent class to PNode.

Now rename RWBall.m to RWBall.mm.

Switch to RWBall.mm and replace initWithShader: with the following:

- (id)initWithShader:(GLKBaseEffect *)shader {
    if ((self = [super initWithName:"Ball"
                               mass: 1.0f       //1
                             convex: YES        //2
                                tag: kBallTag   //3
                             shader:shader
                           vertices:(Vertex *)Ball_Sphere_ball_Vertices
                        vertexCount:sizeof(Ball_Sphere_ball_Vertices)/sizeof(Ball_Sphere_ball_Vertices[0])
                        textureName:@"ball.png"
                      specularColor:Ball_Sphere_ball_specular
                       diffuseColor:Ball_Sphere_ball_diffuse
                          shininess:Ball_Sphere_ball_shininess])) {
        self.width = 1.0;
        self.height = 1.0;
    }
    return self;
}

Now the RWBall class is calling PNode’s init instead of RWNode’s. All you have to do is to specify additional properties required for physics objects:

  1. You set the ball’s mass to 1.0. You can play with this value to see what it does.
  2. The ball is spherical. Since a sphere is a convex shape, you set the convex flag to YES.
  3. You mark the ball with its corresponding tag.

Build the project now and you’ll see you get several strange errors in ball.h, a file with the vertices of the ball model.

Errors in ball.h

You’re getting this error because you’ve changed the extension to RWBall.mm and using some C++, which has different rules regarding global variable initialization.

But there’s an easy fix. Switch to ball.h and add the extern keyword before each variable declaration. You should end up with this:

extern const GLKVector4 Ball_Sphere_ball_ambient;
extern const GLKVector4 Ball_Sphere_ball_diffuse;
extern const GLKVector4 Ball_Sphere_ball_specular;
extern const float Ball_Sphere_ball_shininess;
extern const Vertex Ball_Sphere_ball_Vertices[420];

The extern keyword simply notifies the compiler that, although the variable is defined here, the variable’s value is initialized in ball.m.

Build the project. You should get no errors.

You may see a couple more warnings regarding Conversion from string literal to ‘char *’ is deprecated. Those are totally okay to ignore for now (or you can fix them the way I mentioned earlier in this tutorial).

Adding the Ball to the Physics World

The next step is to add the ball to your physics world.

Switch to RWGameScene.mm and scroll to the place where you create the ball node. Replace these lines:

        _ball = [[RWBall alloc] initWithShader:shader];
        _ball.position = GLKVector3Make(_gameArea.width/2, _gameArea.height * 0.1, 0);
        _ball.diffuseColor = GLKVector4Make(0.5, 0.9, 0, 1);
        _ballVelocityX = 10;
        _ballVelocityY = 10;
        [self.children addObject:_ball];

With the following:

        _ball = [[RWBall alloc] initWithShader:shader];
        _ball.position = GLKVector3Make(_gameArea.width/2, _gameArea.height * 0.1, 0);
        _ball.diffuseColor = GLKVector4Make(0.5, 0.9, 0, 1);
        [self.children addObject:_ball];
        _world->addRigidBody(_ball.body); //Adding ball to world

Notice that final line. When you create the ball object, it calls PNode’s init and at the end of initialization, you already have a physics body that you can access using the body property you created earlier in PNode.

You simply need to add the body to the world. That’s what _world->addRigidBody(_ball.body); does.

Next up is stepping the world. Remember, this is what gives the physics engine time to process the physics simulation and update the positions of each physics body accordingly.

Scroll to updateWithDelta: and replace it with the following:

- (void)updateWithDelta:(GLfloat)aDelta {
    //1
    [super updateWithDelta:aDelta];
 
    //2
    _world->stepSimulation(aDelta);
 
    //3
    NSLog(@"Ball height: %f", _ball.body->getWorldTransform().getOrigin().getY());
}

The method got smaller, didn’t it? :] Well, it will grow a bit larger, but it will still remain smaller than before because the physics engine will do most of the work. Here’s what updateWithDelta: does now:

  1. It calls the parent method, which enumerates children and calls their updateWithDelta:.
  2. Remember what I described earlier? Since you can only update in updateWithDelta:, which is called at some rate, you need to pass to the world the amount of time elapsed since the last step, so that the world can simulate until that point. This exactly what _world->stepSimulation(aDelta); does.
  3. The code logs the ball’s y-position. You’ll see why later – it will be a surprise. :]

Build and run the project, and you’ll see the ball seems to be stuck in space!

BallStuck

But wait! Why is the ball not moving, even though you can see in the Log that its position changes?

2013-10-15 13:41:26.410 Breakout[44391:a0b] Ball height: 0.000000
2013-10-15 13:41:26.575 Breakout[44391:a0b] Ball height: -0.002778
2013-10-15 13:41:26.608 Breakout[44391:a0b] Ball height: -0.008333

2013-10-15 13:41:30.941 Breakout[44391:a0b] Ball height: -24.383337
2013-10-15 13:41:30.975 Breakout[44391:a0b] Ball height: -24.752781

Here is a very important thing to understand: Physics objects are not drawn objects!

There is a physics world where you create bodies and all the simulation happens, but changes to simulated objects are not automatically applied to drawn objects and vice-versa. When you move a drawn object, the related physics object doesn’t move automatically.

This means you have to write some code to synchronize the position of the physics object with the drawn ball. The easiest thing to do is to override the position property of RWNode in the PNode class.

Syncing a Physics Body with a Drawn Object: Position

Switch to PNode.mm and add the following two methods right after dealloc:

//1
-(void)setPosition:(GLKVector3)position
{
    //2
    [super setPosition:position];
 
    //3
    if (_body)
    {
        btTransform trans = _body->getWorldTransform();
        trans.setOrigin(btVector3(position.x, position.y, position.z));
        _body->setWorldTransform(trans);
    }
}
 
//4
-(GLKVector3)position
{
    if (_body)
    {
        //5
        btTransform trans = _body->getWorldTransform();
        return GLKVector3Make(trans.getOrigin().x(), trans.getOrigin().y(), trans.getOrigin().z());
    }
    else
    {
        //6
        return [super position];
    }
}

As you probably know, all that fancy @property stuff in Objective-C is just a convenient way of creating getter and setter methods. You’re using that knowledge to override the position property of RWNode with custom code.

  1. Start with the setter method. It will allow you to change the position of the physics body when you set the position for a node.
  2. Call a super implementation, in case for some reason you don’t have the body yet.
  3. In case you do have a physics body, you need to apply a transform to the body. In Bullet, you don’t work with position alone. Instead you work with btTransform, which holds both the position and rotation of the object. Here is the definition of a transform from the Bullet wiki:

    A transform is a translation [vector] plus a rotation [quaternion]. A “transform” alone is usually sufficient to describe everything you need to use to map a physics body [in Bullet] into your graphical rendering system.

    Since you don’t want to change the rotation yet, you need to get the current transform of the body, change the position part and send it back.

  4. It’s time to change the getter method by implementing backwards synchronization. This means when you get the position property in order to understand where you need to draw the object, you get the position of the physics body and draw the object right at that location.
  5. Getting the position is easy. You get the transform of the body and take only the position part.
  6. In case for some reason PNode doesn’t have the body, just use the default property implementation.

Build and Run the project. Your ball should fall down through the paddle.

ball_falling_through_paddle

w00t physics in action!

Stopping the Ball with the Paddle

The ball shouldn’t fall through the paddle, should it? You’re not rewriting the rules of the game, after all!

To fix this, you have to make almost the same changes to the paddle as you did to the ball. Let’s see if you can make these changes yourself. Take a peek in the spoiler sections for answers if you’re lost.

Switch to RWPaddle.h and change the parent class to PNode:

Solution Inside: RWPaddle.h after changes SelectShow

Then rename RWPaddle.m to RWPaddle.mm.

Switch to RWPaddle.mm and change the call to super initWithShader: to use PNode’s init method with physics parameters.

Set the new parameters as follows and leave the existing parameters untouched:

  1. mass:0.0f

    A mass of zero means that forces or collisions with other objects do not affect the object. It can be static or, as in this case, kinematic (since you move the paddle using touches).

  2. convex:YES

    The paddle is also a convex object.

  3. tag:kPaddleTag

    You’re just marking it with the special tag you prepared earlier.

Solution Inside: RWPaddle.mm initWithShader: SelectShow

Finally, switch to paddle.h and fix the variable declarations by adding the extern keyword at the start of each line with variable declarations.

Solution Inside: paddle.h - fixed version SelectShow

I hope you’ve had no issues and haven’t needed to look at the spoilers. :]

There is one final thing missing: Adding the paddle body to the world.

Switch to RWGameScene.mm and find this line:

[self.children addObject:_paddle];

Add the following line right below it:

_world->addRigidBody(_paddle.body);

Build and Run the project. You should see the ball bouncing nicely on the paddle.

ball_bouncing

Limiting Movement with a Border

Bouncing the ball on the paddle is fun, but your goal is a bit different. Let’s get one step closer to it by adding the border that will limit the ball’s movement when you launch it in the next section.

The changes you need to make here are once again familiar: converting the RWBorder to use PNode instead of RWNode. I believe you can do them yourself.

Switch to RWBorder.h and change the parent class of RWBorder to PNode:

Solution Inside: RWBorder.h after changes SelectShow

Rename RWBorder.m to RWBorder.mm.

Switch to RWBorder.mm and change the call to super initWithShader: to use PNode’s version of this method.

Set additional parameters as follows, leaving the existing parameters untouched:

  1. mass:0.0f

    Border is a static body in Bullet terminology, since it has zero mass, and this means forces and collisions don’t move it. In addition, you won’t move it from the code.

  2. convex:NO

    Note that the border has a concave rather than convex shape, and thus you have to pass NO to PNode’s init so that it can create the border’s shape another way.

  3. tag:kBorderTag

    Use the border tag.

Solution Inside: RWBorder.mm initWithShader: SelectShow

Fix the variable declarations in border.h by adding the extern keyword at the start of each line with variable declarations.

Solution Inside: border.h - fixed version SelectShow

To add the border to the world, switch to RWGameScene.mm and find this line:

[self.children addObject:_border];

Add the following line right below it:

_world->addRigidBody(_border.body);

This will add the border’s body to the world.

Build and Run the project. You will still see the ball bouncing on the paddle, but you will change that very soon!

Launching the Ball

Right now the ball’s bouncing is kind of wimpy. It’s time to man up and launch him into the sky!

Well, in manner of speaking. I hope it doesn’t actually launch into the sky because that would mean the border you added in previous section doesn’t work. :]

Switch to RWGameScene.mm and find this line:

_world->addRigidBody(_ball.body);

Add the following line of code right below it:

_ball.body->setLinearVelocity(btVector3(15,15,0));

Here you set the ball’s velocity. You set the x- and y-components of the velocity vector because you want to set the ball moving along both directions – diagonally, since you give x and y the same values.

There’s one more thing. Currently you have gravity enabled, but in the original Breakout game, there is none. You want the ball to keep moving in the direction it’s heading, not be slowed down by the effect of gravity, so you need to disable the gravity.

Switch to RWGameScene.mm and scroll to the bottom of initPhysics.

Replace the line that sets the gravity:

_world->setGravity(btVector3(0, -9.8, 0));

With this:

_world->setGravity(btVector3(0, 0, 0));

Build and run the game. The ball should launch to the top and right, bounce off the border and go through the bricks. Now that’s progress! As for the ghostly bricks, you’ll fix them in a minute.

ball_hits_border

Adding Bricks to the Physics World

Bricks are the ball’s natural enemies. Wait… who turned on Discovery channel? :]

Converting bricks to physical nodes should be straightforward – it’s the same process you’ve already completed with the ball, paddle and border.

Switch to RWBrick.h and change its parent class to PNode. Don’t forget to import PNode.h.

Solution Inside: RWBrick.h after changes SelectShow

Then rename RWBrick.m to RWBrick.mm.

Switch to RWBrick.mm and change initWithShader: to use PNode’s init method. Try to guess the correct values for the following brick properties (if in doubt, check the spoiler):

  1. The brick is a kinematic object. It is not affected by forces or collisions, but you’ll rotate it in the code.
  2. The brick has a convex shape.
  3. The brick’s tag is kBrickTag. It’s very important to set the correct tag for the brick, so double-check this.
Solution Inside: RWBrick.mm initWithShader: SelectShow

Fix the extern-related issue in brick.h.

Solution Inside: brick.h - fixed version: SelectShow

And add all brick bodies to the world.

Switch to RWGameScene.mm and find the line where bricks are added to an array – this one:

[_bricks addObject:brick];

Add the following line right below it:

_world->addRigidBody(brick.body);

Build and Run the project. You have all the physics bodies in place and the ball interacts with all of them.

Ball bouncing off brick

There is only one issue: You cannot win (since the bricks no longer get destroyed on collision), and although the ball falls down, you can’t lose, either!

Maybe someone would settle for this draw situation, but you won’t!

Winning and Losing with Physics

Losing is easy, so let’s start with that. :]

Switch to RWGameScene.mm and find updateWithDelta.

Add the following code to the bottom of the method:

    if (_ball.position.y < 0)
    {
        [RWDirector sharedInstance].scene = [[RWGameOverScene alloc] initWithShader:self.shader win:NO];
        return;
    }

This code is pretty simple. You check if the ball is below the zero line and switch to the Game Over scene if it is.

Build and Run the project. Let the ball fall and you should see the Game Over scene.

You Lose screen

After the sad experience of losing, you must get revenge on those bricks and win the game!

Switch to RWGameScene.mm and import PNode.h at the top of the file, right after all other imports and includes:

#import "PNode.h"

Scroll down to updateWithDelta: and add the following code to the end of the method, right after the code block where you check if the player lost:

    //1
    int numManifolds = _world->getDispatcher()->getNumManifolds();
    for (int i=0;i<numManifolds;i++)
    {
        //2
	btPersistentManifold* contactManifold =  _world->getDispatcher()->getManifoldByIndexInternal(i);
 
        //3
	int numContacts = contactManifold->getNumContacts();
	if (numContacts > 0)
	{
            //4
            [[RWDirector sharedInstance] playPopEffect];
 
            //5
            const btCollisionObject* obA = contactManifold->getBody0();
            const btCollisionObject* obB = contactManifold->getBody1();
 
            //6
            PNode* pnA = (__bridge PNode*)obA->getUserPointer();
            PNode* pnB = (__bridge PNode*)obB->getUserPointer();
 
            //7
            if (pnA.tag == kBrickTag) {
                [self destroyBrickAndCheckVictory:pnA];
            }
 
            //8
            if (pnB.tag == kBrickTag){
                [self destroyBrickAndCheckVictory:pnB];
            }
	}
    }

As advised in the official Bullet wiki here:

The best way to determine if collisions happened between existing objects in the world is to iterate over all contact manifolds.

This is exactly what are you going to do. Here’s your plan:

  1. Enumerate all manifolds.

    Note: A contact manifold is a cache that contains all contact points between pairs of collision objects.

  2. Take each manifold object from the internal manifolds array by index.
  3. Get the number of contacts and check that there is at least one contact between the pair of bodies.

    This seems tricky, at least to me. The existence of a manifold holding a pair of bodies doesn’t mean they are in contact right now. This is why you should check the number of contacts.

  4. In this game, only the ball collides with things, so at this point you know for sure that the ball just hit something and thus you need to play the corresponding sound effect.
  5. Next you need to understand which object the ball hit. Get the collision object from the manifold.
  6. Remember this line from PNode’s init method?

    _body->setUserPointer((__bridge void*)self);

    In this line, you’ve saved a reference to the PNode object in the body object property and here you’re going to get it back to be able to check the tag property.

  7. & 8. Check if any of the objects is a brick. That would mean that the ball hit the brick, since the ball is the only moving object. In that case, you need to destroy the brick. The method to destroy the brick is just below.

Add the brick destruction method right below updateWithDelta:

- (void)destroyBrickAndCheckVictory:(PNode*)brick
{
    //1
    [self.children removeObject:brick];
    [_bricks removeObject:brick];
 
    //2
    _world->removeRigidBody(brick.body);
 
    //3
    if (_bricks.count == 0) {
        [RWDirector sharedInstance].scene = [[RWGameOverScene alloc] initWithShader:self.shader win:YES];
    }
}

This method does three simple things:

  1. It removes the brick node from the scene and the bricks array.
  2. It removes the brick body from the world.
  3. Finally, it checks for a victory. If there are no bricks left, then the player just won the game! Yee-haw!

Build and run the game. It should now be fully playable.

ball_bounces_angle

Maintaining a Constant Velocity

And yet, as you’ll notice, the gameplay experience is not quite as it was in the original. For one thing, the ball begins to slow down after several collisions. This can be due to friction or some slight variance with the physics calculations. Here is the fix for that.

Switch to RWGameScene.mm and add an instance variable called _desiredVelocity.

@implementation RWGameScene {
    //...
 
    btScalar   _desiredVelocity;
}

Then go to initWithShader:, also in RWGameScene.mm, and find this line:

_ball.body->setLinearVelocity(btVector3(15,15,0));

Add the following line right below it:

_desiredVelocity = _ball.body->getLinearVelocity().length();

This way, you save the magnitude of the vector without the direction, since the direction changes as the ball bounces off of different objects.

Scroll down to updateWithDelta: and add the following code at the end of the method:

    btVector3 currentVelocityDirection =_ball.body->getLinearVelocity();
    btScalar currentVelocty = currentVelocityDirection.length();
    if (currentVelocty < _desiredVelocity)
    {
        currentVelocityDirection *= _desiredVelocity/currentVelocty;
        _ball.body->setLinearVelocity(currentVelocityDirection);
    }

Now you’re using the saved magnitude to keep the ball’s velocity constant.

It is also time to remove the NSLog from the method. Do that now.

Here is the complete version of updateWithDelta:, in case you want to check if everything is correct.

Solution Inside: RWGameScene.mm final updateWithDelta: SelectShow

Build and run, and now your ball should move at a much better (constant) speed!

Syncing a Physics Body with a Drawn Object: Rotation

I know it looks like the bricks are rotating as they were in the initial project, but it’s a lie! You are rotating drawable bricks, but the physical bricks are not rotating, and that is why the ball always bounces back the same way.

You’re going to fix this. The easiest way to do it is to override the rotation properties (rotationX, rotationY, rotationZ) of the PNode class, just as you did with the position property, and keep them in sync with the physics body.

Disclaimer: You may remember that Bullet uses quaternions to represent rotation, while the original project uses Euler angles. In this tutorial, you’re going to write some quick code to convert from Euler to quaternions and back. In a real-world project, you should stick with one or the other and use either quaternions or Euler angles everywhere in the code.

Switch to PNode.mm and add the following methods somewhere near the end of the file:

//1
-(void)setRotationX:(float)rotationX
{
    //2
    [super setRotationX:rotationX];
 
    if (_body)
    {
        //3
        btTransform trans = _body->getWorldTransform();
        btQuaternion rot = trans.getRotation();
 
        //4
        float angleDiff = rotationX - self.rotationX;
        btQuaternion diffRot = btQuaternion(btVector3(1,0,0), angleDiff);
        rot = diffRot * rot;
 
        //5
        trans.setRotation(rot);
        _body->setWorldTransform(trans);
    }
}
 
//6
-(float)rotationX
{
    if (_body)
    {
        //7
        btMatrix3x3 rotMatrix = btMatrix3x3(_body->getWorldTransform().getRotation());
        float z,y,x;
        rotMatrix.getEulerZYX(z,y,x);
        return x;
    }
 
    //8
    return [super rotationX];
}

This requires an explanation:

  1. Start with the setter method. You need to override it to allow rotating both drawable bodies and physics bodies when you set the rotation in the code.
  2. Save the value in case the node doesn’t have a body for some reason.
  3. Get the current transform. Since you don’t want to change the position, you will only modify the rotation part of the transform and send it back.
  4. Here’s the tricky part. You need to rotate the existing quaternion to the delta angle to achieve the required rotation. To do so, you calculate the angle of difference and rotate the current quaternion along the x-axis (btVector3(1,0,0)) by multiplying the new quaternion by the existing one. Please note that the order of multiplication matters!
  5. Send back the updated transform.
  6. It’s time for a getter method. You need to override the property’s getter to get the rotation from the physics object when rendering the node.
  7. Here you take the body’s current rotation quaternion and convert it to a rotation matrix. btQuaternion doesn’t have methods to get Euler angles (at least I couldn’t find any) but btMatrix3x3 does. So you’re being a little lazy and converting to btMatrix3x3 to get Euler angles.
  8. In cases where the node doesn’t have a body, you use the default implementation of the property.

Now it’s time to implement the same for the y- and z-rotations. Simply paste the following code below the x-rotation property implementation in PNode.mm:

-(void)setRotationY:(float)rotationY
{
    [super setRotationY:rotationY];
 
    if (_body)
    {
        btTransform trans = _body->getWorldTransform();
        btQuaternion rot = trans.getRotation();
 
        float angleDiff = rotationY - self.rotationY;
        btQuaternion diffRot = btQuaternion(btVector3(0,1,0), angleDiff);
        rot = diffRot * rot;
 
        trans.setRotation(rot);
        _body->setWorldTransform(trans);
    }
}
 
-(float)rotationY
{
    if (_body)
    {
        btMatrix3x3 rotMatrix = btMatrix3x3(_body->getWorldTransform().getRotation());
        float z,y,x;
        rotMatrix.getEulerZYX(z,y,x);
        return y;
    }
 
    return [super rotationY];
}
 
-(void)setRotationZ:(float)rotationZ
{
    [super setRotationZ:rotationZ];
 
    if (_body)
    {
        btTransform trans = _body->getWorldTransform();
        btQuaternion rot = trans.getRotation();
 
        float angleDiff = rotationZ - self.rotationZ;
        btQuaternion diffRot = btQuaternion(btVector3(0,0,1), angleDiff);
        rot = diffRot * rot;
 
        trans.setRotation(rot);
        _body->setWorldTransform(trans);
    }
}
 
-(float)rotationZ
{
    if (_body)
    {
        btMatrix3x3 rotMatrix = btMatrix3x3(_body->getWorldTransform().getRotation());
        float z,y,x;
        rotMatrix.getEulerZYX(z,y,x);
        return z;
    }
 
    return [super rotationZ];
}

Build and run the game.

Rotating bricks

Ah, that’s better. The ball now bounces more naturally off of the bricks. Of course it doesn’t look 100% realistic since you’ve restricted the ball’s movement to the (x,y) plane but it’s still much better.

You might also notice that the ball now spins. Before the physics body spun due to fiction, but the visual representation didn’t. Now that you’ve overridden the rotation methods, the visual representation now matches!

Where to Go from Here?

Here is the final project with all the source code from this Bullet physics tutorial.

Congratulations, you have successfully integrated the Bullet physics engine into a 3D game. I hope this tutorial inspires you to continue learning and create your own 3D games using Bullet.

If you have any questions or comments, please post them below!

Kirill Muzykov
Kirill Muzykov

Kirill is a founder of PixelOxygen, an independent development company creating games and applications for iOS.

Also, Kirill is the author of Learning iPhone Game Development with Cocos2D 3.0 book.

You can read his Blog or check his latest Games and Apps at the Apple AppStore.

User Comments

11 Comments

  • That is a hefty hard core tutorial :) look forward going trough it over the weekend!
    Hannu
  • hello
    this is a great tutorial
    i learned so much about easier 3d game programming, but that is because of the classes that were included in the sample project
    they really solve a lot of stuff i had problems with
    is there gonna be more followup tutorials ?
    and what if i use these classes into a game, ill male the game totally different, but do i just add link to this site or is there a license connected to the files, if so, what type ?
    AppStoreMod
  • you wrote that you used a command line tool to create the .h and .m files
    i couldnt find, i do know that the .m file contains the .obj files content and the light and texture mapping
    anything else ?, then i can make the .h and .m files myself to
    McIntire
  • Hi!

    I'm glad that you like the tutorial. Here are answers to the questions:

    @AppStoreMod, tutorial on how to make till the point that you find in the starter project is planned in the future.
    You can find information about source code license here http://www.raywenderlich.com/faq

    @McIntire, yes .m file contains vertices, texture coordinates & normals from .obj file, and also lightning parameters (ambient, diffuse, specular) that you can find in .mtl file. You totally can create such file yourself.
    Kirill Muzykovkmuzykov
  • In response to the question about generating .h and .m files from an OBJ file, Ricardo Rendon Cepeda just released a good tutorial on that: http://www.raywenderlich.com/48293/how- ... -es-part-1

    I actually made my own slightly modified version of Ricardo's OBJ importer that I used to export/import the models from for Breakout game that Kirill's tutorial is based on, which you can download here in case you're interested: http://www.raywenderlich.com/downloads/ObjLoader.zip
    rwenderlich
  • Hi,
    Outstanding tutorial, and the explanation on getting Bullet to compile for IOS - simply priceless..

    One question, although not related to this particular tutorial, however came to me as I was coding - is there a way of getting the face of the cube has been hit by the ball?
    meridian
  • @meridian, sure there is a way to get the face of the cube that has been hit.

    Although I'm not sure there is a good way to do this with the current code and due to how we input the data. In this tutorial we don't even care about the faces of the cube, since we just pass a set of vertices and btConvexHullShape does the rest of the job.

    If you need to get the face of the cube you can try to get collision normal and compare it with the normal of the each face of the cube. If normals are collinear then this is the face that was hit.

    Hope this helps. Maybe someone can suggest an easier way or correct me if I'm wrong.
    Kirill Muzykovkmuzykov
  • Hi
    Thank you for this tutorial. I would like to better understand the original code in the starter kit. Was it included in a different tutorial? If so, would you point me to it?
    ArtR
  • Hi ArtR,

    I'm glad that you like the tutorial! Thanks!

    The tutorial on how to create the game till the starter kit point is not yet written, but as far as I know it is planned. Maybe Ray can answer regarding when to expect it. Unfortunately I cannot write it due to workload on the other projects. Sorry about that :[
    Kirill Muzykovkmuzykov
  • @ArtR: I plan on releasing a tutorial series on how to make the game itself at some point, but it will be a little while still - stay tuned!
    rwenderlich
  • Trying to run the starter project on Xcode 6 Beta I got this error:
    - "RWNode.m:39:13: Implicit declaration of function 'glGenVertexArraysOES' is invalid in C99"
    to make it work, I added this line at the beginning of RWNode.m
    #import

    Great tutorial!!! One of the best I ever seen!
    Rojano

Other Items of Interest

Ray's Monthly Newsletter

Sign up to receive a monthly newsletter with my favorite dev links, and receive a free epic-length tutorial as a bonus!

Advertise with Us!

Hang Out With Us!

Every month, we have a free live Tech Talk - come hang out with us!


Coming up in July: Facebook Pop Tech Talk!

Sign Up - July

RWDevCon Conference?

We are considering having an official raywenderlich.com conference called RWDevCon in DC in early 2015.

The conference would be focused on high quality Swift/iOS 8 technical content, and connecting as a community.

Would this be something you'd be interested in?

    Loading ... Loading ...

Our Books

Our Team

Tutorial Team

  • Kirill Muzykov

... 50 total!

Update Team

  • Andy Pereira

Editorial Team

... 23 total!

Code Team

  • Orta Therox

... 1 total!

Translation Team

  • Vitaliy Zarubin
  • Myeong Hoon
  • Marina Mukhina

... 33 total!

Subject Matter Experts

  • Richard Casey

... 4 total!