Using PhysicsEditor with Cocos2D

Andreas Löw
Using PhysicsEditor with Cocos2D
Last update: More than 3 months ago

This tutorial explains how you can use PhysicsEditor with version 3 of Cocos2D, which has integrated Chipmunk2D as physics engine.

  • Create physics shapes for your sprites
  • Setup your Cocos2D application
  • Add collision shapes to your sprites

Exporter included for download

Demo App screenshot later on

In this tutorial you are going to create a simple demo application that lets you tap the screen to drop objects. The objects will stack on the floor at the bottom of the screen.

You can clone the finished project from GitHub using the following command line:

git clone --recursive https://github.com/CodeAndWeb/PhysicsEditor-Cocos2D-V3.git

The --recursive is important because we are integrated Cocos2d as a git submodule — to avoid copying the project's source code.

Create physics shapes for your sprites

Please start with downloading and installing PhysicsEditor. The 7 days trial version should be fine for this tutorial.

After starting it select Cocos2d exporter in the Exporter combo box. After doing that, you can model your physics shapes as usual:

  • add your sprites by dragging and dropping them onto the left panel under Shapes

  • trace the outlines of your sprites using the magic wand tool

  • configure physical parameters and collision settings

  • export your setup using Publish, add the generated .plist file to your Xcode project

PhysicsEditor: Traced shapes

Setup your Cocos2D application

Creating a new project

For this tutorial we use the unofficial cocos2d templates.

Use the following sequence in a terminal to create an empty project:

Start by cloning the cocos2d project from github:

git clone --recursive https://github.com/slembcke/UnofficialCocos2DTemplate.git

Now rename the project to PhysicdEditorCocos2d

cd UnofficialCocos2DTemplate
./RenameProject.rb

You can also set up a project using SpriteBuilder — simply create a new project and save it.

Preparing the project

Remove MainScene.swift — from the project, you can also delete the file.

Get the loader code for cocos2d from out PhysicsEditor-Loaders repository.

Copy PhysicsShapeCache.m and PhysicsShapeCache.h into your project's folder and add them to the project.

For simplicity of this tutorial you'll focus on the iOS app. Adjusting things for Mac and Android should be easy.

Open AppDelegate.m for the iOS app and change the screen orientation:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [self setupCocos2dWithOptions:@{
        CCSetupTabletScale2X: @(YES),
        CCSetupScreenOrientation: CCScreenOrientationPortrait,
    }];

    return YES;
}

Open MainScene.m. Remove the code found in the file and replace it with the following code block:



#import "MainScene.h"


#import "PhysicsShapeCache.h"

@implementation MainScene

-(instancetype)init
{
    if((self = [super init]))
    {
        // Enable touch handling on scene node
        self.userInteractionEnabled = YES;

        // Load the generated physics shapes into the PhysicsShapeCache
        [[PhysicsShapeCache sharedShapeCache] addShapesWithFile:@"Shapes.plist"];
    }

    return self;
}

@end

The code block initializes the scene, enables touch handling and loads the Shapes.plist into the PhysicsShapeCache .

Add collision shapes to your sprites

Now create a method to spawn our physics shapes. You'll later feed the method with an object name and the position where it's going to be spawned.

- (void)spawnSprite:(NSString *)name atPos:(CGPoint)pos
{
    // create a CCSprite node and set it's position
    CCSprite *sprite = [CCSprite spriteWithImageNamed:[NSString stringWithFormat:@"%@.png", name]];
    sprite.position = pos;

    // attach the physics body to the sprite
    [[PhysicsShapeCache sharedShapeCache] setBodyWithName:name onNode:sprite];

    // add the new physics object to our world
    [_physicsWorld addChild:sprite];
}

Note how easy it is to set up the physics object by simply calling [[PhysicsShapeCache sharedShapeCache] setBodyWithName:name onNode:sprite] . The first parameter is the name of the physics shape - as you see it in PhysicsEditor, the second parameter is the CCNode to which you want to attach the body. _physicsWorld is an instance variable we've added to our MainScene :

@implementation MainScene
{
    CCPhysicsNode *_physicsWorld;
}

Extend the init method:

  • Add some background graphics
  • Init the _physicsWorld
  • Add a ground sprite
  • Add the first object
-(instancetype)init
{
    if((self = [super init]))
    {
        // Enable touch handling on scene node
        self.userInteractionEnabled = YES;

        // Load the generated physics shapes into the PhysicsShapeCache
        [[PhysicsShapeCache sharedShapeCache] addShapesWithFile:@"Shapes.plist"];

        // Load background image
        CCSprite *background = [CCSprite spriteWithImageNamed:@"background.png"];
        background.anchorPoint = ccp(0,0);
        [self addChild:background];

        // Setup physics world
        _physicsWorld = [CCPhysicsNode node];
        _physicsWorld.gravity = ccp(0,-900);
        //_physicsWorld.debugDraw = YES;
        [self addChild:_physicsWorld];

        // Add ground sprite (set as static in PhysicsEditor)
        [self spawnSprite:@"ground" atPos:ccp(0,0)];

        // Add a banana
        [self spawnSprite:@"banana" atPos:ccp(self.contentSize.width/2,self.contentSize.height/2)];
    }
    return self;
}

Compile and run. You should now see a simple scene with a dropping banana.

Adding more sprites

Add the following block: It spawns new sprites at the touch position:

-(void) touchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
    CGPoint touchLoc = [touch locationInNode:self];
    static int i = 0;
    NSArray *sprites = @[ @"banana", @"cherries", @"crate", @"orange" ];
    [self spawnSprite:[sprites objectAtIndex:(i++ % [sprites count])] atPos:touchLoc];
}

That's it! We can start playing around with our demo app:

Demo App screenshot Demo App screenshot later on