[Part.1] 利用URLSchemes功能通过邮件发送“游戏关卡”的解决方案

你是否想过为自己的游戏中加入“发送自定义游戏关卡“的功能呢?

如果你有自己的服务器的话当然可以实现,或是使用openfeint的挑战功能以及Gamecenter(这个木有试过)来实现。

但是这些方法总是有些麻烦…要么得有台服务器,要么得使用penfeint/gamecenter(有的用户可能并没有用这些功能)。

其实,使用URLSchemes可以很简单的实现”游戏关卡发送“的功能^_^

本问包括了以下的内容:

1.准备需要的Scene和类
2.JSON文件的读写
3.在游戏内发送邮件
4.使用URLSchemes发送和接收数据
5.总结

1.准备需要的Scene和类

为了保证项目简单易懂,我们首先准备了以下几个Scene:

a.MainMenu Scene: 主菜单,包含了一些跳转的菜单项

b.MyEditor Scene: 随机生成”游戏关卡“并同时保存至本地,也可以通过邮件发送给朋友

c.MySentLevel Scene: 显示所有”发送的关卡“,可以选择关卡进行加载显示内容

d.MyReceivedLevel Scene: 显示所有”通过邮件接收的关卡“,可以选择关卡进行加载显示内容

除了这些Scene以外我们还需要一个使用单件模式的”GameDataManage“类来保存一些数据和提供一些方法,这样我们就可以在项目的所有地方对其进行访问。

最后需要的,是一个与JSON中保存数据结构一一对应的”GameLevelData”类。

OK,准备工作完成,接下来就开始JSON的读写部分^_^

2.JSON文件的读写

写游戏的一个好习惯自然是把一些数据和代码分离出来,用配置文件来进行保存。你可以使用plist或是xml,不过本项目选择使用JSON。

当你的游戏数据结构比较简单的时候,JSON会是一个不错的选择,通过cocos2d自带的”TouchJson”三方库,可以帮助你很轻松的读写JSON文件。

本项目所使用的JSON文件结构:

[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]

结构比较简单,主要是一个用户名,以及保存了CCSprite各种属性的大小可变的”SpriteArray”。

2.1 读取JSON文件

读取JSON格式的文件非常简单:

[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]

首先把文件内容读入NSData,再使用CJSONDeserializer来将NSData转换为NSDictionary。

2.2 解析NSDictionary

NSDictionary中包含了我们所有的游戏数据信息,我们需要将其解析为我们的”GameLevelData”类对:

”GameLevelData“类:

[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]

如何读取”playername“属性内容:

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

很简单吧^_^

读取spriteArray的话就相对比较麻烦了:

[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]

搞定。

顺便把解析后的数据打印出来检查一下:

[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]

控制台输出结果:

[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]

好了, 现在我们已经成功的读取并解析了JSON文件。接下来就是保存JSON文件了。

2.3 JSON文件的保存

其实将NSData保存为JSON文件并不需要使用到TouchJson,只需要:

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

就可以了。

但是我们需要使用TouchJson来将NSDictinnary转换为NSData:

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

NSDictionary中包含的数据必须与JSON的数据结构一一对应,其实就是我们读取解析JSON的一个逆操作:

[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]

这样我们就可以把NSDictioany转换为NSData并写入JSON文件了。

PS: 这里保存好的JSON文件在格式上有一点小问题,文件中没有换行符和缩进,所以看起来比较麻烦,当然你可以自己写一段程序来解决这个问题。

接下来,我们就要在游戏中,通过邮件来发送我们的”游戏关卡“内容了^_^

我会在第二部分完成后把整个项目的源代码下载地址发布出来^_^

项目截图:

☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆

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 🙂


☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆