How to Make a Game Like Cut the Rope – Part 1

Gustavo Ambrozio
Learn how to make a game like Cut the Rope!

Learn how to make a game like Cut the Rope!

This is a blog post by iOS Tutorial Team member Gustavo Ambrozio, a software engineer with over 20 years experience, including over three years of iOS experience. He is the founder of CodeCrop Software. You can also find him on .

In this tutorial series, you’ll build a cool Cut the Rope-type game from scratch using Cocos2D and Box2D.

You’ll use art created by Ray’s lovely and talented wife Vicki to build a very rudimentary Cut the Rope, mainly to show how to create and destroy ropes using Box2D.

In this 2-part tutorial series, you’ll learn:

  • How to use rope joints
  • How to draw ropes using verlets
  • How to cut the ropes (of course)
  • And much, much more!

This tutorial series assumes that you’ve already gone through the Intro to Box2D with Cocos2D Tutorial: Bouncing Balls, or have equivalent knowledge. It also uses a bunch of concepts found in another great tutorial series by Ray, How To Create A Breakout Game with Box2D and Cocos2D – Part 1 and Part 2.

Getting Started

In this tutorial, you’ll use the latest version of Xcode (4.3.x at the time of writing) and version 2.0 of Cocos2D. We’re using 2.0 because it contains a new joint in Box2D that we need (the rope joint), which 1.0.1 does not have.

If you’re still using Cocos2D 1.0.1 and are afraid that your current templates will be replaced, don’t worry. The templates for Cocos2D version 2 are installed alongside the templates for version 1.0.1, so there’s no problem installing them alongside each other.

Once you have version 2.0 of Cocos2D installed, fire up Xcode and click “Create a new Xcode project.” Under iOS, choose Cocos2D v2.x, choose the “Cocos2D iOS with Box2D” template and click Next.

On the next screen, give your project the name “CutTheVerlet” and fill out your company identifier. Don’t forget to choose “iPhone” as the device family.

In the next step, select the folder where you want to store your project. You don’t have to create a new folder – Xcode will create one for you. Click “Create” and you’re ready to start coding!

You probably know what this template project is all about, but just for the fun of it, click Run and see what it does:

You can play with a few blocks. This is cool, but not nearly as cool as what you’re about to make!

Follow Along on GitHub

If you want to follow me wherever I may go, check out this project’s GitHub page!

I’ll publish the entire tutorial, with comments and tags for every step on GitHub!

You might find this handy in case you get stuck somewhere or want to look at the code at a particular stage instead of typing it out yourself. Otherwise, keep following along here!

The repository tag for this point in the tutorial is ProjectTemplate. You can download the project zip at this state here.

Cleaning Up

Before you get your hands dirty, time for some cleanup. :]

Open HelloWorldLayer.h and remove the declaration of the spriteTexture_ instance variable:

//Remove this line
CCTexture2D *spriteTexture_;	// weak ref

Open and completely remove the implementations of the following three methods:

  1. -(void) addNewSpriteAtPosition:(CGPoint)p;
  2. -(void) createMenu;
  3. -(void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

The first two methods also have declarations at the top of the file. Make sure you remove those as well.

Now you’ll have a couple of warnings on the init method in this file, because of calls to createMenu and addNewSpriteAtPosition:. Clean up the init method by removing those method calls.

Next, delete the line that enables the accelerometer, as you won’t be using it in this project. Also remove the line that grabs the window size, as you won’t need it, at least not now:

// delete these lines!
self.isAccelerometerEnabled = YES;
CGSize s = [CCDirector sharedDirector].winSize;

At the end of the init method, remove everything that adds stuff to the scene:

    // Delete ALL the lines listed here!
    //Set up sprite
#if 1
    // Use batch node. Faster
    CCSpriteBatchNode *parent = [CCSpriteBatchNode batchNodeWithFile:@"blocks.png" capacity:100];
    spriteTexture_ = [parent texture];
    // doesn't use batch node. Slower
    spriteTexture_ = [[CCTextureCache sharedTextureCache] addImage:@"blocks.png"];
    CCNode *parent = [CCNode node];
    [self addChild:parent z:0 tag:kTagParentNode];
    [self addNewSpriteAtPosition:ccp(s.width/2, s.height/2)];
    CCLabelTTF *label = [CCLabelTTF labelWithString:@"Tap screen" fontName:@"Marker Felt" fontSize:32];
    [self addChild:label z:0];
    [label setColor:ccc3(0,0,255)];
    label.position = ccp( s.width/2, s.height-50);

That’s it for!

Open the resources group on the project navigator and delete blocks.png, since you don’t need it. When asked if you want to remove the reference only or move to trash, don’t be shy. Click “Move to Trash” – you don’t want any unnecessary files hanging around.

To make sure everything works, compile and run. You should see an empty scene:

The repository tag for this point in the tutorial is CleanedUpProject.

Adding Some Sprites

Now that you’ve tossed out what you don’t need, you can add some things you do need, starting with the art. I got most of these images from Vicki’s site, and she made a few additional sprites just for this tutorial. Go ahead and download the art files from GitHub.

Extract the ZIP file contents. This will create a new folder called “Art.” Inside this folder are two more folders: Images and Originals. The Originals folder has all the original PNG files, in retina resolution.

You won’t use these original files directly in the project. As you may know, the recommended approach for using sprites in Cocos2D is to work with a sprite sheet created with a program like TexturePacker.

Note: If you want to know more about how to use TexturePacker, there’s an excellent tutorial – guess where? Yep, right here on, in the aptly-named “How to Create and Optimize Sprite Sheets in Cocos2D with Texture Packer and Pixel Formats“.

But in this case, there’s no need to make a sprite sheet – I’ve already made one for you! :] They’re in the ZIP you just downloaded, in the Images subdirectory.

Moving on then. The Images folder inside the Art folder has everything you need to add to the project, so go ahead and drag this folder to the Resources group of your project.

Be sure to check the “Copy items into destination group’s folder” to copy these files to your project folder.

You now have the elements you need to begin building your scene. You’re going to make the initial scene look like this:

To do this, first you need to add a reference to the crocodile sprite you’ll be using in your scene. So add the following line to HelloWorldLayer.h below the existing declaration for m_debugDraw:

    CCSprite *croc_;            // weak ref

Then go to and insert the code below right before the initPhysics call in the init method:

        // Load the sprite sheet into the sprite cache
        [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"CutTheVerlet.plist"];
	    // Add the background
        CCSprite *background = [CCSprite spriteWithSpriteFrameName:@"bg.png"];
        background.anchorPoint = CGPointZero;
        [self addChild:background z:-1];
        // Add the croc
        croc_ = [CCSprite spriteWithSpriteFrameName:@"croc_front_mouthclosed.png"];
        croc_.anchorPoint = CGPointMake(1.0, 0.0);
        croc_.position = CGPointMake(320.0, 30.0);
        [self addChild:croc_ z:1];

The first line loads all your sprites and holds them in the sprite sheet frame cache. You then add the background and the croc. Build and run to see whether it looks the way you want it to:

Oops, not exactly! The scene is designed for portrait mode, but the code is forcing it to run in landscape.

There’s an easy fix for this. Open, find shouldAutorotateToInterfaceOrientation:, and change the implementation to this:

	return UIInterfaceOrientationIsPortrait(interfaceOrientation);

Now run and smile:

Simple so far, right? Now comes the hard part: the rope.

The repository tag for this point in the tutorial is BasicScene.

What’s This Verlet You Speak Of?

So, how are you going to implement the rope using Cocos2D and Box2D, you ask?

Out of the box, the only useful thing provided by Box2D is a joint called rope joint. A rope joint is a joint that can be thought of as a “maximum distance” joint. You specify two bodies and the maximum distance between them, and Box2D makes sure that these two bodies are never more than this distance apart, much like a real rope with something tied to each end.

This is very nice, but Cocos2D does not (yet) have any way to draw this rope. You could draw a straight line between the two bodies, but this won’t depict a realistic rope in all scenarios. For instance, if the distance between the objects is less than the maximum distance (the rope length in your case), the rope should be sagging. But if you were to draw a straight line between the two points, obviously it would not sag, so it would not look realistic.

To achieve this sagging effect, I found a very nice class called VRope that PatrickC of Clever Hamster Games wrote about in the Cocos2D forums, based on code written in ActionScript at Thanks to both of those great sites for your contributions – you made my life easier. :]

To simulate a rope, the VRope class uses the concept of Verlet integration. As explains:

The Verlet integration consists in dots and links between these dots where each dot has remembered which was its previous position to determine its next step, the new position of x is equal to x + x – previous_x (same for y) and then each of these dots are associated (grouped) by pairs that try to keep same distance between each other as they were when the program started.

I’ll explain in more detail how this is implemented in the VRope class, but first add a simple rope to your project to see it in action.

Download the original VRope class code from PatrickC here. Extract and drag the vrope-latest folder to your project tree:

Again, choose to copy the items into the destination folder:

If you compile the code now, you’ll get two errors and one warning. Fix those before you go any farther.

The errors are in‘s debugDraw method. This class was built to be used with version 1.0.1 of Cocos2D, which supports OpenGL ES 1.0. Cocos2D 2.x uses OpenGL ES 2.0, and some of the older Cocos2D 1.x functions are not forward-compatible. Since you won’t use debugDraw, just remove it. Don’t forget to also remove the method declaration in VRope.h.

The warning comes from a deprecated Cocos2D method that’s called from createRope:pointB:. This is the offending line that should be in yellow in Xcode:

CCSprite *tmpSprite = [CCSprite spriteWithBatchNode:spriteSheet rect:CGRectMake(0,0,multiplier,[[[spriteSheet textureAtlas] texture] pixelsHigh])];

Replace it with:

CCSprite *tmpSprite = [CCSprite spriteWithTexture:spriteSheet.texture
               [[[spriteSheet textureAtlas] texture] pixelsHigh]/CC_CONTENT_SCALE_FACTOR())];

Now the project will compile with no errors or warnings.

You’ll have to modify the VRope class a little to suit your game’s needs. The original class keeps track of two Box2D bodies and simulates the rope based on the movement of these bodies. But it determines the rope length based on the distance between the two objects at the time they were created. This could result in an incorrect rope length in your game, as the rope might not be tight when you create the VRope instance.

You’ll modify the class to use an instance of b2RopeJoint (discussed at the beginning of this section), which already has two bodies attached to it. It also has information about the length of the rope, taking into consideration the anchor points where the b2RopeJoint attaches to the two bodies.

In other words, you say where the rope is attached, and how long it is, and the rope will automatically calculate the appropriate amount of “sagging” necessary to meet those constraints.

So, open VRope.h and replace these lines:

    b2Body *bodyA;
    b2Body *bodyB;

With this:

    b2RopeJoint *joint;

Also, change the init method declaration from:

-(id)init:(b2Body*)body1 body2:(b2Body*)body2 spriteSheet:(CCSpriteBatchNode*)spriteSheetArg;


-(id)initWithRopeJoint:(b2RopeJoint*)joint spriteSheet:(CCSpriteBatchNode*)spriteSheetArg;

This will make it easier to create a visual representation of a rope joint by passing in the b2RopeJoint directly.

Next change the createRope method from:

-(void)createRope:(CGPoint)pointA pointB:(CGPoint)pointB;


-(void)createRope:(CGPoint)pointA pointB:(CGPoint)pointB distance:(float)distance;

This allows us to set the length of the rope.

Now, go to and replace the existing implementation for init:body2:spriteSheet: with:

-(id)initWithRopeJoint:(b2RopeJoint*)aJoint spriteSheet:(CCSpriteBatchNode*)spriteSheetArg {
    if((self = [super init])) {
        joint = aJoint;
        CGPoint pointA = ccp(joint->GetAnchorA().x*PTM_RATIO,joint->GetAnchorA().y*PTM_RATIO);
        CGPoint pointB = ccp(joint->GetAnchorB().x*PTM_RATIO,joint->GetAnchorB().y*PTM_RATIO);
        spriteSheet = spriteSheetArg;
        [self createRope:pointA pointB:pointB distance:joint->GetMaxLength()*PTM_RATIO];
    return self;

Here we pull out the two bodies from the b2RopeJoint and call the previous initializer.

Also replace the existing reset and update implementations to use the rope joint instead of the bodies, as follows:

-(void)reset {
    CGPoint pointA = ccp(joint->GetAnchorA().x*PTM_RATIO,joint->GetAnchorA().y*PTM_RATIO);
    CGPoint pointB = ccp(joint->GetAnchorB().x*PTM_RATIO,joint->GetAnchorB().y*PTM_RATIO);
    [self resetWithPoints:pointA pointB:pointB];
-(void)update:(float)dt {
    CGPoint pointA = ccp(joint->GetAnchorA().x*PTM_RATIO,joint->GetAnchorA().y*PTM_RATIO);
    CGPoint pointB = ccp(joint->GetAnchorB().x*PTM_RATIO,joint->GetAnchorB().y*PTM_RATIO);
    [self updateWithPoints:pointA pointB:pointB dt:dt];

Finally, createRope needs to be updated to use the distance you provide instead of the current distance between the two points. So, just change the method declaration from:

-(void)createRope:(CGPoint)pointA pointB:(CGPoint)pointB {


-(void)createRope:(CGPoint)pointA pointB:(CGPoint)pointB distance:(float)distance {

And remove this line from the method:

    // Remove this line
	float distance = ccpDistance(pointA,pointB);

You also need to update an old call to createRope inside initWithPoints:pointB:spriteSheet:. Go to this method and change the line:

    [self createRope:pointA pointB:pointB];


    [self createRope:pointA pointB:pointB distance:ccpDistance(pointA, pointB)];

This should be enough for now. But before you get to making your rope, you need to add a little more infrastructure to handle the ropes and the candies.

Candy for Crocs

Your game may have a crocodile instead of the Om Nom monster, but you still have to feed him! And that means candy, which in this project comes in the form of pineapple. (What else to crocodiles eat?!)

First, add a few more instance variables to HelloWorldLayer.h:

    NSMutableArray *ropes;
    NSMutableArray *candies;
    b2Body* groundBody;    // weak ref
    CCSpriteBatchNode *ropeSpriteSheet; // weak ref

The arrays will help you keep track of the ropes and candies you’ll create. The groundBody instance variable will hold a reference to the world body, and ropeSpriteSheet will hold the sprite batch node that will be used in the creation of the VRope instances.

Now, open and add these lines to init right after self.isTouchEnabled = YES;:

    ropes = [[NSMutableArray alloc] init];
    candies = [[NSMutableArray alloc] init];
    ropeSpriteSheet = [CCSpriteBatchNode batchNodeWithFile:@"rope_texture.png"];
    [self addChild:ropeSpriteSheet];

Just so you don’t forget, add these lines to dealloc before the call to super dealloc:

    [ropes release];
    [candies release];

You need to keep a reference to the world body created in initPhysics. So, go to that method and change:

	b2Body* groundBody = world->CreateBody(&groundBodyDef);


	groundBody = world->CreateBody(&groundBodyDef);

Now, add this method to the end of the file (but before the final @end):

-(b2Body *) createCandyAt:(CGPoint)pt
    // Get the sprite from the sprite sheet
    CCSprite *sprite = [CCSprite spriteWithSpriteFrameName:@"pineapple.png"];
    [self addChild:sprite];
    // Defines the body of your candy
    b2BodyDef bodyDef;
    bodyDef.type = b2_dynamicBody;
    bodyDef.position = b2Vec2(pt.x/PTM_RATIO, pt.y/PTM_RATIO);
    bodyDef.userData = sprite;
    bodyDef.linearDamping = 0.3f;
    b2Body *body = world->CreateBody(&bodyDef);
    // Define the fixture as a polygon
    b2FixtureDef fixtureDef;
    b2PolygonShape spriteShape;
    b2Vec2 verts[] = {
        b2Vec2(-7.6f / PTM_RATIO, -34.4f / PTM_RATIO),
        b2Vec2(8.3f / PTM_RATIO, -34.4f / PTM_RATIO),
        b2Vec2(15.55f / PTM_RATIO, -27.15f / PTM_RATIO),
        b2Vec2(13.8f / PTM_RATIO, 23.05f / PTM_RATIO),
        b2Vec2(-3.35f / PTM_RATIO, 35.25f / PTM_RATIO),
        b2Vec2(-16.25f / PTM_RATIO, 25.55f / PTM_RATIO),
        b2Vec2(-15.55f / PTM_RATIO, -23.95f / PTM_RATIO)
    spriteShape.Set(verts, 7);
    fixtureDef.shape = &spriteShape;
    fixtureDef.density = 30.0f;
    fixtureDef.filter.categoryBits = 0x01;
    fixtureDef.filter.maskBits = 0x01;
    [candies addObject:[NSValue valueWithPointer:body]];
    return body;

This method will create a pineapple body and its sprite at a particular position on the screen. It uses a polygon as the fixture for the body. The points for the fixture were taken using VertexHelper. You can see how to use VertexHelper in the How To Use Box2D For Just Collision Detection with Cocos2D iPhone tutorial. It’s pretty basic Cocos2D+Box2D stuff. :]

And Now For Some Ropes!

It’s finally time to add the method to create the rope and attach two bodies to it. No, not that kind of body – this game is rated G! :]

First, add this import at the top of

#import "VRope.h"

Now add this method to the end of the file:

-(void) createRopeWithBodyA:(b2Body*)bodyA anchorA:(b2Vec2)anchorA 
                      bodyB:(b2Body*)bodyB anchorB:(b2Vec2)anchorB
    b2RopeJointDef jd;
    jd.bodyA = bodyA;
    jd.bodyB = bodyB;
    jd.localAnchorA = anchorA;
    jd.localAnchorB = anchorB;
    // Max length of joint = current distance between bodies * sag
    float32 ropeLength = (bodyA->GetWorldPoint(anchorA) - bodyB->GetWorldPoint(anchorB)).Length() * sag;
    jd.maxLength = ropeLength;
    // Create joint
    b2RopeJoint *ropeJoint = (b2RopeJoint *)world->CreateJoint(&jd);
    VRope *newRope = [[VRope alloc] initWithRopeJoint:ropeJoint spriteSheet:ropeSpriteSheet];
    [ropes addObject:newRope];
    [newRope release];

Now things are getting a little more interesting!

First, you create a b2RopeJointDef and attach the two bodies passed into the method using the provided local anchor points. For example, to attach the rope to the center of a body you’d pass in coordinates (0,0).

Then, you calculate the current distance between the two bodies at the given local anchors and multiply by a “sag” value. This sag value should be always greater than 1 and will determine how much longer the rope will be. So, for example, if the two bodies are 10 meters apart and sag is 1.1, the rope will have a maximum length of 11 meters.

You then create the b2RopeJoint and send it to the init method of VRope that you created above. The new rope object is kept in an array (so you can update it later) and returned.

That’s all you need to add some ropes! Now add a new method below init that creates all the bodies and ropes (including a delectable pineapple):

#define cc_to_b2Vec(x,y)   (b2Vec2((x)/PTM_RATIO, (y)/PTM_RATIO))
-(void) initLevel 
    CGSize s = [[CCDirector sharedDirector] winSize];
    // Add the candy
    b2Body *body1 = [self createCandyAt:CGPointMake(s.width * 0.5, s.height * 0.7)]; 
    // Add a bunch of ropes
    [self createRopeWithBodyA:groundBody anchorA:cc_to_b2Vec(s.width * 0.15, s.height * 0.8) 
                        bodyB:body1 anchorB:body1->GetLocalCenter()
    [self createRopeWithBodyA:body1 anchorA:body1->GetLocalCenter()
                        bodyB:groundBody anchorB:cc_to_b2Vec(s.width * 0.85, s.height * 0.8)
    [self createRopeWithBodyA:body1 anchorA:body1->GetLocalCenter()
                        bodyB:groundBody anchorB:cc_to_b2Vec(s.width * 0.83, s.height * 0.6)

This is a pretty simple method, but notice one important thing: the difference in coordinate space. To make life easier, you want to use screen coordinates to place the ropes and pineapples, but your createRope method takes anchor points in local body coordinates, and those have to be specified in Box2D’s world coordinates, not as screen coordinates.

To get around this, you create a macro, cc_to_b2Vec, which translates screen coordinates to world coordinates.

Now you just need to add a call to initLevel in init, right after the call to initPhysics:

    [self initLevel];

Compile and run and let’s see what you get. :] It should be something like:

Not exactly what you expected… The problem is that you forgot to update your sprites based on the Box2D world simulation. You also forgot to call the rope’s update method. (If you remembered these things and already did them, good for you!)

So, go to update: in and add this at the end:

    //Iterate over the bodies in the physics world
    for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
        CCSprite *myActor = (CCSprite*)b->GetUserData();
        if (myActor)
            //Synchronize the AtlasSprites position and rotation with the corresponding body
            myActor.position = CGPointMake( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO);
            myActor.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
    // Update all the ropes
    for (VRope *rope in ropes)
        [rope update:dt];
        [rope updateSprites];

Compile and run again, and this is what you should get:

Great, what a nice looking rope you’ve got!

You might notice, though, that the ropes move a lot when the app starts, and it looks a little weird. This happens because when a VRope object is created, it’s first laid out as a straight line, and then the simulation makes the rope fall, according to the game physics. The wobbling rope is physics working as it should!

To solve this, you can jump forward in time when you first lay out the scene. Add these lines to the end of initLevel:

    // Advance the world by a few seconds to stabilize everything.
    int n = 10 * 60;
    int32 velocityIterations = 8;
    int32 positionIterations = 1;
    float32 dt = 1.0 / 60.0;
    while (n--)
        // Instruct the world to perform a single step of simulation.
        world->Step(dt, velocityIterations, positionIterations);
        for (VRope *rope in ropes)
            [rope update:dt];
    // This last update takes care of the texture repositioning.
    [self update:dt];

Build and run again, and you should see no more bouncing rope. Instead you should have a tranquil scene with a hungry crocodile, and ropes so still they’re begging to be cut!

The repository tag for this point in the tutorial is BasicRopes.

Where to Go From Here?

That’s it for today. In the next and last part of the tutorial, you’ll learn how to cut the verlet and feed the croc.

In the meantime, if you have any questions about this part of the tutorial, join in the forum discussion below!

This is a blog post by iOS Tutorial Team member Gustavo Ambrozio, a software engineer with over 20 years experience, including over three years of iOS experience. He is the founder of CodeCrop Software. You can also find him on .

Gustavo Ambrozio

Gustavo is a software engineer from Brazil with over 20 years experience, over 4 years of iOS experience and founder of CodeCrop Software. Gustavo has worked on everything from server software, corporate systems and now is having fun living in sunny California developing mobile games for PocketGems. You can also read his blog, follow him on Twitter, GitHub and connect on LinkedIn.

Other Items of Interest

There’s more waiting for you in our video tutorial section. Weekly

Sign up to receive the latest tutorials from each week, and receive a free epic-length tutorial as a bonus!

Advertise with Us!

PragmaConf 2016 Come check out Alt U

Our Books

Our Team

Video Team

... 19 total!

Swift Team

... 16 total!

iOS Team

... 31 total!

Android Team

... 15 total!

macOS Team

... 11 total!

Apple Game Frameworks Team

... 10 total!

Unity Team

... 11 total!

Articles Team

... 11 total!

Resident Authors Team

... 11 total!