1.对于一些集成起来的通用配置表,如下面这样的:

还是上图吧

这种通用表,字段直接是value1,value2,value3,value4,value5,value6。

这是GameConfigData里面的类:

 class CGodWingJinJieBase:public cdf::CRefShared{public:Message::Db::Tables::TGodWingConfig _godWingJinJieConfig;};typedef cdf::CHandle<CGodWingJinJieBase> GodWingJinJieBasePtr;

这是使用的代码:

     if(!CGodWingConfigManager::instance()->getJinJieInfoConfig(playerGodWing.jinJieLevel, godWingJinJieConfig)){CErrorCodeManager::throwException("Public_GameConfigDataError");}//判断是否已拥有该皮肤if(!godWingManager->isSkinExist(godWingJinJieConfig.value6, true)){//添加皮肤godWingManager->addGodWingSkin(godWingJinJieConfig.value6, "", gateEntity, player);//设置皮肤godWingManager->setGodWingSkin(godWingJinJieConfig.value6, player, gateEntity);}

这样直接使用value6,以后每个人看到这里的代码,都要去数据库查一下,还得对照一下其他代码。非常麻烦。

在GameConfigData读取的时候应该进行封装,转换成可读取的字段,而不是直接使用。

修改后:

class CGodWingJinJieConfig:public cdf::CRefShared{public:int jie;//阶int jiePropNum;//消耗进阶道具数量int blessValue;//祝福值int attributeId;//属性int skillCode;//技能int skinCode;//皮肤 };typedef cdf::CHandle<CGodWingJinJieConfig> CGodWingJinJieConfigPtr; typedef std::map<int, CGodWingJinJieConfigPtr> MapCGodWingJinJieConfig;
Message::Db::Tables::SeqTGodWingConfig::const_iterator iter1 = tGodWingConfigs.begin();for(; iter1 != tGodWingConfigs.end(); iter1++){switch(iter1->type){case 1://神翼升星的经验{_starExpMap[iter1->value1][iter1->value2] = iter1->value3;}break;case 2://阶的数据{CGodWingJinJieConfigPtr jinJenConfig = new CGodWingJinJieConfig();jinJenConfig->jie = iter1->value1;jinJenConfig->jiePropNum = iter1->value2;jinJenConfig->blessValue = iter1->value3;jinJenConfig->attributeId = iter1->value4;jinJenConfig->skillCode = iter1->value5;jinJenConfig->skinCode = iter1->value6;_jinJieMap[iter1->value1] = jinJenConfig;}break;

这样取出来的配置,别人可以直接使用。

做游戏的代码,一定要时刻准备随时让别人看,因为随时要改。

2.typedef相当于重新声明了一个结构,所以开头应该大写。

typedef std::map<int, GodWingJinJieConfigPtr> mapCGodWingJinJieInfoList;
typedef std::map<int, GodWingExpSkinPtr> mapCGodWingSkinInfoList;
typedef std::map<int, GodWingSkillPtr> mapCGodWingSkillInfoList;
typedef std::map<int, Message::Game::SPlayerGodWingCritPrompt> mapJinJieExpInfoList;

开头的m都应该改成M.

另外,对于这种别名,最好起名字的时候不要带有具体功能意思的名字,毕竟其他地方可以重用的。

3.对于拼音的命名,一个词的开头才大写。是词,不是字。

GodWingJinJieConfigPtr

应该是

GodWingJinjieConfigPtr

如果要用拼音的话。

4.除数不能为0

bool CGodWingConfigManager::getBlessingValue(int jinJieLevel, int blessingValue, bool& isLevelUp, Message::Game::SPlayerGodWingCritPrompt& cirtInfo)
{MapCGodWingJinjieConfig::const_iterator iter1 = _jinJieMap.find(jinJieLevel);if(_jinJieMap.end() == iter1){return false;}if (iter1->second->blessValue <= 0){return false;//这里是我加的。}//获取当前经验百分比int blessPercent = blessingValue * 10000 / iter1->second->blessValue;//load配置的地方没检测,函数内也没有检测//判断是否可以直接进阶int rand = Common::CUtil::myRand(1, 10000);for(DictIntInt::const_reverse_iterator iter2 = _jinjieLevelUpMap.rbegin();_jinjieLevelUpMap.rend() != iter2;++iter2){

5.函数不要用大写开头,类名,结构名都要用大写开头。属性不要用大写。

interface IGodWing{/** 神翼培养接口* @param type 1激活神翼系统,2神翼加经验* @param amount 使用数量* @exception --失败返回异常 使用异常代码*/["ami","amd"] void GodWingLevelUp(int type, int amount);//大写了/** 神翼进阶接口* @param autoBuy 是否自动买 0不自动,1自动* @param result 返回进阶结果 1进阶成功,2进阶失败* @param jinJieValue 返回进阶值* @exception --失败返回异常 使用异常代码*/["ami","amd"] void GodWingJinJie(int autoBuy, out int result, out int jinJieValue);//大写了/** 打开神翼系统接口*/["ami","amd"] void OpenGodWing();//<span style="font-family: Arial, Helvetica, sans-serif;">大写了</span>/** 领取返还进阶石*/["ami","amd"] void getJinJieReward();

居然还写到cdl里面了。。。。。。

6.保存数据库的时候如非必要,都是延时保存。immediatelyUpdate是立即更新的意思,一般使用changeFlag。

//保存数据库getSaveInfo(ETPlayerGodWing).immediatelyUpdate = true;save(false);

7.使用json,有好处也有坏处。好处是比较方便,节省字段。

但是坏处也很明显,

1.多了很多额外的运算

2.极大增加调试的时候查看内存

3.因为不需要声明,所以也就不知道具体有多少字段在里面。

所以一般情况下,

1.json只是用来节省字段,保存数据库的时候才转化一下。

2.对于一些大的系统json的key值放在Common/Config中

3.对于一些小的地方,只是简单一个字符串就行。

4.不保存复杂的结构,太复杂的要考虑新建一个表。

5.如果实在要保存复杂的内容,先转成string,然后保存到json中,登陆的时候,转成各自的结构,要保存的时候才转成字符串。

6.key中要写明是哪个数据类型,value一般只是基础数据类型。

总结得不好,其实我觉得最大问题是,根本没人知道你里面保存的是什么。

bool GateApp::CGodWingManager::isSkinExist(int skinCode, int flag)
{Json::Value json;json.parse(_playerGodWing.skinJsStr);if(flag){for(Json::Value::iterator iter = json[ALL_SKIN_KEY].begin(); json[ALL_SKIN_KEY].end() != iter; ++iter){if((*iter).isInt()){if(skinCode == (*iter).asInt()){return true;}}}}else{for(Json::Value::iterator iter = json[LIMIT_SKIN_KEY].begin(); json[LIMIT_SKIN_KEY].end() != iter; ++iter){if(!iter.key().isNull()){std::string temp = iter.key().asString();if(skinCode == atoi(temp.c_str())){return true;}}}}return false;
}

像这种以后不要再用了。

8.playerExtend和playerExtend2保存

 CPlayerHelper::updatePlayerExtend(gateEntity, player);//用这个player->getSaveInfo(ETPlayerExtend).changeFlag = true;//不要这样写

9.自己写的功能,要每一句代码都调试过才行。

void GateApp::CItemExtend::useProp( CGateEntityPtr gateEntity, CPlayerPtr player,::GateApp::Bag::CBagPtr bag,const CPlayerItemPtr& playerItem,Common::CBaseItemPtr item,int useAmount,const ::Message::Public::SeqString& values)
{switch( item->getTItem().type ){case EPropMountDan:{CItemExtend::useMountAttributeDan(gateEntity, bag, playerItem, item, useAmount);}break;case EPropGodWingDan:{CItemExtend::useMountAttributeDan(gateEntity, bag, playerItem, item, useAmount);//这里明显是坐骑的丹药。。。}break; 

我们做游戏的流程,测试人员只是负责做黑盒测试,因为非技术人员的员工,关注点一般都在客户端。而服务端的bug除非很明显,当然这个是很明显的。否则是测不到的,很多情况下要靠自己的编码习惯来规避一些低级错误。

10.商品价格必须从t_shop_shell中获得,

         //判断元宝是否足够player->enoughMoneyException(EPriceUnitEMoney, cost * oweAmount, updateCode);//商品价格和单位必须从t_shop_shell中获得,//购买道具CShopManager::instance()->buyItem(gateEntity, SHOP_CODE_AUTO_BUY, itemCode, oweAmount, updateCode);//这里根本不需要购买道具,而是在下面直接扣钱

不能自己找个地方配置。

使用商品的时候必须使用t_shop_shell的unit和amount。

商店打折活动肯定会有的。这个必须要注意。

11.对于bool的内容,做判断的时候不要再==true或者==false了。

 tlogGodWing.oldLevel = (true == flag) ? playerGodWing.jinJieLevel - 1 : playerGodWing.jinJieLevel;tlogGodWing.newLevel = playerGodWing.jinJieLevel;tlogGodWing.newExp = playerGodWing.blessingValue + playerGodWing.limitBlessingValue;tlogGodWing.oldExp = oldBless;tlogGodWing.addExp = (true == isLevelUp) ? totalExp - oldBless : exp;

12.在一般的消耗某种道具,然后获得某种属性的流程中,要先判断所有可能抛错误码的情况,然后再去执行扣除道具,最后是获得东西。

按具体的例子来说吧:

在神翼进阶的流程中,先判断了是否有当前配置,然后根据道具为空判断是否为最大阶数。其实是没必要的。下一个阶的配置是无论如何都要获取的。

 //获取进阶信息CGodWingJinjieConfigPtr jinjieConfig = CGodWingConfigManager::instance()->getJinJieConfig(playerGodWing.jinJieLevel); if (!jinjieConfig){CErrorCodeManager::throwException("Public_GameConfigDataError");}//判断是否最高阶数if (0 == jinjieConfig->jiePropNum)//不消耗道具,是最大阶{CErrorCodeManager::throwException("Public_jinJieMaxLevel");}
这是后面,消耗道具之后,再去获取下一阶的配置。如果这里出现问题,之前计算的内容,都白费了,而且还白扣钱了。
 CGodWingJinjieConfigPtr nextJinjieConfig = CGodWingConfigManager::instance()->getJinJieConfig(playerGodWing.jinJieLevel + 1);if (!nextJinjieConfig){CErrorCodeManager::throwException("Public_jinJieMaxLevel");}

这里可以考虑一个问题。在程序运行过程中,极小概率出现意想不到的情况,是先扣除玩家道具呢?还是先给玩家属性?

按理说,玩家处于弱势,扣了钱,不给属性,非常亏,一怒之下可能都不想玩了。好像我们应该优先为玩家考虑的样子。

但是实际情况是,市面上存在各种各样的外挂以及各种各样想占便宜的玩家。如果玩家发现了bug,而这个bug对自己有利,可以不劳而获,即使是极小概率,他们也会去研究,将这种特殊情况出现的概率大大提高,甚至每次都出现。如果是玩家自己发现的还好,可能他自己偷偷刷bug,我们发现了就处理了,没发现也只是影响一个服的问题。但是如果是被外挂利用了,可能在极短时间内,被无数人疯狂刷,这个时候很可能我们就得回档,即使没这么惨,也得各种补偿,对游戏的生命周期大大影响。而且非常打击正常玩家的信心。

说多了,总之是先扣钱,再给属性。

在写代码的时候要有意识,先把可能抛错的放前面,到了扣物品扣钱的那一步开始,通常就不能再去抛错了。

13.还是那一句,起名是非常重要的,关乎后来者能不能正确看你的代码。

这是神翼进阶的代码,同一个函数内的。

int totalExp = jinjieConfig->blessValue;
int totalexp = playerGodWing.blessingValue + playerGodWing.limitBlessingValue;

14.不要在一个语句里面做太多的计算。

其实我是想说三目运算符?:

tlogGodWing.addExp = ( isLevelUp) ? totalExp - oldBless : exp;

出现这种情况,通常都是上面已经分成很多分支了,定义个addExp,在其中复制就好了。可以代码更加清晰。

15.客户端调用接口的时候,一些不是很紧要的代码,可以放在Response之后。

 GodWingJinJieCB->cdeResponse(isLevelUp, exp);//for logMessage::Db::Tables::TLogGodWing tlogGodWing;tlogGodWing.__init();tlogGodWing.userName = player->getTPlayer().username;

就像这样,日志的保存,放在response之后。

16.bool不要和int混用

     //判断皮肤是否已拥有,flag为true检测永久卡中是否已拥有该卡,false检测限时卡中是否已拥有该卡bool isSkinExist(int skinCode, int flag);

一般情况下是不会有问题的,但是如果出问题的时候,只能呵呵呵呵呵呵呵呵呵呵呵呵呵呵呵呵了,碰到过,非常难找。尽量不要用默认类型转换。这相当于削弱了C++强类型的属性,变成弱类型,就会像客户端的Lua一样,非常多bug,而且很难修的。

17.检测限时的皮肤的时候,要判断一下时间是否过期了。虽然已经有每分钟检测的定时器,但是出于严谨,还是要检测一下。

bool GateApp::CGodWingManager::isSkinExist(int skinCode, bool isForever)
{ if (isForever){for (SeqInt::iterator iter = _foreverSkins.begin();iter != _foreverSkins.end();iter ++){if (skinCode == *iter){return true;}} }else{DictIntInt::iterator iter = _limitSkinMap.find(skinCode);if (iter != _limitSkinMap.end()){cdf::CDateTime now;if (iter->second > now.getTotalSecond())//-----这个检测是我加的,本来没有的----------------{return true;//还没过期}} }return false;
}

18.对于穿戴皮肤,传0过来就是脱掉了。没必要弄多一个接口。语义上也是一样的,分出来很多余。

void
::Message::Game::IGodWingImpl::setGodWingSkin_async(const ::Message::Game::AMD_IGodWing_setGodWingSkinPtr& setGodWingSkinCB,
int skinCode,
const ::cde::CContext& context)

下面这个是多余的。

void
::Message::Game::IGodWingImpl::takeOffGodWingSkin_async(const ::Message::Game::AMD_IGodWing_takeOffGodWingSkinPtr& takeOffGodWingSkinCB,
const ::cde::CContext& context)

19.有些函数里面会抛异常,在外面就不用再去抛了。

GateApp::Bag::CBagPtr roleBag = CBagHelper::getBag(gateEntity, EPlayerItemPosTypeRole);
if(!roleBag)
{CErrorCodeManager::throwException("ErrorGate_BagNotExist");
}

实际上函数里面已经抛异常了。。。

GateApp::Bag::CBagPtr GateApp::CBagHelper::getBag( const CGateEntityPtr& gateEntity,const ::Message::Public::EPlayerItemPosType& type, bool isException /*= true*/ )
{::GateApp::Bag::CBagSystemPtr bagSystem = getBagSystem(gateEntity, isException);if (bagSystem == NULL){return NULL;}GateApp::Bag::CBagPtr bag = bagSystem->getBag( type );if ( ! bag && isException ){Common::CErrorCodeManager::throwException( "ErrorGate_BagNotExist" );}return bag;
}

20.对于某些属性,过了某个时间失效的情况。设个定时器,到了这个时间点,就把所有的都改掉。这是策划的思想,而不是程序员的做法。

int CPlayerGodWingTimer::handleTimeout(const cdf::CDateTime ¤tTime, const void *act)
{CGateEntityPtr gateEntity = CGateEntityManager::instance()->findGateEntity( _entityId );if (!gateEntity){return 0;}CPlayerPtr player = CPlayerPtr::dynamicCast(gateEntity->getComponent(ECOMPONENT_TYPE_PLAYER));if(!player){return 0;}CGodWingManagerPtr godWingManager = CGodWingManagerPtr::dynamicCast(gateEntity->getComponent(ECOMPONENT_TYPE_PLAYER_GODWING));if(!godWingManager){return 0;}//等级判断if (player->isFunctionOpen("GodWing")){//清空限时祝福值godWingManager->checkLimitBless(player);}gateEntity->removeTimer(ETIMER_TYPE_PLAYER_GOD_WING_TIMER);CPlayerGodWingTimerPtr timer = new CPlayerGodWingTimer();timer->_entityId = _entityId;cdf::CReactor::instance()->schedule(timer, NULL,cdf::CInterval(1, 5, 0, 0, 0), 0);gateEntity->addTimer(ETIMER_TYPE_PLAYER_GOD_WING_TIMER, timer);return 0;
}

定时器是个很方便的东西,但是用多了可能造成负担。而且这种限定时间,对所有玩家都有效的情况。可能会造成集中时间爆发大量计算。那个时刻会很卡。

而且五点钟,应该是很少人的时候,系统一般都进行一些比较耗时的操作,更新升级维护备份什么的。说多了,就是尽量不要用定时器。

正确的做法是在用到的时候,检测一下,发现时间过时了,就更新一下。

void
::Message::Game::IGodWingImpl::godWingJinJie_async(const ::Message::Game::AMD_IGodWing_godWingJinJiePtr& GodWingJinJieCB,int autoBuy,const ::cde::CContext& context)
{CGateEntityPtr gateEntity;CPlayerPtr player;CGateHelper::getPlayerAndEntity(context, gateEntity, player);//参数检查CCheckInput::validValue(autoBuy, 0, 1);CGodWingManagerPtr godWingManager = CGodWingManagerPtr::dynamicCast(gateEntity->getComponent(ECOMPONENT_TYPE_PLAYER_GODWING));if(!godWingManager){CErrorCodeManager::throwException("Public_NullPointer");}godWingManager->checkLimitBless(player);

makeClientGodWingInfo函数里面也检测一下就够了。

21.虽然我们做的不是网站,但是也要有MVC的概念。发送给客户端的信息应该相对独立。不能从发送给客户端的消息中触发属性的计算。假如没发到呢,难道属性就不用算了?

void GateApp::CGodWingManager::makeClientGodWingInfo(Message::Game::SPlayerGodWingInfo& playerGodWing, CPlayerPtr& player, CGateEntityPtr& gateEntity)
{。。。此处省略。。。if(_isNeedcalc){getGodWingAllAttribute(gateEntity, player, playerGodWing.attributeInfo);getGodWingBaseAttribute(playerGodWing.baseAttribute);_allAttribute = playerGodWing.attributeInfo;_baseAttribute = playerGodWing.baseAttribute;_isNeedcalc = false;}else{playerGodWing.attributeInfo = _allAttribute;playerGodWing.baseAttribute = _baseAttribute;}
}

22.过度依赖json,写出来的代码,调试的时候根本没法看到内存。

void GateApp::CGodWingManager::getActivedSkinEquipSkills(int skinCode, Message::Public::DictIntInt& skillList)
{std::string temp1 = _activeSkinSkillJson[ToStr(skinCode)].asString();if(temp1.empty()){return;}Json::Value js;js.parse(temp1);std::string temp2 = js[ACTIVE_EQUIT_SKILL_LIST].asString();if(temp2.empty()){return;}std::vector<std::string> VecSkill;cdf::CStrFun::split(VecSkill, temp2.c_str(), ';');for(std::vector<std::string>::const_iterator it = VecSkill.begin(); VecSkill.end() != it; ++it){std::vector<std::string> temp;cdf::CStrFun::split(temp, it->c_str(), ',');if(2 != temp.size()){continue;}skillList[atoi(temp[0].c_str())] = atoi(temp[1].c_str());}
}

一层套一层的,无法看。如此复杂的结构,应该新建一个表来保存内容。

后台php统计的时候用到json也是很麻烦的,这样最终还是拖慢整个计算的速度。

凡人修真3D(3)神翼相关推荐

  1. 凡人修真3D(4)神装

    1.for循环的iter如果不是之后特殊要求用到,千万不要提出来,要养成习惯, Message::Db::Tables::SeqTGodEquip::const_iterator it = seqTG ...

  2. 凡人修真3D(1)坐骑

    代码风格请尽量统一,写下来的代码不是自己的,是整个团队的.说不定某天也要看别人的代码,或者某个新来的要看我们的代码.说的不好听,项目时间一长,就会出现人员流动,如果每个人都写一个风格,就会很难看了. ...

  3. 凡人修真3D(2)神兵

    1.命名很重要,不知道上面有么有提过,不过发现了还是写下来吧.命名的时候,要看看这个单词在其他系统中,是否已经被使用了,已经具有特别的意义. 例如:整个游戏里面,表示魔法的都是用magical这个词, ...

  4. 凡人修真3D(6)背包

    1.背包检测空位的时候要注意.直接上代码吧. 正确的做法:检测完之后,需要立刻附加到背包中,才能进行下一次检测. for (SeqPlayerItemPtr::iterator iter = play ...

  5. 《凡人修真2》 架设

    具体内容见 百度网盘 链接:http://pan.baidu.com/s/1qY9wqXe 密码:j9n8 1. 解压文件: 看里面的 视频教程:按照里面的步骤:执行:重要的是:建立数据库 2. 凡人 ...

  6. 鸿蒙生息 不朽凡人,不朽凡人

    不朽凡人是一款Q版仙侠风格手游,游戏不但场景精致,技能特效也十分酷炫,神兵武器幻形更是趣味无穷.还有新颖独特的时装染色系统,翅膀幻形玩法,增长战力的同时还能选择自己的独特造型,满足你的个性化装备需求! ...

  7. Bookmarks_2012_06_13

    Bookmarks 书签栏 VeryCD 邮件 - 入职申请SVN - zengfeng@verycd.com2345网址导航-我的个性化主页-中国最好的网址站我的工作台 - 心动游戏项目管理 手册A ...

  8. 页游《火影忍者》角色和背景遮挡半透明效果的实现

    这里讲的是关于2D游戏的角色和背景以及物体之间的遮挡关系,用半透明角色处理的讨论和实现方式.这里主要是讨论关于页游<火影忍者>里对于角色和背景物体之间的遮挡处理方式.同时也实现了和他一样的 ...

  9. 角色和背景遮挡半透明效果的实现

    这里讲的是关于2D游戏的角色和背景以及物体之间的遮挡关系,用半透明角色处理的讨论和实现方式.这里主要是讨论关于页游<火影忍者>里对于角色和背景物体之间的遮挡处理方式.同时也实现了和他一样的 ...

最新文章

  1. 【camera】基于深度学习的车牌检测与识别系统实现(课程设计)
  2. try finally 中的return
  3. 机器学习竞争其实是一场数据上的竞争
  4. JQ~trigger与bind,触发与绑定何先何后?
  5. matlab 绘图3
  6. Scala 执行流程分析
  7. oracle z中rowid,oracle 10g中的ROWID
  8. c#form+mysql储存读取图片_C#从SQL server数据库中读取l图片和存入图片
  9. 休眠锁定模式– PESSIMISTIC_READ和PESSIMISTIC_WRITE如何工作
  10. [css] 使用纯css来创建一个滑块
  11. arcgis xml 下载 切片_xml格式文件如何用arcgis进行编辑和更新
  12. 统计csv词频_分词词频统计
  13. Eclipse 优化
  14. 梳理常见硬盘存储 I/O 接口相关简称
  15. 使用python给微信推送信息(一)
  16. windows虚拟机dhcp服务器,无法访问虚拟机中的DHCP服务器
  17. 信号与系统--信号以及系统的介绍(一)
  18. 常见模块设计--权限管理(一)
  19. SmartFoxServer(SFS) 是什么?
  20. linux ps -aux 怎么看内存,Linux下ps aux命令 与 查看CPU配置

热门文章

  1. javacv从入门到精通——第三章:基本使用
  2. java折木棍_蓝桥杯算法训练 Sticks(木棍)问题(JAVA)
  3. 安装配置webpack webpack不是内部或外部命令
  4. Unity--Ugui播放mp4视频
  5. MyBatis框架的优缺点及其适用场合
  6. ceph kernel rbd (一): 简介
  7. 基于WebGL架构的3D可视化ThingJS平台—粮仓3D场景
  8. 工程项目提成标准方案_工程项目提成方案汇总
  9. 英国药品信息数据查询(网址)
  10. nofollow标签的作用 nofollow标签添加方法