Introduction to physics on the iPhone Part 4: Running the simulation on the iPhone

This is the final part of this tutorial where we're going to run the project we created on the iPhone simulator. In the earlier parts of this tutorial I showed you how to set up your own Box2D enabled Cocos2D project. It's important to know how to do this, but for now I advise that you open the "ShapeWorkshop Base" project which can be downloaded here. In this project I've deleted a whole load of un-necessary code which comes with the Cocos2D template and I've added some utility classes which we'll be using. If you would prefer to add this functionality to an existing project I've included instructions.

XCode manual setup

In the bundle included with ShapeWorkshop there should be six files:

  • BBox2DBuilder.h / BBox2DBuilder.mm:
  • BLevel.h / BLevel.m:
  • BElement.h / BElement.m:

These files are really important for your project because they automate the process of reading the level geometry file and provide a class for setting up Box2D. Right click on the main class group in XCode and create a new group called "Shape Workshop". Next copy the 6 files into your XCode project main directory. Finally right click the "Shape Workshop" directory and add the 6 files.

Importing your level into XCode

Firstly, we need to make the level geometry file and sprite spritesheet available to XCode.

You should have exported your project from Shape Workshop to the "Resources" folder of your XCode project. If you're using the base project you will need to re-do this step. First, you need to add the files to your XCode project. Right click the "Resources" folder and click:"New Group" call the group "table_scene". This group will help to organise the resources if you have more than one level. Next right click the "table_scene" group and click "Add Files to [Project Name]".

Figure 1:Adding files to our project

The really nice thing about this setup is that once you've got your project setup with XCode you can export from Shape Workshop with one click. The geometry file will be exported and the images will be packed and exported automatically. This makes it really easy to adjust elements of your level without having to manually faff around creating sprite sheets and moving files.

Here's a quick overview of the support classes provided to help you import your level.

BLevel:

The BLevel class represents all the information in your level. It contains properties such as: gravity, screenToWorld ratio and scale as well as a list of all the elements contained in the level. It also contains utility methods like: getElementsByName and getElementsByTag which are useful if you want to customise your level programatically. To create a new level you can use the: levelWithContentsOfFile method and provide a link to your level's .plist geometry file. This will load your level and all it's elements from the file.

BElement:

The element object is a convenient way to access element properties such as: name, position, outline etc… You can access all the properties that you setup in Shape Workshop. This class is well commented so for more details take a look at the class itself.

BBox2DBuilder:

The core of the action happens in this class. The class parses the level and converts it into a Box2D world. It also provides some convenience functions for implementing your level. It provides a function which allows you to set the zoom for your scene. It also helps setting up sprites and updating the Box2D world.

I've tried to design ShapeWorkshop to be light weight and flexible so that beginners can get started writing a few lines of code whereas experts can easily modify the builder functions to provide more customisation. These three classes are well commented provide everything you need to know in order to access your object properties and work with Box2D. If you prefer to use Chipmunk or another physics engine it would be very easy to create your own custom profiles in ShapeWorkshop and use the code provided as a base to create your own builder class.

Now you should be ready to display your scene.

Open HelloWorldLayer.h and add the following code:

  1. #import "BBox2DBuilder.h"
  2.  
  3. @interface HelloWorldLayer : CCLayer
  4. {
  5. // Our level object
  6. BLevel * _level;
  7.  
  8. // Out box2d builder
  9. BBox2DBuilder * _builder;
  10.  
  11. // A pointer to the jug body
  12. b2Body * _jug;
  13. }

Now open the class "HelloWorldLayer.mm" and locate the init method. This is were we're going to be setting up our scene. Add the following code to the init method:

  1. -(id) init
  2. {
  3. if( (self=[super init])) {
  4.  
  5. // Get a link to the plist file
  6. NSString * path = [[NSBundle mainBundle] pathForResource:@"table_scene" ofType:@"plist"];
  7.  
  8. // Create a new level from the file
  9. _level = [BLevel levelWithContentsOfFile:path];
  10.  
  11. // Add the sprite sheet
  12. [BBox2DBuilder setSpriteSheet:self withSpriteSheet:@"table_scene-spritesheet1.png" withPackFile:@"table_scene-pack.plist"];
  13.  
  14. // Build the level into a Box2D simulation
  15. _builder = [BBox2DBuilder box2DBuilderWithLevel:_level withDebug: NO];
  16.  
  17. // Add individual sprites to the layer
  18. [_builder addSpritesToLayer:self];
  19.  
  20. // Set the scale to the scale specified in ShapeWorkshop
  21. [_builder setScaleFromLevel:self];
  22.  
  23. // Make the jug pour. The all elements tagged with jug
  24. NSMutableArray * jugs = [_level getElementsByTag:@"jug"];
  25.  
  26. for(BElement * aJug in jugs) {
  27. // For each element (there should only be one)
  28. // get the linked body and give it a rotation
  29. b2Body *b;
  30. [aJug.physicsLink getValue:&b];
  31.  
  32. if(b != Nil) {
  33. // get a pointer to the body
  34. _jug = b;
  35. }
  36. }
  37.  
  38. // Give the jug an angular velocity
  39. if(_jug != Nil) {
  40. _jug->SetAngularVelocity(0.2);
  41. }
  42.  
  43. [self scheduleUpdate];
  44.  
  45.  
  46. }
  47. return self;
  48. }

Box2D setup:

The first line of this code creates a string which point to the location of our table_scene.plist file. This is the file which contains our level's geometry and configuration. Next we create a new BLevel object using the file. This will translate our config file into an object which we can use in our code. Because we're using a sprite sheet we need to load that next. This is important because the builder will reference these sprites so they must exist otherwise it will fail. We provide the name of the sprite sheet and the name of the packing file which allows Cocos2D to un-pack our sprite sheet into individual sprites.

Next we build the level into a Box2D simulation and turn debuggin off. In the next line we are adding the sprites to our layer. We've already defined the sprite sheet but as yet the individual sprite instances haven't been added to the layer. The next line scales our level to the value specified in ShapeWorkshop. This means that our scene will appear exactly like our scene in Shape Workshop. That's it! The Box2D scene is now fully setup!

Making the jug pour:

We want the jug to pour the food onto the plate to make the scene a bit more interesting. Here use the getElementsByTag method to return our jug element. We're only expecting one element but this method returns an array anyway to cover cases when we may have tagged more than one element. Next we loop over the tagged elements and get a pointer to the Box2D body. If you remember this allows us add a velocity/rotation/acceleration. In this example we're going to add a rotation. We do this using the SetAngularVelocity method.

The final [self scheduleUpdate] line tells Cocos2D to call the update method every frame.

Debug draw (optional):

Debug draw provides a useful way to debug our Box2D scene. Box2D will draw a wireframe version of each object which will be displayed behind the sprite. You could hide the sprites or not add them to the view of you want to see the debug objects more clearly. To enable this se need to add some code to the draw method.

  1. -(void) draw
  2. {
  3. [super draw];
  4. [_builder draw];
  5.  
  6. }

Just one line. Now if you enable debug when you build your level the objects will be displayed.

Updating the Box2D world:

The final thing we need to do is make sure that our simulation is updated every time step. The BBox2DBuilder class takes care of this with it's update method. To activate this every frame add the following line to the HelloWorldLayer.mm update method:

  1. -(void) update: (ccTime) dt
  2. {
  3. [_builder update:dt];
  4.  
  5. // Check the angle of the jug, when it reaches
  6. // a max pouring angle set it's angular velocity
  7. // to zero
  8. if(_jug != Nil) {
  9. if(_jug->GetAngle() > 1.80 && _jug->GetAngularVelocity() > 0) {
  10. _jug->SetAngularVelocity(0);
  11. }
  12. }
  13. }

We also add a piece of code which checks the angle of the jug every frame and when it reaches about 100 degrees we stop it from revolving more. This is so it stops pouring and doesn't keep spinning.

Tidying up:

Finally add the following to the dealloc method to tidy up our objects when the layer is released:

  1. -(void) dealloc {
  2. [_level release];
  3. [_builder release];
  4. [super dealloc];
  5. }

Run the project:

Click run and you should see the jug pour the items onto the plate. Congratulations you've created a complex physics scene on the iPhone! If you had any problems a working project is contained in the Shape Workshop download package.

This tutorial has given you a basic understanding of Box2D, Cocos2D and Shape Workshop. From here you just need to play around. Try setting different fixture properties for the game elements. Change density and restitution and see what happens. In the next tutorial I'm going to show you how to take this one stage further and create a labyrinth game for the iPhone!

Tweet: 

Comments

Hello, i download this project. Then i copy BBox2DBuilder.h/m/mm, BElement.h/m, BLevel.h/m
and when i compile it i'm getting error : Lexical or Preprocessor Issue 'cassert' file not found
Lexical or Preprocessor Issue 'PhysicsSprite.h' file not found
How can i get it? and what does it mean 'cassert' file not found ???????
Thanks

Delete the line:
#import "PhysicsSprite.h"
From BBox2DBuilder.h

hi, I downloaded the shapeworkshop base project, and copied box2dbuilder, etc to my project. Whenever I try to run it, I get a lot of compile errors from your classes. I've already deleted"#import physics sprite.h", but it still wont work. Can you fix this?

thanks.

Hi Kirk,

I've uploaded a new version of the project which works on my setup. If you have problems with this version please let me know the errors you're getting. I can't solve anything on your system without details!

I'm still getting "Lexical or Preprocessor Issue 'cassert' file not found". I don't know how to solve this problem???

Add new comment

Filtered HTML

  • Web page addresses and e-mail addresses turn into links automatically.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <c>, <cpp>, <drupal5>, <drupal6>, <java>, <javascript>, <php>, <python>, <ruby>. The supported tag styles are: <foo>, [foo].
  • Allowed HTML tags: <a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.