本着高效简洁的目的, 根据 <深入学习 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。
举一反三,设计其他功能系统时, 比如好友系统, 工会系统, 也可以参照上述的背包系统设计思路,轻松进行开发

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

  1. 某公司要开发新游戏,请用面向对象的思想,设计游戏中的蛇怪和蜈蚣精

    某公司要开发新游戏,请用面向对象的思想,设计游戏中的蛇怪和蜈蚣精 设定 蛇怪类: 属性包括:怪物名字,生命值,攻击力 方法包括:攻击,移动(曲线移动),补血(当生命值<10时,可以补加20生命值 ...

  2. 基于虚拟现实的游戏中的人工智能:如何使用Python和Pygame实现人工智能

    作者:禅与计算机程序设计艺术 <基于虚拟现实的游戏中的人工智能:如何使用Python和Pygame实现人工智能> 1. 引言 1.1. 背景介绍 随着虚拟现实 (VR) 和增强现实 (AR ...

  3. 基于skynet设计游戏服务端框架

    skynet并不是一个开箱即用的服务端框架,游戏后端在开展业务时,需要根据自身业务特点,合理设计相应的服务端框架.在这里我根据自身的设计目标,写下各方面的选择与取舍.对于小型企业来说,一些商业化的软件 ...

  4. 如何设计游戏中道具功能(一)

    acejoy重新换机房花了一些时间,这一段时间无法登陆.现在终于搞好了.把春节前抽空写的一点东西补上来. 以前写过一些游戏的道具设计,沉淀了几年,一直没有时间回头整理,春节前几日,好多人都回家了,工作 ...

  5. 如何设计游戏中的道具功能(二)

    下面来看看具体的实现代码吧. #ifndef _OBJECT_H #define _OBJECT_H //所有物品的基类 //add by freeeyes #include "Object ...

  6. 如何设计游戏中的道具功能(三)

    对于道具的交换,我原则上是鼓励使用另一个容器去实现. 所有要交易的道具可以放在交易盒子中进行交换. #ifndef _ITEMDEALBOX_H #define _ITEMDEALBOX_H #inc ...

  7. 从游戏中学习产品设计1:充值篇

    游戏,是人类文明的最基本组成部分之一,已知的最古老的数字游戏,是早在公元前15世纪到公元前11世纪的计数游戏<宝石棋>,第一部记述游戏的历史书是3000多年前希罗多德编著的<历史&g ...

  8. 游戏中的人工智能AI设计

    因为在现在的项目中花了很大精力设计和制作怪物AI和技能,所以在这里也做个小总结. 什么叫做游戏中的AI        游戏中的AI可以简单的理解为计算机控制的智能角色,这些智能角色能够通过周遭环境或者 ...

  9. 基于组块设计执行开放世界等距游戏引擎

    文 / Benedikt S. Vogler 过去今年里我一直在开发一款名为Wurfel Engine的游戏引擎.以下大部分内容是对于我在学校中的最后一次考试所发现的一些算式与解决方法的解释并在过去2 ...

最新文章

  1. 命令行编译 WRK ,windbg 调试
  2. Django 函数和方法的区别
  3. k8s创建pod的步骤
  4. 【学术相关】翻倍!研究生招生规模持续扩张!
  5. ruby array_Ruby中带有示例的Array.shuffle方法
  6. 【多目标优化求解】基于matlab金鹰算法求解多目标优化问题【含Matlab源码 188期】
  7. 移除Kubeadm部署的kubernetes环境
  8. 汇编语言8086笔记
  9. Oracle开发专题之:OLAP 函数 (rows 2 preceding / unbounded preceding)
  10. Spyder5 显示器校准 色彩校准
  11. Git文件过大(pack文件过大)
  12. 4.jetson更换python版本
  13. 2022年ccpc威海站
  14. 20175208 张家华 MyCP
  15. 如何组织一场安全、可靠、高效的网络实战攻防演习?
  16. spirngcloud
  17. LNMP架构搭建(源码编译)
  18. 吉安赣吉计算机学校,吉安市撤销32所民办中职学校和2所公办学校中专部(班)...
  19. Android:从零开始打造自己的深度链接库(一):ARouter简介
  20. 现有的人脸数据库介绍及下载链接

热门文章

  1. 博图V14SP1组态下载时报错
  2. 吴恩达ChatGPT《Prompt Engineering》笔记
  3. 正式进军Java的前奏
  4. 第43讲 Android Camera2 API AF自动对焦 第二部分
  5. MATLAB——绘制系统的零极点图
  6. AD部分器件变绿,出现x>25.4mm提示时的解决办法
  7. css中文字闪烁这么实现,css3实现文字闪烁,改变透明度
  8. Java 核心类库面试题
  9. 江山易改本性难移之UART要点
  10. 自媒体运营4个超实用的网站,速速收藏起来