程序运行截图如下:

JSON Save Game例子展示了如何使用QJsonDocument,QJsonObject,QJsonArray保存和加载存档。

许多游戏有存储的功能,允许玩家存储保存游戏进度或者加载存档。在存储游戏,通常将每个游戏对象序列到一个文件中。存储的文件格式有多种多样。其中的一种方式就是使用Json格式,使用的是QJsonDocument,如果希望文件不可读,那么可以将其转换为二进制,这里可以再来个对称加密,更好。

此例子展示了如何存储文件,并且加载json文件。

Character类

角色类代表游戏里面的NPC。还存储了玩家名字,等级,职业等。

此类还提供了read()和write()方法去序列化其成员变量。

class Character{Q_GADGET;public:enum ClassType {Warrior, Mage, Archer};Q_ENUM(ClassType)Character();Character(const QString &name, int level, ClassType classType);QString name() const;void setName(const QString &name);int level() const;void setLevel(int level);ClassType classType() const;void setClassType(ClassType classType);void read(const QJsonObject &json);void write(QJsonObject &json) const;void print(int indentation = 0) const;private:QString mName;int mLevel;ClassType mClassType;};

上述的代码主要关心read和write函数的实现

void Character::read(const QJsonObject &json){if (json.contains("name") && json["name"].isString())mName = json["name"].toString();if (json.contains("level") && json["level"].isDouble())mLevel = json["level"].toInt();if (json.contains("classType") && json["classType"].isDouble())mClassType = ClassType(json["classType"].toInt());}

read()函数,使用QJsonObject获取值填充到Character中。可以使用QJsonObject::operator[]或QJsonObject::value()。如果返回的值不存在则为QJsonValue::Undefined。可以使用QJsonObject::contains()确保其key值存在。

  void Character::write(QJsonObject &json) const{json["name"] = mName;json["level"] = mLevel;json["classType"] = mClassType;}

write()函数与read()函数相反,使用QObject::operator[]()和QJsonObject::insert()进行赋值,如果key存在,那么值将会被覆盖。

下面是Level类:

  class Level{public:Level() = default;Level(const QString &name);QString name() const;QVector<Character> npcs() const;void setNpcs(const QVector<Character> &npcs);void read(const QJsonObject &json);void write(QJsonObject &json) const;void print(int indentation = 0) const;private:QString mName;QVector<Character> mNpcs;};

游戏中还需要等级,每一个npc也需要等级,使用QVector存储Character对象,然后再提供上面类似的read()和write()函数。

void Level::read(const QJsonObject &json){if (json.contains("name") && json["name"].isString())mName = json["name"].toString();if (json.contains("npcs") && json["npcs"].isArray()) {QJsonArray npcArray = json["npcs"].toArray();mNpcs.clear();mNpcs.reserve(npcArray.size());for (int npcIndex = 0; npcIndex < npcArray.size(); ++npcIndex) {QJsonObject npcObject = npcArray[npcIndex].toObject();Character npc;npc.read(npcObject);mNpcs.append(npc);}}}

使用QJsonArray接受json中的数组,调用toObject(0获取Character的Json对象。然后存储到mNpcs中。

  void Level::write(QJsonObject &json) const{json["name"] = mName;QJsonArray npcArray;for (const Character &npc : mNpcs) {QJsonObject npcObject;npc.write(npcObject);npcArray.append(npcObject);}json["npcs"] = npcArray;}

这个是写函数。

上面就是人物和等级相关的类,下面是游戏类。

class Game{public:enum SaveFormat {Json, Binary};Character player() const;QVector<Level> levels() const;void newGame();bool loadGame(SaveFormat saveFormat);bool saveGame(SaveFormat saveFormat) const;void read(const QJsonObject &json);void write(QJsonObject &json) const;void print(int indentation = 0) const;private:Character mPlayer;QVector<Level> mLevels;};

首先定义了SaveFormat的枚举,可以选择存储为Json或者二进制。提供了玩家和关卡相关的成员变量,这里官方给出了下面3个函数的说明:newGame(),saveGame(),loadGame(),这里read()和write()函数被saveGame()和loadGame()使用。

 void Game::newGame(){mPlayer = Character();mPlayer.setName(QStringLiteral("Hero"));mPlayer.setClassType(Character::Archer);mPlayer.setLevel(QRandomGenerator::global()->bounded(15, 21));mLevels.clear();mLevels.reserve(2);Level village(QStringLiteral("Village"));QVector<Character> villageNpcs;villageNpcs.reserve(2);villageNpcs.append(Character(QStringLiteral("Barry the Blacksmith"),QRandomGenerator::global()->bounded(8, 11),Character::Warrior));villageNpcs.append(Character(QStringLiteral("Terry the Trader"),QRandomGenerator::global()->bounded(6, 8),Character::Warrior));village.setNpcs(villageNpcs);mLevels.append(village);Level dungeon(QStringLiteral("Dungeon"));QVector<Character> dungeonNpcs;dungeonNpcs.reserve(3);dungeonNpcs.append(Character(QStringLiteral("Eric the Evil"),QRandomGenerator::global()->bounded(18, 26),Character::Mage));dungeonNpcs.append(Character(QStringLiteral("Eric's Left Minion"),QRandomGenerator::global()->bounded(5, 7),Character::Warrior));dungeonNpcs.append(Character(QStringLiteral("Eric's Right Minion"),QRandomGenerator::global()->bounded(4, 9),Character::Warrior));dungeon.setNpcs(dungeonNpcs);mLevels.append(dungeon);}

初始化函数设置了玩家目前在哪个关卡和相关属性以及NPC。

 void Game::read(const QJsonObject &json){if (json.contains("player") && json["player"].isObject())mPlayer.read(json["player"].toObject());if (json.contains("levels") && json["levels"].isArray()) {QJsonArray levelArray = json["levels"].toArray();mLevels.clear();mLevels.reserve(levelArray.size());for (int levelIndex = 0; levelIndex < levelArray.size(); ++levelIndex) {QJsonObject levelObject = levelArray[levelIndex].toObject();Level level;level.read(levelObject);mLevels.append(level);}}}

read()函数填充mPlayer相关的数据,然后清空关卡然后重置下。

通过读取QJsonArray读取每个关卡的数据。

 void Game::write(QJsonObject &json) const{QJsonObject playerObject;mPlayer.write(playerObject);json["player"] = playerObject;QJsonArray levelArray;for (const Level &level : mLevels) {QJsonObject levelObject;level.write(levelObject);levelArray.append(levelObject);}json["levels"] = levelArray;}

这里的write和上面说的一样。

  bool Game::loadGame(Game::SaveFormat saveFormat){QFile loadFile(saveFormat == Json? QStringLiteral("save.json"): QStringLiteral("save.dat"));if (!loadFile.open(QIODevice::ReadOnly)) {qWarning("Couldn't open save file.");return false;}QByteArray saveData = loadFile.readAll();QJsonDocument loadDoc(saveFormat == Json? QJsonDocument::fromJson(saveData): QJsonDocument::fromBinaryData(saveData));read(loadDoc.object());QTextStream(stdout) << "Loaded save for "<< loadDoc["player"]["name"].toString()<< " using "<< (saveFormat != Json ? "binary " : "") << "JSON...\n";return true;}

加载游戏的关键是存储的什么格式的文件,是save.json还是save.dat这个文件

QJsonDocument可以通过使用QJsonDocument::fromJson()和QJsonDocument::fromBinaryData()读取数据。成功就返回true。

 bool Game::saveGame(Game::SaveFormat saveFormat) const{QFile saveFile(saveFormat == Json? QStringLiteral("save.json"): QStringLiteral("save.dat"));if (!saveFile.open(QIODevice::WriteOnly)) {qWarning("Couldn't open save file.");return false;}QJsonObject gameObject;write(gameObject);QJsonDocument saveDoc(gameObject);saveFile.write(saveFormat == Json? saveDoc.toJson(): saveDoc.toBinaryData());return true;}

存储游戏和loadGame()很像通过官方封装好的QJsonDocument::toJson()和JSonDocument::toBinarayData()存储,一个是读Json,一个是读二进制。

下面是main()函数:

 int main(int argc, char *argv[]){QCoreApplication app(argc, argv);QStringList args = QCoreApplication::arguments();bool newGame = true;if (args.length() > 1)newGame = (args[1].toLower() != QStringLiteral("load"));bool json = true;if (args.length() > 2)json = (args[2].toLower() != QStringLiteral("binary"));Game game;if (newGame)game.newGame();else if (!game.loadGame(json ? Game::Json : Game::Binary))return 1;// Game is played; changes are made...QTextStream(stdout) << "Game ended in the following state:\n";game.print();if (!game.saveGame(json ? Game::Json : Game::Binary))return 1;return 0;}

Qt文档阅读笔记-对JSON Save Game官方实例解析相关推荐

  1. Qt文档阅读笔记-QThread::setPriority(Priority priority)官方解析及实例

    目录 官方解析 博主栗子 官方解析 QThread::setPriority(Priority priority) 这个函数为运行的线程设置了优先级.如果这个线程没有运行,那么这么函数啥事都不会做,并 ...

  2. Qt文档阅读笔记-QGraphicsEffect::draw(QPainter *painter)官方解析与实例

    目录 官方解析 博主例子 官方解析 QGraphicsEffect::draw(QPainter *painter) 这个纯虚函用于绘制效果,并且在原图需要被绘制的时候被调用. 在QGraphicsE ...

  3. Qt文档阅读笔记-共享库的创建与调用

    使用共享库的符号 这个符号可以作用在变量.类.函数中,并且这些都可以被调用端使用. 在编译共享库中,需要使用export符号.在使用端调用的时候使用import符号. 这里是本人从文档中记录的笔记,大 ...

  4. Qt文档阅读笔记-加载HeightMap(高度图)构造3D地形图

    Qt文档阅读笔记-加载HeightMap(高度图)构造3D地形图 QHeightMapSurfaceDataProxy:是Q3DSurface的一个基本代理类. 他是专门加载高度图. 高度图是没有X, ...

  5. Qt文档阅读笔记-Rotations Example相关

    Rotations Example文档阅读笔记 使用这种方式,对y轴和z轴进行旋转. QQuaternion yRotation = QQuaternion::fromAxisAndAngle(0.0 ...

  6. Qt文档阅读笔记-QIODevice解析及Audio Example实例解析

    目录 QIODevice官方解释及个人分析 Audio Example官方实例解析 QIODevice官方解释及个人分析 QIODevice类是Qt中I/O设备的接口. 提供了读和写的接口,QIODe ...

  7. Qt文档阅读笔记-Fortune Client Example实例解析

    目录 官方解析 实例代码 博主增加解析 官方解析 Fortune Client Example 以使用QTcpSocket为例子,服务端可以配合Fortune Server或Threaded Fort ...

  8. Qt文档阅读笔记-对Style Plugin Example实例的解析

    目录 前言 Style Plugin Example SimpleStylePlugin Class 定义 SimpleStylePlugin Class 实现 main()函数 The Simple ...

  9. Qt文档阅读笔记-QWebEngineView及QML WebEngineView

    这里主要是最近有给Java Web项目及Qt项目需要混合,自己搞的QtWebEngine没有问题,而用了项目里面的,就有问题,在此阅读下官方资料,看看能不能解决这样莫名其妙的问题,在此记录下本次的阅读 ...

最新文章

  1. 只用CPU开发自动驾驶轮船,他们居然做到了
  2. OpenGL交互——菜单控制(基础教程)
  3. 真人语音朗读软件_才知道,手机还自带文字转语音功能,一键按下便可实现,网友:赞...
  4. MyBatis中提示:You have an error in your SQL syntax; check the manual that corresponds to your MySQL ser
  5. Robot Framework基础学习(六)
  6. echarts-学习笔记及扩展
  7. 微软面试题:有100万个数字(1到9),其中只有1个数字重复2次,如何快速找出该数字
  8. 【Makefile由浅入深完全学习记录8】条件判断语句
  9. 小程序多个echars_小程序界面与逻辑
  10. android 获取已安装 错误代码,android获取手机已经安装的app信息
  11. 背景图层和普通图层的区别_图层样式(一)—高级混合选项
  12. (2/2)Canvas的交互存为图片-爬坑篇
  13. 骗过70%的人!这个AI能自动给视频配音,真假难辨(不服来试)
  14. [渝粤教育] 西南科技大学 人力资源管理 在线考试复习资料
  15. 分享一波大厂面试题,助力大家拿个好Offer
  16. mysql 保存昵称_mysql 微信用户昵称emoji 完整保存
  17. 中国科学院沈阳计算技术研究所考研问题
  18. IC China展商大唐展讯新潮华虹等2014电子信息百强榜上有名
  19. 1.6在Ubuntu安装QT5.14.2
  20. [SSPU新生赛2019]Coda的题解集

热门文章

  1. 2月5日年初六返沪的情景
  2. windows下配置cvs服务端
  3. android 资料文档共享
  4. 全面认识UML类图元素
  5. 实践 Ubuntu 10.10/11.04 关闭双显卡问题
  6. 最好用的手机端C/C++语言编程软件, 不要说没电脑就不学编程了!
  7. 帮助企业降本增效,提高IT运营效率的六种方法
  8. 在谈数据治理和数字化的时候,别忘了数据标准
  9. 防止Visual C++应用程序缓冲区溢出
  10. 计算机族应常喝的健康饮品