Create Your Own Level Editor: Part 3/3
In this last portion of the tutorial, you’ll add the ability to delete objects, move them around, complete the level save and reset mechanism, and implement multiple level handling to round out your level editor! By Barbara Reichart.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Create Your Own Level Editor: Part 3/3
55 mins
- Getting Started: Removing Objects From Your Level
- Calculating the Distance to a Line
- Deleting Pineapples From Your Level
- Deleting Ropes Attached to Pineapples
- Moving Objects In Your Level
- Moving Objects - Ropes
- Moving Objects - Pineapples
- Saving Your Level Data
- Resetting Your Level Data
- Menu – Scrolling with CCMenuAdvanced
- Where To Go From Here?
Resetting Your Level Data
First, add the following method prototype to LevelFileHandler.h:
-(void)reset;
Next, add the following method implementation to LevelFileHandler.m:
-(void)reset {
[self loadFile];
}
All that this method does is to load the level file again from the save directory, which overwrites the current changes you've made to the level.
Now you can call the reset
method when the user taps the corresponding menu item in the level editor.
Replace the existing stub for resetLevel in LevelEditor.mm with the following code:
-(void)resetLevel {
[pineapplesSpriteSheet removeAllChildrenWithCleanup:YES];
[ropeSpriteSheet removeAllChildrenWithCleanup:YES];
[ropes removeAllObjects];
selectedObject = nil;
[connectedRopes removeAllObjects];
[fileHandler reset];
[self drawLoadedLevel];
}
The above code first removes all onscreen elements, clears out the selected object, and resets all level data. It then calls reset
on the file handler to reload the level and then draws the newly loaded level.
And that completes the saving and reloading functionality!
Build and run your project, start the editor, make some changes, then tap Save and restart the simulator. The level that loads should now contain your changes. Awesome!
As well, make a few changes to the level and tap Reset. Boom! A nice clean slate to work from!
Menu – Scrolling with CCMenuAdvanced
OK, so far your editor can edit and save a level. But you can only edit, load, and play a single level. That's going to get boring really quickly!
It's time to implement multiple file handling in your level editor.
Create an Objective-C class named MenuLayer with superclass CCLayer
. Also change the file extension of the implementation file from .m to .mm.
Replace the contents of MenuLayer.h with the following:
#import "cocos2d.h"
#import "CCMenuAdvanced.h"
#import "FileHelper.h"
#import "LevelFileHandler.h"
#import "CutTheVerletGameLayer.h"
@interface MenuLayer : CCLayer
+(CCScene*) scene;
@end
In addition to the imports, the above adds a static method that will return a scene containing the menu.
Implement the following static method in MenuLayer.mm:
+(CCScene*)scene {
CCScene* scene = [CCScene node];
[scene addChild: [MenuLayer node]];
return scene;
}
Nothing too complicated here; you're simply creating the MenuLayer
and adding it to an otherwise empty scene.
Now switch to AppDelegate.mm and remove the following import from the top of the file:
#import "LevelFileHandler.h"
Next, add the following import to the top of the file:
#import "MenuLayer.h"
Now switch to AppDelegate.mm and replace the following two lines of application:didFinishLaunchingWithOptions:
:
LevelFileHandler* fileHandler = [[LevelFileHandler alloc] initWithFileName:@"levels/level0"];
[director_ pushScene:[HelloWorldLayer sceneWithFileHandler:fileHandler]];
With these two lines:
// Create menu and pass it to scene
[director_ pushScene: [MenuLayer scene]];
Build and run your project; you should see an amazing...black screen?
Hmm — it looks like you still have some work to do! You'll start by adding a menu to your MenuLayer
.
Add the following initialization method to MenuLayer.mm:
-(id)init {
self = [super init];
if (self) {
NSMutableArray* items = [NSMutableArray array];
int levelNumber = 0;
BOOL fileExists;
do {
fileExists = [FileHelper fileExistsInDocumentsDirectory:[NSString stringWithFormat:@"levels/level%i.xml", levelNumber]];
CCMenuItem* item;
if (fileExists) {
NSString* itemLabel = [NSString stringWithFormat:@"Level %i", levelNumber];
item = [CCMenuItemFont itemWithString:itemLabel target:self selector:@selector(selectLevel:)];
} else {
item = [CCMenuItemFont itemWithString:@"New Level" target:self selector:@selector(selectLevel:)];
}
item.tag = levelNumber;
[items addObject:item];
levelNumber++;
} while (fileExists);
CCMenuAdvanced* menu = [CCMenuAdvanced menuWithArray:items];
[menu alignItemsVerticallyWithPadding:0.0f bottomToTop:NO];
menu.position = CGPointMake(0, -menu.contentSize.height/2);
CGSize winSize = [[CCDirector sharedDirector] winSize];
menu.boundaryRect = CGRectMake(winSize.width/2-menu.contentSize.width/2, 0, menu.boundingBox.size.width, winSize.height);
[self addChild:menu];
[menu fixPosition];
}
return self;
}
The above method first creates an empty array to contain the menu items to be displayed on the screen. The menu should contain one item for each level file present in the documents directory.
As all files in that directory will have been created by your level editor, you can assume that the files will be named like level0.xml, level1.xml, level2.xml and so on.
You next create a loop to iterate over all those files using a counter. At each step, you use the FileHelper
class to check for the existence of a file for the given counter. If the file exists, create a menu item with the file name. If there is no file with the given name, assume that there are no more level files to load, and instead add a menu item named "New Level".
You assign the current level number to each menu item as a tag so that you can identify each menu item uniquely. Then you add the menu item to the array of items.
At this point you have a nice array containing an item for each level — now you need to display them on the screen.
At this point you might see a class that is completely unfamiliar to you - the CCMenuAdvanced
class, which is part of the Cocos2D extensions. Why should you use it here instead of the normal CCMenu
?
The screenshot below does a pretty good job of showing what would happen if you used CCMenu
:
The screen on an iPhone or iPod touch is relatively small, and it's hard to fit more than a few items on the screen without crowding.
If you were to use a standard CCMenu
, then you might have to do something drastic like limit the number of levels in your menu list. But CCMenuAdvanced
supports scrolling and so does away with any screen size limitations.
To display the menu, you first create a CCMenuAdvanced
instance with your array of menu items. Then you set the menu alignment so that it starts adding items from top.
Next you position it on the screen and give it a boundary rectangle which determines the scrolling area. Finally, you add the menu to the menu layer so that it is displayed on screen.
Build and run your app, and you should see your menu on the screen. Go ahead and select one of the menu items!
Whoops — you probably just crashed your app. Oh, right — you need to add the menu handler!
Add the following method to MenuLayer.mm:
-(void)selectLevel:(id)sender {
if ([sender isKindOfClass:CCMenuItem.class]) {
CCMenuItem* item = (CCMenuItem*) sender;
int levelNumber = item.tag;
NSString* fileName = [NSString stringWithFormat:@"levels/level%i", levelNumber];
LevelFileHandler* fileHandler = [[LevelFileHandler alloc] initWithFileName:fileName];
[[CCDirector sharedDirector] replaceScene: [HelloWorldLayer sceneWithFileHandler:fileHandler]];
}
}
The above code simply gets the sender object, casts it back to a CCMenuItem
and retrieves its tag. Next, the tag is used to assemble the level's file name. Finally, the method creates a new game scene with the filename as parameter.
Build and run your project — you should now be able to load any levels you've created or create a new level from the main menu. Have fun creating challenging new levels for your game!