Chipmunk Color Match:

This tutorial shows you how to create a simple color matching game with Chipmunk Pro and Cocos2D 2.1. It assumes you know the basics about Chipmunk such as how to create spaces, bodies and shapes. You might want to read up on some of the documentation or the Chipmunk Basics tutorial on the documentation page.

TODO: I either haven't made the Chipmunk Basics tutorial yet or forgot to remove this reminder to myself. Please send me an email if I've forgotten. ;)

You can download this tutorial and all the project files from the GitHub page. It also contains alternate projects using UIKit and regular (non-Pro) Chipmunk.

What Do You Need to Know First?

This tutorial assumes you have some prior experience with Cocos2D development. It doesn't go into how Cocos2D itself works, although the project is simple enough you can probably figure it out as you go.

What is Chipmunk?

Chipmunk is a 2D rigid body physics library distributed under the MIT license. It is intended to be fast, portable, numerically stable, and easy to use. For this reason it's been used in hundreds of games on just about every system you could name. This includes a lot of successful games such as Waking Mars, Night Sky, Zombie Smash, Feed Me Oil and many others. I've put thousands of hours of work over many years to make Chipmunk what it is today. Check out Chipmunk's website for more information.

What is Objective-Chipmunk and Chipmunk Pro?

Objective-Chipmunk is an Objective-C wrapper for the Chipmunk Physics Library distributed as part of Chipmunk Pro and Chipmunk Indie. While Chipmunk's C API is pretty easy to use, the Objective-C API is even better. The primary advantages of a native Objective-C API include integrating with the Cocoa memory management model (including ARC) and the Chipmunk Object protocol. The Chipmunk Object protocol unifies the basic Chipmunk types as well as making it easy to create custom composite collections of the basic types. Additionally, the wrapper adds many convenience methods for doing common setup tasks as well as helper methods that integrate it with the rest of the Cocoa Touch API. The wrapper tries to do things the Objective-C way, adding useful method variations where it makes sense to do so.

You can find out more information on Chipmunk's website. While Objective-Chipmunk is not free like Chipmunk is, the enhanced API will almost certainly save you time and money. You'll also be helping to support further Chipmunk development!

Overview

Some of the things you'll see in this tutorial.

Let's get started!

This color matching tutorial is inspired by Crayon Ball. In this tutorial game, the goal is to get 4 balls of the same color to touch. Then they are removed. You can interact with the balls in the scene by popping them to make room for more matches. Of course, this is a physics tutorial, so the balls will be rolling over each other in a big pile. The tutorial demonstrates collision handler callbacks, adding and removing physics objects, CCPhysicsSprite, and a lot of Chipmunk basics. Unlike some of our other tutorials, this one is more of a complete game.

As I said earlier, it's assumed that you already know how to create a Cocos2D project, and how some of the basic Cocos2D things like scenes and such work. I won't bore you with that by repeating how to do it here. There are many many tutorials on that already. One thing to note is that I'm using ARC in this project. So you might want to read up on how to do that in a Cocos2D project as the templates aren't made for it by default.

Ball.m

The [MainLayer init] method:

Starting in MainLayer.m; let's look at the init method. First it starts out by setting up some Cocos stuff (enabling touch, creating the foreground/background sprites and forcing high quality texture filtering for the balls. I won't paste the code here as it's not related to the physics really.

Next is the basic setup of the space. The collision slop is the amount of overlap that objects are allowed to have. Increasing the slop makes it more likely that that they will stay in contact over many frames. That's desirable for this game because if the contacts kept appearing and disapearing it would affect the ability of the game to find groups of colors to match out. It might take a few frames for all of the contacts to be active at the same time. The default value of the collision slop is 0.1, which is reasonable to keep the contact solution stable, but not enough for visible overlap if you are using pixels as your distance units. In general, setting colision slop as high as you can without causing visible overlap will make your simulation run more stably.

    // Set up the physics space
    _space = [[ChipmunkSpace alloc] init];
    _space.gravity = cpv(0.0f, -500.0f);
    // Allow collsion shapes to overlap by 2 pixels.
    // This will make contacts pop on and off less, which helps it find matching groups better.
    _space.collisionSlop = 2.0f;

Next up, we add the collision handler callbacks. In Objective-Chipmunk, this takes the form of a target and set of selectors. A collision handler is a set of methods that are called when two shapes that are tagged with specific collision type identifiers collide. This lets you only register for the collisions that you are interested in, like a player touching a monster, instead of having to process every collision that ever occurs.

What we are doing here is iterating the collision types of the balls and registering a callback when two balls of the same color touch. We only want to get callbacks for the preSolve events which are called every frame, so the rest of the selectors are nil. You'll see what the markPair:space: method does later.

    // Set up collision handlers for each of the colors.
    for(cpCollisionType type in [Ball collisionTypes]){
      // Call the markPair:space: method each time a collision is detected between two balls of the same color.
      [_space addCollisionHandler:self typeA:type typeB:type begin:nil preSolve:@selector(markPair:space:) postSolve:nil separate:nil];
    }

There is a nice convenience method in Objective-Chipmunk for putting segment shapes around the edges of a box. Remember how the edge shapes have their layers property set to PhysicsEdgeLayers. We'll talk about that more later when processing the touch events.

    // Add bounds around the playfield
    [_space addBounds:CGRectMake(130, 139, 767, 1500) thickness:20 elasticity:1.0 friction:1.0 layers:PhysicsEdgeLayers group:CP_NO_GROUP collisionType:nil];

Cocos2D v2.1 and up now ships with two handy classes that I wrote named CCPhysicsDebugNode and CCPhysicsSprite. CCPhysicsDebugNode is really useful when you are developing your game so you can see that your collision shapes and joints line up with your graphics in the way you expect.

The last thing in the init method is to create the CCPhysicsDebugNode to draw the collision shapes. I made it invisible by default as it gets in the way of the game. There is also some Cocos2D menu code following this to toggle the visibility.

    // The debug node will draw an overlay of the physics shapes.
    // Very useful for debugging so that you know your collision shapes and graphics line up.
    CCPhysicsDebugNode *debugNode = [CCPhysicsDebugNode debugNodeForChipmunkSpace:_space];
    debugNode.visible = FALSE;
    [self addChild:debugNode z:Z_PHYSICS_DEBUG];

The [MainLayer addBall:] and [MainLayer removeBall:] methods:

The addBall: method is pretty straightforward. It adds the ball to _balls array, adds the ball to the space and adds the sprites for the ball to the scene. Each ball has two sprites. The base sprite, and a second overlay sprite that gives it a shading effect.

// Add a Ball object to the scene.
-(void)addBall:(Ball *)ball
{
  [_balls addObject:ball];
  
  // The Ball class implements the ChipmunkObject protocol so you can add it directly to the space.
  [_space add:ball];
  
  // Add each sprite for the ball to the scene.
  for(CCNode *node in ball.sprites){
    [self addChild:node];
  }
}

The removeBall: method shouldn't have any surprises. Particle effects are good, so I threw in some confetti particles.

// This method should look suspiciously similar to addBall:
-(void)removeBall:(Ball *)ball
{
  [_space remove:ball];
  
  for(CCNode *node in ball.sprites){
    [self removeChild:node];
  }
  
  [_balls removeObject:ball];
  
  // Draw the confetti particles whenever a ball is removed.
  CCParticleSystem *particles = [[CCParticleSystemQuad alloc] initWithDictionary:PopParticles];
  particles.position = ball.pos;
  particles.autoRemoveOnFinish = TRUE;
  [self addChild:particles z:Z_PARTICLES];
}

The [MainLayer update:] method:

Now let's skip ahead to the update: method. This is the method that Cocos2D calls each time before it draws a frame. The dt variable that it passes is usually going to be about 1/60th of a second, but it's never quite consistent. This is somewhat undesirable for the physics. It's not a good practice to update the physics with these variable sized timesteps because sometimes the CPU might be busy for a few frames. Then the next time you update the physics enough time may have passed so that objects can pass through each other. It also makes the gameplay very non-deterministic and it will act a little differently depending on the framerate.

Instead, you'll want to implement a fixed timestep with Chipmunk. This is really easy to do. I usually do this in all of my games, not just physics ones for the same reasons. Keep the code that updates graphics in update: and create a separate tick: method that handles all the game logic and runs with a fixed timestep. If you want to know more about fixed timesteps, the article in the comment below is a good resource.

// This is the update method called by Cocos2D each time it draws a frame.
// It implements a fixed timestep to keep the physics running smoothly and deterministically.
// Using a fixed timestep is *highly* recommended with Chipmunk.
// A good article on fixed timesteps can be found here: http://gafferongames.com/game-physics/fix-your-timestep/
// I consider extrapolation/interpolation to be fairly optional unless the tickrate is slower than the framerate.
-(void)update:(ccTime)dt
{
  ccTime fixed_dt = 1.0/(ccTime)TICKS_PER_SECOND;
  
  // Add the current dynamic timestep to the accumulator.
  // Clamp the timestep though to prevent really long frames from causing a large backlog of fixed timesteps to be run.
  _accumulator += MIN(dt, 0.1);
  // Subtract off fixed-sized chunks of time from the accumulator and step
  while(_accumulator > fixed_dt){
    [self tick:fixed_dt];
    _accumulator -= fixed_dt;
  }
}

The [MainLayer tick:] method:

So then the tick: method is the code that runs with a fixed timestep, independent of the framerate. So far in the game we have an empty playing field without any balls in it. It would be nice if it filled up slowly over time until there were a set number of balls onscreen. An easy way to do that is to check the number of balls and add one every few frames if the number is below that number. Additionally, it tries to insert the ball into the playing field at an empty spot. [ChipmunkSpace shapeTest:] returns true if the shape is overlapping something else in the space given the regular collision filtering rules.

// The tick: method is the fixed timestep. See update: for more information.
-(void)tick:(ccTime)dt
{
  // Attempt to add a ball every 6 ticks if the playfield has less than 70 balls.
  if(_ticks%6 == 0 && _balls.count < 70){
    Ball *ball = [Ball ball];
    
    // Try up to 10 times to find a clear spot to insert the ball.
    for(int i=0; i<10; i++){
      // Give the ball a random position.
      ball.pos = cpv(512.0f + 300.0f*frand_unit(), 1000.0f);
      
      if(![_space shapeTest:ball.shape]){
        // If the area is clear, add the ball and exit the loop.
        [self addBall:ball];
        break;
      }
    }
  }

While Chipmunk will be passing information on when any two balls of the same color are touching, we still need a way to detect when a group of four balls are touching. To do that, I'll be using the disjoint-set forest algorithm. I won't go into too much detail on how it works in the tutorial, but you can find out more information from the wikipedia page. Before having Chipmunk call markPair:space: to tell us which balls are touching, we need to reset the properties back to their default states. You'll see what there are used for in a couple paragraphs.

  // Reset the component properties
  for(Ball *ball in _balls){
    ball.componentCount = 1;
    ball.componentRoot = ball;
  }

Now we can update the space by telling it to step forward in time by the fixed timestep amount. This is also when Chipmunk calls all the collision handler callbacks, one for each pair of shapes that match a collision handler definition. (There is also a default collision handler that you can define if you want to process all the other collisions as well, but this is rarely needed.)

  // Step the space forward in time.
  // This is what actually makes the physics go.
  [_space step:dt];

During the step, Chipmunk has called the markPair:space method a bunch of times. All the information about what group balls are in, and how many balls in each group will be filled in for us. All we need to do then is to iterate all the balls and check if their group has more than 4 balls in it. If so, remove the ball and make a pop noise for each one. I like to bend the pitch up or down a few notes for variety.

Notice that I'm iterating a copy of the _balls array. There are very few data structures where it's safe to remove objects while iterating. NSMutableArray is no exception. Making a copy of the array to iterate is the simplest solution. People usually get strangely worried about the performance impact of doing this, but it's really a non-issue most of the time. Check the profiler if you don't believe me. ;)

  // At this point Chipmunk called markPair:space: a bunch of times.
  // Look for balls in components with 4 or more balls and remove them.
  // Not that I'm iterating a copy of the _balls array.
  // You can't remove objects from an array while iterating it.
  for(Ball *ball in [_balls copy]){
    // Get the component's root and check the count.
    Ball *root = ball.componentRoot;
    if(root.componentCount >= 4){
      [self removeBall:ball];
      
      // Play a pop noise.
      int half_steps = (arc4random()%(2*4 + 1) - 4);
      float pitch = pow(2.0f, half_steps/12.0f);
      [[SimpleAudioEngine sharedEngine] playEffect:@"ploop.wav" pitch:pitch pan:0.0 gain:1.0];
    }
  }
  
  _ticks++;
}

The [MainLayer markPairs:space:] method:

Now we need to implement the markPairs:space: method that we used with the collision handlers earlier. This is the method that will be doing all the work to figure out how big our groups of colors are.

Chipmunk collision handler methods take a pointer to a cpArbiter C struct and the ChipmunkSpace object that the collision handler was registered with. The cpArbiter pointer is to a C struct instead of an Objective-C object is for a couple reasons. First, Chipmunk's C code manages the memory for cpArbiters, and it's an error to store the pointer anywhere. The other reason is for performance. Chipmunk pools a lot of cpArbiters, discarding and reusing them constantly. Creating an Objective-C object every time to wrap them would be very expensive. Lastly, begin and preSolve collision handler callbacks must return a boolean value. For begin callbacks, returning false means to ignore the collision until separate is called. The preSolve and postSolve callbacks will never be called and there will be no collision response. Returning false from a preSolve callback means to ignore the collision response for the current step only. This gives you a very powerful way to filter collisions dynamically. In this game, we want to return true all the time so the collisions are processed normally.

-(bool)markPair:(cpArbiter *)arb space:(ChipmunkSpace *)space
{

Generally the first thing you want to do in a collision handler callback is get the shapes or bodies involved in the collision. Objective-Chipmunk provides two macro functions to help with that. CHIPMUNK_ARBITER_GET_BODIES() and CHIPMUNK_ARBITER_GET_SHAPES(). Both macros take a cpArbiter * and the names of the two variables it should define. The collision types of the colliding shapes will have the same order as when the collision handler was defined. In this case, we are looking for the times when two balls of the same collision type (their color) collide so the order is unimportant.

  // Get the two shapes involved in the collision.
  // This macro defines the shapeA and shapeB variables for you.
  CHIPMUNK_ARBITER_GET_BODIES(arb, shapeA, shapeB);

If you could only get information on the shapes and bodies that were involved in the collision, you wouldn't be able to do much. For that reason, nearly every Chipmunk object has a data pointer that you can assign to something related to that object, generally the game object that owns it. For example, we set the data pointers on the ball's body and shape to the ball object itself. We need the ball object because we store the grouping information there.

  // We set the shapes' data pointers to point to the ball that owns them.
  Ball *ballA = shapeA.data;
  Ball *ballB = shapeB.data;

To find the groups, I'm using the disjoint-set forest algorithm. The short explanation is that each group of colored balls is identified by a (more or less random) ball in the group. That ball becomes the root and stores the count of the balls in the group. It starts out with each ball being it's own group (and each ball it's own root). Then as markPair:space: is called once for each pair of touching balls, you merge their groups, randomly picking one of the existing roots as the new root. Once all of the touching pairs have been identified, all the balls in the same group will have the same root, and the root will contain the correct count of balls in the group. A very simple algorithm, but a little tricky. Now back in the tick: method it can iterate the balls and remove the ones in groups of more than 4.

  // So the rest of the method is half of the implementation of the disjoint set forest algorithm.
  // I won't further explain the algorithm here, but it's one of my favorites.
  // I use it within Chipmunk itself to find groups of sleeping objects.
  // You can find more information here: http://en.wikipedia.org/wiki/Disjoint_set_forest#Disjoint-set_forests
  
  Ball *rootA = ballA.componentRoot;
  Ball *rootB = ballB.componentRoot;
  
  if(rootA != rootB){
    // Merge the two component trees.
    rootA.componentRoot = rootB.componentRoot;
    rootA.componentCount = rootB.componentCount = rootA.componentCount + rootB.componentCount;
  }

The last thing to do is to return a true/false value telling Chipmunk if the collision should be processed normally or discarded. We don't need to do any fancy filtering here. So we just return true.

  // Returning false would mean Chipmunk should ignore the collision between shapeA and shapeB.
  return TRUE;
}

The [MainLayer ccTouchesBegan:withEvent:] method:

The only remaining game logic to implement in the layer is the user input. Cocos2D provides methods for converting input coordinates. Then all you need to do is to use that point to query Chipmunk for the nearest ball shape. Notice how it's using PhysicsBallOnlyBit, as that layer bit will not be set for the border shapes we created in the init method above.

// This method removes balls when you touch them.
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
  // Convert the touch position to the correct coordinate system.
  UITouch *touch = [touches anyObject];
  cpVect point = [self convertTouchToNodeSpace:touch];
  
  // Perform a nearest point query to see what the closest shape to the touch is.
  // It only finds shapes that are within fingerRadius distance though.
  // Also, it is using PhysicsBallOnlyBit to filter out the results so it will only return a ball and not an edge shape.
  cpFloat fingerRadius = 10.0;
  ChipmunkNearestPointQueryInfo *info = [_space nearestPointQueryNearest:point maxDistance:fingerRadius layers:PhysicsBallOnlyBit group:CP_NO_GROUP];
  if(info.shape){
    Ball *ball = info.shape.data;
    [self removeBall:ball];
    
    int half_steps = (arc4random()%(2*4 + 1) - 4);
    float pitch = pow(2.0f, half_steps/12.0f);
    [[SimpleAudioEngine sharedEngine] playEffect:@"pop.wav" pitch:pitch pan:0.0 gain:1.0];
  }
}

Ball.m:

Collision Types:

Unlike in regular Chipmunk where collision types are plain integers, collision types are unretained id pointers in Objective-Chipmunk that are compared by value (and not using an equals method). This makes it really easy to use anything you want for an identifier. You can use unique object references such as static NSStrings, class objects, or other object references. Because the pointers are unretained, with a little casting you can also safely store selectors (a convenient way to look up unique identifiers), other pointers or integers.

I often use static NSString objects as identifiers. In this case where we need a unique identifier for each of the 6 colors, NSString references don't necessarily make the most sense, but it's still a useful example I think. We create a static NSArray to hold them, and initialize the array in the initialize class method. I also define a class method to expose the variable to the MainLayer.m file.

static NSArray *CollisionTypes = nil;

+(void)initialize
{
  CollisionTypes = @[@"1", @"2", @"3", @"4", @"5", @"6"];
}

+(NSArray *)collisionTypes
{
  return CollisionTypes;
}

The following property methods complete the disjoint-set forest algorithm from earlier. If you want more information on how it works, see the earlier wikipedia link.

// The following two methods implement the other half of the disjoint set forest algorithm.
// See [MainLayer markPairs:space:] for more information.
-(Ball *)componentRoot
{
  if(_componentParent != self){
    // Path compression.
    // Make the next lookup quicker by caching the parent's root.
    _componentParent = _componentParent.componentRoot;
  }
  
  return _componentParent;
}

-(void)setComponentRoot:(Ball *)componentRoot
{
  if(componentRoot == self){
    _componentParent = self;
  } else {
    _componentParent = componentRoot.componentRoot;
  }
}

The init method:

Finally the last piece: the init method for the ball objects. All that is left is to set up the physics of the individual balls.

The first thing to do is set the random properties of the balls. Give them a random color (out of 6 colors), and give them a random radius. The mass of the ball will vary proportionally with the square of the radius, so we'll just set the mass to that. Because we aren't interacting with any physics objects other than just balls, it doesn't really matter what the mass is as long as it's proportional to the other balls.

    int color = arc4random()%6;
    
    cpFloat radius = cpflerp(30.0f, 40.0f, frand());
    // The mass will increase with the square of the radius.
    // Since there are only balls in the game, the actual value don't matter as long as they are relative.
    cpFloat mass = radius*radius;

To create a body, you need to know its mass (which we already have) and moment of inertia. You can think of the moment inertia as being like the rotational mass of the body. The mass is how hard it is to push a body around, and the moment of inertia (often just called the moment) is how hard it is to make it spin. The moment is affected by the mass of the object, its shape, and how the mass is distributed away from the center. A rookie mistake is to guess the moment of inertia and to just put in a number similar to the mass. Don't do that! You are likely to be wrong by several orders of magnitude and your physics will be very glitchy. Use the cpMomentFor*() functions to help you guess the moment of your objects. For a composite shape, add the value of several moments together.

Once you've created the shape, you can fill in the other properties you want such as the position, velocity, angle, data pointer, etc. The position is set by MainLayer.m, so we'll just leave it out. We set the body's data pointer to self here so we can access the ball that owns the body from Chipmunk callbacks.

    // Create the body.
    _body = [ChipmunkBody bodyWithMass:mass andMoment:cpMomentForCircle(mass, 0.0f, radius, cpvzero)];
    // Set the user data pointer of the body to point back at the Ball object.
    // That way you can access the Ball object from Chipmunk callbacks and such.
    _body.data = self;

Next, we create a circle shape attached to the body and fill in the properties we want to define. Friction should be pretty self explanatory, and you already know about the data pointer. The layers bitmask value is used to filter only-balls in the nearest point query method earlier. The collision type property is the object reference that we are using when defining collision handlers.

    // Create the collision shape of the ball.
    _shape = [ChipmunkCircleShape circleWithBody:_body radius:radius offset:cpvzero];
    _shape.friction = 0.7f;
    // The layers is a bitmask used for filtering collisions or queries.
    // See the [MainLayer ccTouchesBegan:withEvent:] method for more info.
    _shape.layers = PhysicsBallLayers;
    // The collision type is an object reference that is used to figure out which if any collision handler to call.
    _shape.collisionType = [CollisionTypes objectAtIndex:color];
    // Set the user data pointer of the shape to point back at the Ball object.
    // That way you can access the Ball object from Chipmunk callbacks and such.
    _shape.data = self;

In order for the Chipmunk objects (bodies, shapes, constraints) to do anything interesting, they generally need to be added to a Chipmunk space. When you add a body to a space, you are asking Chipmunk to update its position. By adding a shape to a space, you are asking Chipmunk to detect and apply collisions with other shapes. Removing the object from the space makes it inactive again. There are also certain things such as static bodies and other so-called, manually updated "rogue" bodies that are not added to the space. Static bodies never move, so you don't want Chipmunk applying gravity to it. For manually updated rogue bodies, you don't want Chipmunk undoing your work. For everything else though, if something isn't added to a space, it's basically inactive.

Objective-Chipmunk has the ChipmunkObject protocol that makes it really easy to add composite physics objects to a space. The ball is a very simple example, containing only a single body and shape, but it becomes very useful for something such as a ragdoll or vehicle composed of many bodies, shapes and constraints. To implement the ChipmunkObject protocol, all you need to do is make a chipmunkObjects method or property that returns an NSArray (or any NSFastEnumeration) of other ChipmunkObjects. This can be any of the basic Chipmunk types such as ChipmunkBody, ChipmunkShape, or ChipmunkConstraint objects, but you can also include your own objects that implement the ChipmunkObject protocol. The latter is very handy when you have complex, hierarchical objects. Since the property is already defined, all we need to do is fill in the instance variable with an NSArray.

    // Set the chipmunkObjects ivar for the property to an NSArray (or any NSFastEnumeration).
    // This is what Chipmunk objects to add and remove from the space.
    _chipmunkObjects = @[_body, _shape];

Lastly, to finish up the ball objects. We need to give them graphics. The CCPhysicsSprite class makes it really easy to bind a CCSprite and a physics body together. The original class I wrote has been extended to support Box2D bodies as well as Chipmunk and Objective-Chipmunk bodies. All you need to do is to assign a body to the sprite after you create it. The sprite will always have the same position and rotation as the body, and changing the sprite will change the position and rotation of the body its attached to. Handy!

    // The main sprite for the ball.
    CCPhysicsSprite *sprite = [CCPhysicsSprite spriteWithFile:[NSString stringWithFormat:@"ball_%d.png", color]];
    sprite.chipmunkBody = _body;
    sprite.scale = 2.0f*radius/(sprite.contentSize.width - 8.0f);
    sprite.zOrder = Z_BALLS;
    
    // The highlight sprite overlain over the regular sprite.
    // It's set to ignore the rotation of the body.
    CCPhysicsSprite *highlight = [CCPhysicsSprite spriteWithFile:@"ball_highlight.png"];
    highlight.chipmunkBody = _body;
    highlight.ignoreBodyRotation = TRUE;
    highlight.scale = sprite.scale;
    highlight.zOrder = Z_BALL_HIGHLIGHTS;
    
    _sprites = @[sprite, highlight];
  }
  
  return self;
}

With that, the ball class is complete. It doesn't actually need any more methods. All of the physics and rendering and handled by Chipmunk and Cocos2D. So there isn't much the Ball class needs to do other than to set up the objects for them.

Conclusion

That basically wraps up the code for the project. At this point you know everything you need to make a color matching game with Chipmunk Pro and Cocos2D. Again, if you want to grab the code for the project, you can get it from the GitHub page.