[Part.1] A solution to “Using URLSchemes to send game level through e-mail”

It is always a cool feature allowing your user to design a “game level” and then send it to his/her friends to show it off πŸ™‚

If you have a personal server then this might be easy to implement, you can also use the “challenge feature” in open-feint and in game-center maybe(I haven’t tried this though).

But all these solutions above requires you to have a game server or the user to have a open-feint/game-center account support.

A very simple solution here is to use the URLSchemes to implement this cool feature.

This tutorial will show you how to get these stuffs done:

1.Setting up the scenes
2.Playing with Json files (saving and loading)
3.Sending a e-mail inside your app
4.Playing with the URLSchemes feature (sending and receiving)
5.The summary


1.Setting up the scenes

In order to keep the project as simple as possible we’ll create the following scenes(layers) to make up the project”

a.MainMenu Scene: Dose nothing but hold all the menu-item stuffs

b.MyEditor Scene: Generate a “game level” randomly and save it locally then you can send it to your friends through email

c.MySentLevel Scene: Shows all the “game level” saved locally and you can load each to see what’s inside

d.MyReceivedLevel Scene: Shows all the “game level” received and saved from the email and you can also load each to see what’s inside

Besides all the scene stuffs we’ll create a singleton class named “GameDataManage” to hold all the data and common functions so that we can access anywhere anytime in our project

The last thing we’ll create is the “GameLevelData” class which has the excatly same data-structure as that in the json file

Now that’s all we need for the project and let’s begin to play with json file right now πŸ™‚

2.Playing with Json files (saving and loading)

A good harbit of designing a game is to have your data saved somewhere in a config file instead of writing all of them inside the project. You can use the plist or the xml to do that for sure but our choice here is “json”.

It’s much easier than the xml especially when you need to save some simple data structure and there is a great third-party lib in cocos2d named “TouchJson” to help you work with the json file.

Our config file structure is pretty simple:

[cc lang=”objc”] {
“PlayerName”: “SuperSuRaccoon”,
“SpriteArray”:
[
{
“SpriteName”: “Sprite1”,
“SpritePng”: “raccoon.png”,
“SpriteScale”: 1.2,
“SpritePosition”:
[
{
“XPos”: 120,
“YPos”: 150,
}
] },
{
“SpriteName”: “Sprite2”,
“SpritePng”: “rabbit.png”,
“SpriteScale”: 0.6,
“SpritePosition”:
[
{
“XPos”: 300,
“YPos”: 100,
}
] }
] }
[/cc]

As you can see we have a “Playername” and a “SpriteArray” to hold all the parameters of the CCSprite such as name, png name, scale etc. and the number of the CCSprite is not fixed.

2.1 Load the Json file

It is really a piece of cake to load the json file using TouchJson, you can do it like this:

[cc lang=”objc”] NSString *testJsonFilePath = [[NSBundle mainBundle]pathForResource:@”test” ofType:@”json”];
NSData *testJsonFileData = [[NSFileManager defaultManager] contentsAtPath:testJsonFilePath];
CJSONDeserializer *jsonDeserializer = [CJSONDeserializer deserializer];
NSDictionary *testConfigDict = [jsonDeserializer deserializeAsDictionary:fileData error:nil];
[/cc]

And that’s all, we first read all the data in the file into a NSData object and then use the CJSONDeserializer to convert the NSData to a NSDictionary object (which contains all the data in key-value format)

2.2 Parse the NSDictionary

Now we have the NSDictionary containing all the data and we need to parse it to our “GameLevelData” object.

Here is our GameLevelData class:

[cc lang=”objc”] @interface SpriteData : CCNode {

NSString *spriteName;
NSString *spritePng;
CGPoint spritePosition;
float spriteScale;
}

@property(nonatomic, retain) NSString *spriteName;
@property(nonatomic, retain) NSString *spritePng;
@property(nonatomic) CGPoint spritePosition;
@property(nonatomic) float spriteScale;

@end

@interface GameLevelData : CCNode {

NSString *playerName;
NSMutableArray *spriteArray;
}
@property(nonatomic, retain) NSString *playerName;
@property(nonatomic, retain) NSMutableArray *spriteArray;

@end
[/cc]

For example, here’s how to get the playername:

[cc lang=”objc”] GameLevelData *glData = [[GameLevelData alloc] init];
glData.playerName = [testConfigDict objectForKey:@”PlayerName”];
[/cc]

Simple, right? πŸ™‚

And then the spriteArray inside (a little bit complex):

[cc lang=”objc”] NSArray *spriteArray = [testConfigDict valueForKey:@”SpriteArray”];
for (NSDictionary *spriteInfo in spriteArray) {

SpriteData *spData = [[SpriteData alloc] init];
spData.spriteName = [spriteInfo objectForKey:@”SpriteName”];
spData.spritePng = [spriteInfo objectForKey:@”SpritePng”];
spData.spriteScale = [[spriteInfo objectForKey:@”SpriteScale”] floatValue];

NSArray *spritePosArray = [spriteInfo valueForKey:@”SpritePosition”];
for (NSDictionary *spritePosInfo in spritePosArray) {

spData.spritePosition = ccp([[spritePosInfo objectForKey:@”XPos”] floatValue],
[[spritePosInfo objectForKey:@”YPos”] floatValue]);
}

[glData.spriteArray addObject:spData];
}
[/cc]

and that’s all.

Let’s print all the info of the GameLevelData to see if it is all right:

[cc lang=”objc”] -(void) printGameLeveDataInfo:(GameLevelData *)glData
{
/*Debug Log*/
CCLOG(@”/**************Game level data**************/”);
CCLOG(@”PlayerName: %@”, glData.playerName);

for (SpriteData *spData in glData.spriteArray) {

CCLOG(@”SpriteName: %@”, spData.spriteName);
CCLOG(@”SpritePng: %@”, spData.spritePng);
CCLOG(@”SpritePng: %0.1f”, spData.spriteScale);
CCLOG(@”SpritePosition: %0.1f – %0.1f”, spData.spritePosition.x, spData.spritePosition.y);
}
CCLOG(@”/*******************************************/”);
/*Debug Log*/
}
[/cc]

the output in the console:

[cc lang=”objc”] URLSchemesDemo[1012:207] /**************Game level data**************/
URLSchemesDemo[1012:207] PlayerName: SuperSuRaccoon
URLSchemesDemo[1012:207] SpriteName: Sprite1
URLSchemesDemo[1012:207] SpritePng: raccoon.png
URLSchemesDemo[1012:207] SpritePng: 1.2
URLSchemesDemo[1012:207] SpritePosition: 120.0 – 150.0
URLSchemesDemo[1012:207] SpriteName: Sprite2
URLSchemesDemo[1012:207] SpritePng: rabbit.png
URLSchemesDemo[1012:207] SpritePng: 0.6
URLSchemesDemo[1012:207] SpritePosition: 300.0 – 100.0
URLSchemesDemo[1012:207] /***********************************************/
[/cc]

that’s it! Now we succfully loaded the game data from a json file.

What’s next? Yep, we need write something into the json file.

2.3 Save to the json file

To save the data to a json file we do not need any help from the TouchJson, we just simply write the NSData to the file:

[cc lang=”objc”] [jsonData writeToFile:filePath options:NSDataWritingAtomic error:nil];
[/cc]

But, we do need the help from the TouchJson to convert the NSDictinnary to the NSData, just like what we do loading a json file but reversely:

[cc lang=”objc”] jsonData = [[CJSONSerializer serializer] serializeObject:gameLevelDic error:nil];
[/cc]

All we need to do is to prepare a NSDictionary containing all the data in the same format as the json file(that’s quite a lot of job if you have a complex json file):

[cc lang=”objc”] //save all the level info into a Big Dic
NSMutableDictionary *gameLevelDic = [[NSMutableDictionary alloc] init];
[gameLevelDic setValue:@”sxc” forKey:@”PlayerName”];

NSMutableArray *spriteArray = [[NSMutableArray alloc] init];

//random num of sprites to generate
numOfSprites = 1 + CCRANDOM_0_1() * 10;

for (int i = 0; i < numOfSprites; i++) { //pick raccoon or rabbit NSString *spriteFile = @""; if (CCRANDOM_0_1() > 0.5f) {

spriteFile = @”raccoon.png”;
}
else {

spriteFile = @”rabbit.png”;
}
CCSprite *sprite = [CCSprite spriteWithFile:spriteFile];
sprite.scale = 0.1 + CCRANDOM_0_1() * 1;
sprite.position = ccp(20 + CCRANDOM_0_1() * 400, 20 + CCRANDOM_0_1() * 300);
sprite.tag = i;

[self addChild:sprite];

//Position info
NSMutableDictionary *positionDic = [[NSMutableDictionary alloc] init];
[positionDic setValue:[NSNumber numberWithFloat:sprite.position.x] forKey:@”XPos”];
[positionDic setValue:[NSNumber numberWithFloat:sprite.position.y] forKey:@”YPos”];

//Sprite info
NSMutableDictionary *spriteDic = [[NSMutableDictionary alloc] init];
[spriteDic setValue:spriteFile forKey:@”SpriteName”];
[spriteDic setValue:spriteFile forKey:@”SpritePng”];
[spriteDic setValue:[NSNumber numberWithFloat:sprite.scale] forKey:@”SpriteScale”];

NSMutableArray *posArray = [[NSMutableArray alloc] init];
[posArray addObject:positionDic];
[spriteDic setValue:posArray forKey:@”SpritePosition”];

[spriteArray addObject:spriteDic];
}

[gameLevelDic setValue:spriteArray forKey:@”SpriteArray”];
[/cc]

OK, now our new “game level” is saved to the file in json-style that we want πŸ™‚

PS: a little bit of flaw here, the generated json file has no “line feed” or “space” so it’s a little bit difficult to read (but you can write a little bit of code to solve that in your own way :-))

I’ll post the whole source code after finishing this tutorial in part.2 πŸ™‚

Demo ScreenShot:

β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†

If you feel all the stuffs in this site helped you a lot and you would buy me a beer πŸ™‚

Or get a game I made πŸ™‚


β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†β˜…β˜†