欢迎光临Software MyZone,有问题可留言或到站点论坛发帖,争取第一时间帮忙解决 || 站点论坛:火龙论坛 || 淘宝小店:应小心的易淘屋 【欢迎大家提建设性意见】

【cocos2d-x开发实战 特训99-part5】保存游戏数据 转

欢迎热爱编程的朋友们参与到cocos2d-x编程中,为了给大家提供良好的交流环境,网站以开启QQ群
Software MyZone:66202765(群号,欢迎加入,若满,请加1群)
Software MyZone 1群(2dx):286504621
【加群请写:Software MyZone或者是firedragonpzy】
淘宝店:【应小心的易淘屋】初次开店,大家多多支持……
群论坛:火龙论坛正试运营阶段,欢迎大家多提些建设性意见……
摘自:http://codingnow.cn/cocos2d-x/1437.html

上一篇完成了游戏结算界面,但是数据都是假的,这篇来实现游戏数据的保存,这个游戏的玩法就是根据玩家游戏坚持的时间计算游戏分数,然后给予玩家一个荣誉称号。我把荣誉称号保存在level.xml文件中,因为cocos2d-x不支持直接显示中文,level.xml文件内容如下:

< ?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="xiaobing">小兵</string>
    <string name="banzhang">班长</string>
<string name="paizhang">排长</string>
<string name="lianzhang">连长</string>
<string name="yingzhang">营长</string>
<string name="tuanzhang">团长</string>
<string name="lvzhang">旅长</string>
<string name="shizhang">师长</string>
<string name="junzhang">军长</string>
<string name="siling">司令</string>
</resources>
格式跟android中的资源文件string.xml差不多。
首先需要完成一个xml文件的解析类,我直接拿以前写过的一个XmlParser类,可参考cocos2d-x 显示中文字符和解析XML文件这篇博客。
因为现在使用的是cocos2d-x 3.0版本,有点差别,需要修改XMLParser::initWithFile函数:
bool XMLParser::initWithFile(const char *xmlFileName)
{
 m_pDictionary = new CCDictionary();
 SAXParser _parser;
 _parser.setDelegator(this);
 
 auto sharedFileUtils = FileUtils::getInstance();
 string fullPath = sharedFileUtils->fullPathForFilename(xmlFileName);
 return _parser.parse(fullPath.c_str());
}
先来添加几个辅助函数,在GameScene.cpp中添加代码:
int g_gameTime = 0;
 
string getLevel(int score) {
 string ret = "";
 if(score < 20) {
  ret = "xiaobing";
 }else if(score < 30) {
  ret = "banzhang";
 }else if(score < 40) {
  ret = "paizhang";
 }else if(score < 50) {
  ret = "lianzhang";
 }
 else if(score < 60) {
  ret = "yingzhang";
 }else if(score < 70) {
  ret = "tuanzhang";
 }else if(score < 80) {
  ret = "lvzhang";
 }else if(score < 90) {
  ret = "shizhang";
 }else if(score < 100) {
  ret = "junzhang";
 }else if(score >= 120) {
  ret = "siling";
 }
 return ret;
}
 
int getBulletNum(int score) {
 int ret = 10 + score;
 if(ret > 100) {
  ret = 100;
 }
 return ret;
}
变量g_gameTime ,用来保存游戏进行的时间。getLevel函数根据游戏分数返回荣誉名称,后面就根据这个荣誉名称返回xml中对应的中文名称。getBulletNum函数是根据游戏分数返回屏幕上子弹的最大数目。
在GameScene::init函数中添加:
g_gameTime = 0;
每次游戏开始时初始化该值为0.
修改GameScene::createBullet函数:
int maxBulletNum = getBulletNum(g_gameTime);
if (_bullets->count() >= maxBulletNum)
{
 return;
}
之前是写死的10颗子弹,现在改成由玩家游戏时间决定子弹最大数目。
修改GameOverLayer::init函数:
bool GameOverLayer::init()
{
 bool ret = false;
 do {
  CC_BREAK_IF( !this->initWithColor(Color4B(105, 105, 105, 128)) );
  Size visibleSize = Director::getInstance()->getVisibleSize();
  Point origin = Director::getInstance()->getVisibleOrigin();
 
  auto title = Sprite::create("girl.png");
  title->setPosition(Point(origin.x + visibleSize.width / 2, origin.y + visibleSize.height - title->getContentSize().height / 2 - 100));
  this->addChild(title);
 
  auto scorePanel = Scale9Sprite::create("content_bg.png");
  scorePanel->setPreferredSize(Size(500, 250));
  scorePanel->setPosition(Point(origin.x + visibleSize.width / 2, title->getPositionY() - title->getContentSize().height / 2 - scorePanel->getContentSize().height / 2 - 80));
 
 auto purpleBase = Sprite::create("purple_base.png");
  purpleBase->setScaleY(1.2f);
  purpleBase->setScaleX(1.3f);
  purpleBase->setPosition(Point(origin.x + purpleBase->getContentSize().width / 2, scorePanel->getPositionY() + scorePanel->getContentSize().height / 2 + 60));
 
  char tmp2[4];
  sprintf(tmp2, "%d", g_gameTime);
  string scoreStr(tmp2);
 
  auto newScoreLabel = LabelAtlas::create(scoreStr.c_str(), "number_large.png", 64, 90, '0');
  newScoreLabel->setScale(0.8f);
  newScoreLabel->setPosition(Point(purpleBase->getContentSize().width / 2 - newScoreLabel->getContentSize().width / 2 + 20, purpleBase->getContentSize().height / 2 - newScoreLabel->getContentSize().height / 2 + 30));
  purpleBase->addChild(newScoreLabel);
 
 auto newRecordText = Sprite::createWithSpriteFrameName("record_breaking.png");
  newRecordText->setPosition(Point(purpleBase->getContentSize().width / 2, purpleBase->getContentSize().height - newRecordText->getContentSize().height / 2));
  purpleBase->addChild(newRecordText);
 
 auto levelText = Sprite::createWithSpriteFrameName("level.png");
  levelText->setPosition(Point(levelText->getContentSize().width / 2 + 140, scorePanel->getContentSize().height - levelText->getContentSize().height - 30));
  levelText->setScale(1.5f);
  scorePanel->addChild(levelText);
 
  auto userDefault = UserDefault::getInstance();
  int oldScore = userDefault->getIntegerForKey("score");
  if(g_gameTime < = oldScore) {
   newRecordText->setVisible(false);
  }
 
int maxScore = g_gameTime > oldScore ? g_gameTime : oldScore;
  userDefault->setIntegerForKey("score", maxScore);
  XMLParser *pXmlParser = XMLParser::parseWithFile("level.xml");
  string level = ::getLevel(maxScore);
  CCString *pValue1 = pXmlParser->getString(level.c_str());
  auto levelDescText = LabelTTF::create(pValue1->getCString(), "Arial", 40);
  levelDescText->setColor(Color3B(220, 145, 39));
  levelDescText->setPosition(Point(levelText->getPositionX() + levelText->getContentSize().width + 60, levelText->getPositionY()));
  scorePanel->addChild(levelDescText);
 
 auto maxText = Sprite::createWithSpriteFrameName("max.png");
  maxText->setScale(1.5f);
  maxText->setPosition(Point(levelText->getPositionX(), levelText->getPositionY() - levelText->getContentSize().height - 50));
  scorePanel->addChild(maxText);
 
char tmp[4];
  sprintf(tmp, "%d", maxScore);
  string maxScoreStr(tmp);
  auto maxScoreLabel = LabelAtlas::create(maxScoreStr.c_str(), "number_large.png", 64, 90, '0');
  maxScoreLabel->setPosition(Point(levelDescText->getPositionX() - 30, maxText->getPositionY() - maxText->getContentSize().height / 2 - 10));
  maxScoreLabel->setScale(0.6f);
  scorePanel->addChild(maxScoreLabel);
  this->addChild(scorePanel);
  this->addChild(purpleBase);
 
//C++11之lambda表达式
  auto startBtnItem = MenuItemImage::create("", "", [](Object *sender) {
    Scene *scene = GameScene::scene();
    Director::getInstance()->replaceScene(scene);
  });
 
 auto btnSprite = Sprite::create("btn_yellow.png");
  startBtnItem->setNormalSpriteFrame(btnSprite->getDisplayFrame());
  startBtnItem->setPosition(Point(origin.x + visibleSize.width / 2, origin.y + startBtnItem->getContentSize().height / 2 + 150));
  auto startMenu = Menu::create(startBtnItem, NULL);
  startMenu->setPosition(Point::ZERO);
  this->addChild(startMenu);
 
 auto startBtnText = Sprite::createWithSpriteFrameName("again_game_text.png");
  startBtnText->setPosition(startBtnItem->getPosition());
  this->addChild(startBtnText);
 
ret = true;
 }while(0);
 return ret;
}
使用UserDefault来保存游戏历史最高分数,然后根据最高分数活动荣誉名称,再读取xml对应的中文名称。
最后要更新g_gameTime 这个值,以秒为单位计时,在GameScene类中添加:
void updateScore(float dt);
实现updateScore函数:
void GameScene::updateScore( float dt )
{
 if (_isGameOver)
 {
  return;
 }
 
 if( _plane->isVisible()) {
  g_gameTime += dt;
  if(_scoreLabel) {
  char tmp[4];
  sprintf(tmp, "%d", g_gameTime);
  string scoreStr(tmp);
  _scoreLabel->setString(scoreStr);
  }
 }
}

在GameScene::init函数添加:

this->schedule(schedule_selector(GameScene::updateScore),1);

每一秒执行updateScore一次。

运行项目,效果如下: