Save inventory data used UserDefault #2751
-
| How to save JSON object in UserDefault, I have plan to save inventory data but don't know how to implement. Any suggest? |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 2 replies
-
| What do you mean by JSON object? If it's something like an object that contains a structure ( |
Beta Was this translation helpful? Give feedback.
-
| Hi, Generally we have a GameData class that we convert it to JSON with RapidJSON and save to some place, locally, remote, UserDefault, etc and method that save/load it to/from JSON. Sample code: // GameData.h #pragma once // keep includes minimal and portable #include <string> #include <vector> #include <unordered_map> #include <fstream> #include <sstream> // rapidjson #include <rapidjson/document.h> #include <rapidjson/writer.h> #include <rapidjson/prettywriter.h> #include <rapidjson/stringbuffer.h> // axmol #include "base/UserDefault.h" #include "platform/FileUtils.h" namespace ax { class GameData { public: // basic game state int coins = 0; int level = 1; // simple collections std::unordered_map<std::string, int> inventory; // e.g. {"potion": 3, "key": 1} std::vector<int> completedLevels; // e.g. [1,2,3] // serialize current state to a compact json string std::string toJsonString(bool pretty = false) const { // build a rapidjson object rapidjson::Document doc; doc.SetObject(); auto& alloc = doc.GetAllocator(); // primitives doc.AddMember("coins", coins, alloc); doc.AddMember("level", level, alloc); // inventory as object rapidjson::Value inv(rapidjson::kObjectType); for (const auto& kv : inventory) { rapidjson::Value k; k.SetString(kv.first.c_str(), static_cast<rapidjson::SizeType>(kv.first.size()), alloc); inv.AddMember(k, kv.second, alloc); } doc.AddMember("inventory", inv, alloc); // completed levels as array rapidjson::Value comp(rapidjson::kArrayType); for (int lv : completedLevels) { comp.PushBack(lv, alloc); } doc.AddMember("completedLevels", comp, alloc); // write to string rapidjson::StringBuffer buffer; if (pretty) { rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer); writer.SetIndent(' ', 2); doc.Accept(writer); } else { rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); doc.Accept(writer); } return buffer.GetString(); } // load state from a json string bool fromJsonString(const std::string& json) { rapidjson::Document doc; if (doc.Parse(json.c_str()).HasParseError() || !doc.IsObject()) { return false; } // read primitives if present if (doc.HasMember("coins") && doc["coins"].IsInt()) coins = doc["coins"].GetInt(); if (doc.HasMember("level") && doc["level"].IsInt()) level = doc["level"].GetInt(); // read inventory inventory.clear(); if (doc.HasMember("inventory") && doc["inventory"].IsObject()) { for (auto it = doc["inventory"].MemberBegin(); it != doc["inventory"].MemberEnd(); ++it) { if (it->value.IsInt()) { inventory[it->name.GetString()] = it->value.GetInt(); } } } // read completed levels completedLevels.clear(); if (doc.HasMember("completedLevels") && doc["completedLevels"].IsArray()) { for (auto& v : doc["completedLevels"].GetArray()) { if (v.IsInt()) completedLevels.push_back(v.GetInt()); } } return true; } // save to axmol user defaults (persistent key-value store) bool saveToUserDefault(const std::string& key, bool pretty = false) const { const auto json = toJsonString(pretty); UserDefault::getInstance()->setStringForKey(key.c_str(), json); UserDefault::getInstance()->flush(); return true; } // load from axmol user defaults bool loadFromUserDefault(const std::string& key) { const auto json = UserDefault::getInstance()->getStringForKey(key.c_str(), ""); if (json.empty()) return false; return fromJsonString(json); } // save to a file in writable path bool saveToFile(const std::string& relativePath, bool pretty = false) const { const auto full = FileUtils::getInstance()->getWritablePath() + relativePath; std::ofstream ofs(full, std::ios::binary); if (!ofs.is_open()) return false; const auto json = toJsonString(pretty); ofs.write(json.data(), static_cast<std::streamsize>(json.size())); return ofs.good(); } // load from a file in writable path bool loadFromFile(const std::string& relativePath) { const auto full = FileUtils::getInstance()->getWritablePath() + relativePath; std::ifstream ifs(full, std::ios::binary); if (!ifs.is_open()) return false; std::stringstream ss; ss << ifs.rdbuf(); return fromJsonString(ss.str()); } // convenient reset void resetDefaults() { coins = 0; level = 1; inventory.clear(); completedLevels.clear(); } }; } // namespace ax |
Beta Was this translation helpful? Give feedback.
Hi,
Generally we have a GameData class that we convert it to JSON with RapidJSON and save to some place, locally, remote, UserDefault, etc and method that save/load it to/from JSON.
Sample code: