您的位置:首页 > 数据库 > Mongodb

基于mongodb, 设计游戏中的个人背包系统

2015-07-06 20:28 591 查看
本着高效简洁的目的, 根据 <深入学习 MONGODB > 这本书做指导, 数据库设计遵循下面两条规则

规则 1: 预先分配磁盘空间并填充空白数据

规则 2: 文档要自给自足。数据的计算是由 C++ 客户端程序( 这里的客户端程序不是指游戏客户端, 是指数据库服务器)来完成,若查找的信息需要经过计算且无法从文档中获得, 就会付出高昂的性能代价,优化文档使得这些计算信息能从文档中直接获得

////////////////////////////////////////////////////// 分割线 ///////////////////////////////////////////////////////////////

MONGODB 的文档 ( 相当于 MYSQL 的记录 )能非常直观的表达游戏中的逻辑数据结构,并且跟客户端(这里的客户端,是指游戏数据库服务器 )的代码能很好的建立逻辑映射。可以用一个mongodb文档来表示一个游戏角色的个人背包信息。

在 C++ 的服务端代码中, 用下面这个结构体来表达一个背包格子的信息

// 可以表示游戏中的装备(非叠加道具, 比如武器, 盔甲等), 也可以表示叠加道具(比如血瓶,回程卷等)

typedef struct tagItem

{

int nItemID; // 道具唯一编号; 比如某把武器, 或者血瓶, 都有唯一编号的

int nNum; // 数量, 作为可叠加道具, 这个字段才有意义; 作为装备, 这个字段没意义

}ST_ITEM;

而背包信息, 就是一组有限数量的 ST_ITEM 对象集合( 假设背包有 64 个格子 ):

typedef struct tagBagDocument

{

int nCharID; // 角色唯一 ID

int nUsed; // 已使用的格子数, used <= 64

ST_ITEM stBagItemList[ 64 ]; //
如果 stBagItemList[ i ].nItemID 等于 0, 就认为 stBagItemList[ i ] 是空格子

}ST_BAG_DOCUMENT;

在 mongodb 中, 假设数据库 test 中的集合 bag 是存放所有角色的背包信息, 而 bag 中的一个文档, 就是一个角色的背包信息。可以用结构体 ST_BAG_DOCUMENT 来描述文档信息

示范代码:

mongo::DBClientConnection oDB; // 连接 mongodb 的代码省略, 默认 oDB 已经连接到 mongodb 了

// oDB.connect(...)

//创建背包

void CreateBagDoc(const int nCharID)

{

mongo::BSONObjBuilder oBOJ;

oBOJ.append( "characterid", nCharID );

oBOJ.append( "used", 0 ); // 已使用的格子数, 参见页首 规则 2

// 背包有 64 个格子, 参见页首 规则 1

mongo::BSONArrayBuilder arr_o;

for( int i=0; i<64; i++ )

{

mongo::BSONObjBuilder o;

o.append( "itemid", 0 );

o.append( "num", 0 );

arr_o.append( o.obj() );

}

oBOJ.appendArray("array", arr_o.arr());

oDB.insert( "test.bag", oBOJ.obj() );

oDB.ensureIndex( "test.bag", BSON("characterid"<<1), /*unique*/true);

}

//读取背包信息

bool LoadBagDoc(const int nCharID, ST_BAG_DOCUMENT& stBagDoc)

{

memset( ( void* )&stBagDoc, 0, sizeof( stBagDoc ) );

std::auto_ptr< mongo::DBClientCursor > cursor = m_oDB.query( "test.bag", QUERY( "characterid" << nCharID ) );

if( cursor->more() )

{

mongo::BSONObj p = cursor->next();

stBagDoc.nCharID = nCharID;

stBagDoc.nUsed = p.getIntField( "used" );

mongo::BSONObj myarray = p["array"].Obj();

std::vector< mongo::BSONElement > v;

myarray.elems( v );

int i = 0;

std::vector< mongo::BSONElement >::iterator vecIter = v.begin();

for ( ; vecIter!=v.end(); ++vecIter )

{

stBagDoc.stBagItemList[ i ].nItemID = (*vecIter)[ "itemid" ].Int();

stBagDoc.stBagItemList[ i ].nNum = (*vecIter)[ "num" ].Int();

i++;

if ( i >= 64 )

{

break;

}

}

return true;

}

return false;

}

// 删除道具, nPos 是背包格子的下标值, 从 0 开始计数

void DeleteItem(const int nCharID, const int nPos)

{

char szItemID[ 30 ];

sprintf( szItemID, "array.%d.itemid", nPos );

char szNum[ 30 ];

sprintf( szNum, "array.%d.num", nPos );

mongo::BSONObj obj = BSON("$set"<< BSON( szItemID << 0 << szNum << 0 "$inc" << BSON( "used" << -1 ) ) ); // 已使用的格子数 "used" 要减 1

m_oDB.update( "test.bag", QUERY( "characterid" << nCharID ), obj );

}

// 把拾取到的装备放入背包

// nPos 是背包格子的下标值, 从 0 开始计数

// nUsedCell 是更新后已使用的格子数, stItem 是道具信息

void CDBEventFunc::UpdateBagCell(const int nCharID, const int nPos, const int nUsedCell, const ST_ITEM& stItem)

{

char szItemID[ 30 ];

sprintf( szItemID, "array.%d.itemid", nPos );

char szNum[ 30 ];

sprintf( szNum, "array.%d.num", nPos );

mongo::BSONObj obj = BSON("$set"<< BSON( "used" << nUsedCell << szItemID << stItem.nItemID ) );

m_oDB.update( "test.bag", QUERY( "characterid" << nCharID ), obj );

}

// 更新( 增加或者扣除 )可叠加的道具数量

// nPos 是背包格子的下标值, 从 0 开始计数

// nUsedCell 是更新后已使用的格子数, stItem 是道具信息

void CDBEventFunc::UpdateItemNum(const int nCharID, const int nPos, const int nUsedCell, const ST_ITEM& stItem)

{

int nItemID = stItem.nItemID;

int nNum = stItem.nNum;

char szNum[ 30 ];

sprintf( szNum, "array.%d.num", nPos );

char szItemid[ 30 ];

sprintf( szItemid, "array.%d.itemid", nPos );

// 如果堆叠道具的数量为 0, 那么这个格子应该设置为空格子

int nTmpID = ( 0 == nNum ) ? 0 : nItemID;

// 条件修改

mongo::BSONObj obj = BSON("$set"<< BSON( "used" << nUsedCell << szNum << nNum << szItemid << nTmpID ) );

m_oDB.update( "test.bag", QUERY( "characterid" << nCharID ), obj );

}

上述几个函数, 基本上能满足背包系统的一切操作。从开发效率上来看, 在游戏中合理使用 MONGODB, 远胜于 MYSQL。

举一反三,设计其他功能系统时, 比如好友系统, 工会系统, 也可以参照上述的背包系统设计思路,轻松进行开发
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: