游戏开发这个领域相对比较神秘一些,会用一些技巧性的编程技术,当然也不难。

今天我们就来实现游戏开发领域中的读档与存档功能,并剖析其中的技术点:

 

1、首先我们要知道结构体0数组元素的用途。建议看这篇博客:

https://blog.csdn.net/Think88666/article/details/89302555
<https://blog.csdn.net/Think88666/article/details/89302555>

2、new和malloc的本质区别,博客:

https://blog.csdn.net/Think88666/article/details/89684582
<https://blog.csdn.net/Think88666/article/details/89684582>

3、具体实现方法

其实就是将玩家对象序列化成二进制,然后发送到存档服务器保存起来。当然实现方法有很多种,但重要的是稳定与高效

以下是我手动实现序列化玩家对象的代码:

//一次存档数据结构

struct SerializeBinary
{
    DWORD nVersion; //版本 用处详见 
https://blog.csdn.net/Think88666/article/details/90523017
<https://blog.csdn.net/Think88666/article/details/90523017>
    DWORD nDataSize;    //data的大小
    SerializeBinary():nVersion(0),nDataSize(0){}
    DWORD size() { return sizeof(SerializeBinary) + nDataSize; }
    char data[0];    //玩家对象的所有数据
};
//数据块     保存玩家每一个属性的值
struct BinaryBlock
{
    DWORD nType;   //块的类型
    DWORD nDataSize;   //块大小
    BinaryBlock() :nType(0), nDataSize(0) {}
    DWORD size() { return sizeof(BinaryBlock) + nDataSize; }
    char data[0];  //块的实际内容
};


实现思路是我们把每个玩家属性转化成BinaryBlock结构体,再通过内存拷贝存入到SerializeBinary.data中去,并通过SerializeBinary.nDatasize记录所有的BinaryBlock的大小,而每个BinaryBlock又有自己的大小nDataSize,这样我们便可以轻松的通过解析SerializeBinary得到我们想要的数据

完整代码如下:

有一些坑要说一下:

1、指针加1,参考博客

https://blog.csdn.net/Think88666/article/details/90437703
<https://blog.csdn.net/Think88666/article/details/90437703>

大家可以在此基础之上进行一些优化。
#include "stdafx.h" #include <vector> #include <iostream> using namespace
std; typedef unsigned int DWORD; //存档数据块集合 #pragma pack(1) struct
SerializeBinary { DWORD nVersion; //版本 DWORD nDataSize; //data的大小
SerializeBinary():nVersion(0),nDataSize(0){} DWORD size() { return
sizeof(SerializeBinary) + nDataSize; } char data[0]; }; //数据块 struct
BinaryBlock { DWORD nType; //块的类型 DWORD nDataSize; //块大小 BinaryBlock()
:nType(0), nDataSize(0) {} DWORD size() { return sizeof(BinaryBlock) +
nDataSize; } char data[0]; //块的实际内容 }; //装备 struct Equip { DWORD nID; DWORD
nNumber; Equip() :nID(0), nNumber(0) {} }; #pragma pack() class CPlayer {
//为了简写,所有属性都公开 public: vector<Equip> m_goods; //玩家背包物品列表 DWORD m_equip[5];
//身上五个位置对应的装备 id DWORD m_pet; //宠物索引 CPlayer() { memset(m_equip, 0,
sizeof(m_equip)); m_pet = 0; } ~CPlayer() {} //存档函数 char *Save() {
//一般缓冲区的大小是20kb左右 可以自行进行溢出检测,这里是后话,一般20kb足够了! char *buff = new char[1024 * 20];
memset(buff, 0, sizeof(buff)); //placement new 手动构造 SerializeBinary* pbinary =
new (buff)SerializeBinary; pbinary->nVersion = 10000; //版本控制 BinaryBlock
*pblock = reinterpret_cast<BinaryBlock*>(pbinary->data); //依次序列化所有的内容
vector<unsigned char> _bytes; int nSize = 0; int nTotalSize = 0; //玩家背包物品列表 if
(m_goods.size() > 0) { nSize = m_goods.size() * sizeof(Equip);
memcpy(pblock->data, &m_goods[0], nSize); pblock->nType = 111; //物品列表
pblock->nDataSize = nSize; nTotalSize += pblock->size(); } //装备 pblock =
reinterpret_cast<BinaryBlock*>(pbinary->data+nTotalSize); //pblock +=
pblock->size(); nSize = sizeof(m_equip); memcpy(pblock->data, m_equip, nSize);
pblock->nType = 222; //装备 pblock->nDataSize = nSize; nTotalSize +=
pblock->size(); //宠物 pblock =
reinterpret_cast<BinaryBlock*>(pbinary->data+nTotalSize); //pblock +=
pblock->size(); nSize = sizeof(m_pet); memcpy(pblock->data, &m_pet, nSize);
pblock->nType = 333; //宠物 pblock->nDataSize = nSize; nTotalSize +=
pblock->size(); pbinary->nDataSize = nTotalSize; //现在只需要把pbinary存起来即可 return
buff; } //加载存档 void Load(char *buff) { SerializeBinary * pbinary =
reinterpret_cast<SerializeBinary*>(buff); int nTotalSize = 0; while
(pbinary->nDataSize - nTotalSize > 0) { //数据不为空 BinaryBlock *pblock =
reinterpret_cast<BinaryBlock*>(pbinary->data+nTotalSize); switch
(pblock->nType) { case 111: //物品 m_goods.resize(pblock->nDataSize /
sizeof(Equip)); memcpy(&m_goods[0], pblock->data, pblock->nDataSize); break;
case 222: //装备 memcpy(m_equip, pblock->data, pblock->nDataSize); break; case
333: //宠物 memcpy(&m_pet, pblock->data, pblock->nDataSize); break; default:
//error break; } nTotalSize += pblock->size(); } } }; int main() { CPlayer
player; player.m_goods.push_back(Equip()); //装备 player.m_equip[0] = 123; //宠物id
player.m_pet = 123456; char *data = player.Save(); CPlayer player2;
player2.Load(data); cout << "goods:"<<player2.m_goods.size() << endl; cout <<
"pet:" << player2.m_pet << endl; for (int i = 0; i < 5; ++i) { cout << "equip:"
<< player2.m_equip[i] << endl; } delete data; return 0; }
 

友情链接
ioDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信