Create Your Own Level Editor: Part 1/3

In this tutorial, you’ll learn how to make a level editor for the Cut the Rope clone that was previously covered on this site. Using the level editor you can easily make new levels. All you have to do is drag and drop the ropes and pineapples to where you like them. By Barbara Reichart.

Leave a rating/review
Save for later
Share

In this tutorial, you’ll learn how to make a level editor for the Cut the Rope clone that was previously covered on this site.

Using the level editor you can easily make new levels. All you have to do is drag and drop the ropes and pineapples to where you like them.

What is cool about this level editor is that it is build into the game, so players can create their own levels directly on their device.

Although a level editor can be incredibly fun for the end-user, it’s also pretty handy for the game developer to quickly assemble levels instead of hand-coding them.

An added benefit is that a level editor allows you to test-drive your game concepts. This can be especially important for physics games like Cut the Rope, as sometimes it can be hard to predict the behavior of the physics engine, but very easy to test those behaviors in real-time.

A level editor is a great way to increase the longevity and utility of your game by providing your players with the power to create their own levels — and even share their creations with other game fanatics.

In this tutorial, you will create a level editor for the Cut the Verlet game that was previously covered on this site. Didn’t catch the game creation tutorial the first time around? You can read about the game implementation in the tutorials below:

Getting Started

You’ll use the updated version of the game available here as a starter project. Download the project and open it in Xcode.

The code in the starter project is nearly the same as in the original tutorial; the biggest difference is that the project now supports Objective-C ARC, where the original project did not. An XML parser has also been added to the original project, which you’ll use in creating your level editor.

Note: the starter project has not been modified to work with an iPhone 5 4″ screen. So when you run the app on a simulator, make sure to use an iPhone 3.5″ simulator instead of the 4″ one!

Choosing a File Format to Save Your Level Data

The first step in creating a level editor is to decide upon a file format to use when saving your level data. There are a lot of ways to persist information in your apps, but the most important features to consider are the following:

  • simple storage format
  • platform-independent
  • machine-readable and human readable — which helps with file debugging! :]

In this project, you’ll use XML to store your levels; it ticks all the boxes above, and lots of readers have likely used XML in some format before.

Next, you need to think about what information you need to store in order to create (or recreate) the level. What can you deduce about the information that needs to be saved just by considering the game screenshot below?

I spy with my little eye…some data to be saved!

Here’s a hint to help make your list complete — think about the properties of objects, besides their position.

So what did you list? Pineapples? Ropes? The background? There’s a lot of information in a level — sometimes more than meets the eye!

Open the spoiler below to see the complete list of the elements in the level that need to be captured in your level editor file:

[spoiler]

  • Pineapple Elements:
    • ID: to identify each pineapple uniquely and to store the connection between a pineapple and ropes
    • Position: x- and y-coordinates
    • Damping: how bouncy your pineapple is — this information is used by the physics engine of the game
  • Rope Elements:
    • Two anchor points, which have the following properties:
      • Body: ID of the body the anchor point is bound to
      • Position: optional, not required when bound to a pineapple. In that case, you should use the position of the pineapple directly
    • Sagginess: how loosely the rope hangs
  • General Elements (which you’ll find in almost every XML file)
    • Header including the XML version
    • Level: One top-level element to bind everything together
  • ID: to identify each pineapple uniquely and to store the connection between a pineapple and ropes
  • Position: x- and y-coordinates
  • Damping: how bouncy your pineapple is — this information is used by the physics engine of the game
  • Two anchor points, which have the following properties:
    • Body: ID of the body the anchor point is bound to
    • Position: optional, not required when bound to a pineapple. In that case, you should use the position of the pineapple directly
  • Sagginess: how loosely the rope hangs
  • Body: ID of the body the anchor point is bound to
  • Position: optional, not required when bound to a pineapple. In that case, you should use the position of the pineapple directly
  • Header including the XML version
  • Level: One top-level element to bind everything together

[/spoiler]

Did you miss any? Don’t feel bad if you did — it isn’t always easy to tell what information is contained in a level just by looking at it.

The sections below describe each of the elements you’re going to store in your XML file in more detail.

Calculating the Position of Your Pineapples

Everything is relative — even pineapple positioning! :]

Since you want your editor to run on both retina and non-retina displays, you should store all positions relative to the screen size. That way, you don’t have to calculate individual placement based on pixels.

How do you do that? It’s pretty easy — you calculate the object’s location by taking the screen location, divide its x coordinate by the screen width, and its y coordinate by the screen height. To see this illustrated, check out the image below:

Try to calculate the level position to the right. Screen width is 320, and the height is 480.

On the left, the relative position is shown for a pineapple in the middle of the screen with a resolution of 320×480. As a quick example, try to calculate the level coordinates yourself for the example on the right!

[spoiler]
(240, 288) translates to (0.75, 0.6).
[/spoiler]

You’ll need to continually translate level positions to screen positions and vice versa throughout your editor, so it makes sense to implement it in a helper class that is easily accessible.

To create the helper class, open the starter project in Xcode, and create a new file with the iOS\Cocoa Touch\Objective-C class template under the Utilities group. Name the class CoordinateHelper, and make it a subclass of NSObject.

Open CoordinateHelper.h and replace its contents with the following:

#import "cocos2d.h"

@interface CoordinateHelper : NSObject

+(CGPoint) screenPositionToLevelPosition:(CGPoint) position;
+(CGPoint) levelPositionToScreenPosition:(CGPoint) position;

@end

The code is quite straightforward. Here, you define prototypes for two methods. Both take a CGPoint coordinate, and return the translated position as a CGPoint.

To create the method implementations, switch to CoordinateHelper.m and add the method below between the @implementation and @end lines:

+(CGPoint) screenPositionToLevelPosition:(CGPoint) position {
    CGSize winSize = [CCDirector sharedDirector].winSize;
    return CGPointMake(position.x / winSize.width, position.y / winSize.height);
}

The above method translates screen positions to level positions. To understand the code, think about the difference between level positions and screen positions for a moment.

The screen position is the absolute position on screen. The result of screenPositionToLevelPosition: therefore should be the level position, which is the position relative to the screen size. All you need to do is first acquire the size of the screen with the winSize property of CCDirector. Then divide the screen position parameter by this screen size and return the resulting coordinate. That’s it!

Now try to implement the reverse of the above method – levelPositionToScreenPosition: in CoordinateHelper.m.

You can do it! If you need help, the spoiler code is below.

[spoiler]

+(CGPoint) levelPositionToScreenPosition:(CGPoint) position {
    CGSize winSize = [CCDirector sharedDirector].winSize;
    return CGPointMake(position.x * winSize.width, position.y * winSize.height);
}

[/spoiler]

OK, go ahead and take a look at the method if you need to verify that your code is correct. The new code is almost exactly the same as screenPositionToLevelPosition:, but instead of dividing by winSize, you now need to multiply.

Barbara Reichart

Contributors

Barbara Reichart

Author

Over 300 content creators. Join our team.