用 Struct 实现 JSON 存档系统
前段时间群里有朋友在讨论游戏存档的问题,想起了前两年曾经介绍过几种简单的实现存档的方式,分别是采用内置的 game_save() 函数、ini 配置文件和 ds_map 加密存储,其中 ds_map 数据结构可以兼容 JSON 数据,但用 ds_map 来保存某些 JSON 数据可能就会面临反复套娃(ds_map 和 ds_list 相互嵌套)的问题,尽管大部分时候这可能也算不上问题,但 JSON 数据本身就是一个轻量化的数据结构,结果被 GameMaker 的 DS 函数弄得特别笨重,实在很蠢,幸好 YoYo 在 2.3.1 里引入了 Struct 结构体,前段时间 Shaun Splading 和 Matharoo 也都介绍了用 json 和 struct 来实现存档功能,于是今天就来介绍一下如何使用 Struct(结构体) 和 Array (数组)配合实现一套基于 JSON 数据的存档系统吧。
如果不太清楚 JSON 数据是什么的朋友,请看 json.org
存取文件
首先我们自定义两个方法,分别用于把 Json 数据写成文件保存以及读取已经存在的存档文件,当然这两个方法可以广泛运用在其他场景,而不仅仅是读写存档文件,因此单独抽象出来会更通用。
///利用buffer对象将字符串保存为json文件
function SaveString (_string, _filename) {
var _buffer = buffer_create(string_byte_length(_string) + 1, buffer_fixed, 1);
buffer_write(_buffer, buffer_string, _string);
buffer_save(_buffer, _filename);
buffer_delete(_buffer);
}
///利用buffer对象读取json文件并转为字符串
function LoadString (_filename) {
var _buffer = buffer_load(_filename);
var _string = buffer_read(_buffer, buffer_string);
buffer_delete(_buffer);
return _string;
}
以上两个函数中我们存取的其实是字符串信息,而将 json 数据和 struct 结构体相互转化则需要用到新引入的 json_stringify() 和 json_parse() 两个函数,下面我会用一个实际的例子来说明一下具体的使用方法。
示例
假设现在我们有这样一个简单的卡牌游戏,每次点击卡牌则卡牌会反转到正面,并且随机显示一个数字,再次点击则翻回背面。
那我们希望可以利用这套系统来保存画面中卡牌的状态,就需要记录一些基本的信息:
- 卡牌的数量
- 每张卡牌的属性
- 坐标
- 翻转状态
- 数值
这就是我们需要记录的数据结构,大概会长成下面这个样子:
{
card_count : 3, //卡牌数量
[ //卡牌属性数组
{x: 100,y: 200, front: true, num: 7}, //单张卡属性
{x: 150,y: 230, front: false, num: 0},
{x: 200,y: 170, front: true, num: 3},
]
}
那我们现在可以来构造我们的数据保存/读取方法,我们可以在控制其中构造两个存取档案的方法用来
Save = function () {
// 获取卡片数量
var _cardCount = instance_number(oCard);
// 创建卡牌数组根结构体
var _rootStruct = {
cardCount : _cardCount,
cards : array_create(_cardCount)
};
// 写入卡片数据
for (var i = 0; i < _cardCount; i ++) {
var _card = instance_find(oCard, i);
_rootStruct.cards[i] = {
x : _card.x,
y : _card.y,
num : _card.num,
front : _card.front,
}
}
// 把结构体转化为json格式
var _json = json_stringify(_rootStruct);
// 保存为文件
SaveJson(_json, "mysave");
}
Load = function () {
if (!file_exists("mysave")) return;
// 读取JSON转为字符串
var _json = LoadJson("mysave");
// 把json数据转化成结构体
var _rootStruct = json_parse(_json);
// 销毁已存在的卡片卡片
instance_destroy(oCard);
var _cardCount = _rootStruct.cardCount;
var _cards = _rootStruct.cards;
for (var i = 0; i < _cardCount; i ++) {
var _cardData = _cards[i];
// 创建读取的卡片实例
var _card = instance_create_layer(_cardData.x, _cardData.y, "Instances", oCard);
_card.num = _cardData.num;
_card.front = _cardData.front;
}
}
然后我们在控制器的 step 事件中监听“S”和“L”的按键事件来分别执行上面保存和读取的操作
if (keyboard_check_pressed(ord("S"))) { //保存
Save();
}
if (keyboard_check_pressed(ord("L"))) { //读取
Load();
}
现在我们启动游戏,随机点选一下卡牌以后,按下“S”键就可以在对应路径下找到一个"mysave"的文件
用文本编辑器打开这个文件可以看到其中记录的数据
当然在按下“L”键时也能正常加载数据。
最后放出示例工程的下载链接,如果文章没有表述清楚的话,直接看一下代码吧,很简单的小项目,仅供参考,实际运用到自己的项目中的话请按需自行修改
链接: 示例工程 密码: 1kdf