凡人修真3D(2)神兵

来源:互联网 发布:js闭包坏处 编辑:程序博客网 时间:2024/06/02 10:27

1.命名很重要,不知道上面有么有提过,不过发现了还是写下来吧。命名的时候,要看看这个单词在其他系统中,是否已经被使用了,已经具有特别的意义。

例如:整个游戏里面,表示魔法的都是用magical这个词,现在神兵也用了这个词,很容易造成误解。而且,神兵怎么翻译,好像都翻译不出magical吧。


2.读取TAttribute表的时候,还是要判断一下是否有这个数据的。

bool GameConfigData::CAttributeConfigManager::getAttribute( int attrId,Message::Db::Tables::TAttribute& attr ){MapTAttribute::iterator iter = _attrMap.find(attrId);if (iter != _attrMap.end()){attr = iter->second;return true;}else{return false;}}
因为没有数据的时候,附加上去是没有意义的。而且tAttribute的__init()函数好长,所以传进来是没有初始化的。如果在外面没初始化,可能附加了一个随机数,甚至变负。


3.在for循环的初始化语句的地方,很多人为了缩减语句长度,把第一句抽出来。实际上换行就好了,放进for循环中,就相当于一个局部的属性,这个for循环用完了,这个属性就没有了。如果抽了出来,就会一直存在,下面的for循环必须有一个不同的名字,而且如果类型一样,可能会造成混用,编译器也检查不出来。所以如果不是特殊的需要,请把内容放到for循环中去。

int GameConfigData::CMagicalConfigManager::getStarNum(int promoteLevel, int starLevel){MapMapCStarConfigPtr::const_iterator it = _mapMapStarConfig.begin();//我说的是这句!!!!!要放进for循环中去。int starNum = 0;for (; it != _mapMapStarConfig.end(); ++it){if (promoteLevel > it->first){continue;}starNum += it->second.size();}starNum += starLevel;return starNum;}

4.这个不算是bug,算是一个建议把。在写代码的时候,在一个函数里面,可能一层一层下来,if、switch之类一堆,就会出现很多层。到下面的层就一个屏幕都无法显示出来了。我一般是把一些if语句抽出来,早点return掉,下面的继续执行。说的不是很清楚,看代码吧。

if (needItemCount < promoteConfig->_tMagicalPromote.itemNum ){//数量不足if (autoBuy){ //xxxx这里还有一堆代码,省略了。这部分代码很长很长}else{// 升阶石不足CErrorCodeManager::throwException("ErrorGate_MagicalPromoteStoneNotEnough");}}

一般我会这样写的:
if (needItemCount < promoteConfig->_tMagicalPromote.itemNum ){//数量不足if (!autoBuy){     // 升阶石不足            CErrorCodeManager::throwException("ErrorGate_MagicalPromoteStoneNotEnough");}                //继续执行自动购买的代码。}
这样能尽量减少{}的嵌套。只是个小小建议,我也不知道这样算不算好。


5.代码里面尽量不要写死,对于一些用处比较多的数字,可以用一个常量表示。

int price = 0;int shopCode = 10003;//商店类型CShopPtr shop = CShopConfigManager::instance()->getShop(shopCode);if (shop){
这里面的自动购买商店在CShopConfigManager里面有定义

CShopPtr shop = CShopConfigManager::instance()->getShop(SHOP_CODE_AUTO_BUY);
一开始写代码的时候可能大家都不知道有这种东西存在,不过大家要保持这种意识,留意和多看别人的代码。


6.这个好像提过,不过碰到了就写一下吧。读取商店配置的时候,要用上价格单位和数量。单独的数量是无意义的,而且万一改了货币单位呢!

int price = 0; CShopPtr shop = CShopConfigManager::instance()->getShop(SHOP_CODE_AUTO_BUY);if (shop){CShopSellPtr shopSell = shop->getShopSell(promoteConfig->_tMagicalPromote.itemCode);if (shopSell){price = shopSell->_tShopSell.price;}}//检测是否有钱player->enoughMoneyException(EPriceUnitEMoney, price * promoteConfig->_tMagicalPromote.itemNum, updateCode);
7.除数必须检测是否为0.

例如:

if (tPlayerMagical.blessingValue + tPlayerMagical.limitBlessingValue + addExp >= promoteConfig->_tMagicalPromote.needBlessing)

8.对于配置在t_const里面的复杂的字符串,如果有自己功能的Config管理类,应该在GameCofnigData里面先分解。

// 成功率 = 取祝福值百分比区间的成功率.int successRate = 0;std::string successRateStr = CConstConfigManager::instance()->getConstValueStr("MagicalPromoteSuccessRate");std::vector<std::string> successRateTemp;cdf::CStrFun::split_ex(successRateTemp, successRateStr.c_str(), "[]");for (std::vector<std::string>::iterator iter = successRateTemp.begin(); iter != successRateTemp.end(); ++iter){std::vector<std::string> successRateTemp1;cdf::CStrFun::split(successRateTemp1, (*iter).c_str(), ',');if (successRateTemp1.size() != 2){continue;}if (atoi(successRateTemp1[0].c_str()) < blessingPercent){successRate = atoi(successRateTemp1[1].c_str());}}

像这样的,应该先分解,然后封装在管理类里面了。

std::string successRateStr = CConstConfigManager::instance()->getConstValueStr("MagicalPromoteSuccessRate");CUtil::changBracketsStrToMap(_promoteSuccessRate, successRateStr);
bool GameConfigData::CMagicalConfigManager::isPromoteSuccess(int blessingPercent){int rate = 0;for (DictIntInt::iterator iter = _promoteSuccessRate.begin(); iter != _promoteSuccessRate.end(); ++iter){if (blessingPercent < iter->first){break;}else{rate = iter->second;}}int rand = ::Common::CUtil::myRand(1, 10000);return rand < rate;}
内容会清晰和简单很多。

9.关于概率计算的问题,C++中的随机数最大值大概是30000多,不能更大了。另外,一般情况下,设计到战斗和属性之类的,总概率都是10000,用常量FIGHT_RATING。其他的概率一般是100.这个不做要求,但是用到的时候要注意,不要搞错。

bool GameConfigData::CMagicalConfigManager::isPromoteSuccess(int blessingPercent){int rate = 0;for (DictIntInt::iterator iter = _promoteSuccessRate.begin(); iter != _promoteSuccessRate.end(); ++iter){if (blessingPercent < iter->first){break;}else{rate = iter->second;}}int rand = ::Common::CUtil::myRand(1, 10000);//这里总概率是10000,但是上面的配置的总概率是100.return rand < rate;}

10.在一段程序里面,对于一些检测判断,比较容易return或者抛异常的,应该放在前面。变量尽可能放到要用的时候才声明。

这个例子可能不算很经典

void::Message::Game::IMagicalImpl::magicalStar_async(const ::Message::Game::AMD_IMagical_magicalStarPtr& magicalStarCB,int autoBuy,const ::cde::CContext& context){    int succeed = 0;//这两个变量根本没用到,应该放在后面    int exp = 0;CGateEntityPtr gateEntity;CPlayerPtr player;CGateHelper::getPlayerAndEntity(context, gateEntity, player);//一般来说,接口都是这两个比较靠前,因为要取出来用CMagicalManagerPtr magicalManager = CMagicalManagerPtr::dynamicCast(gateEntity->getComponent(ECOMPONENT_TYPE_MAGICAL_MANAGER));// 神兵数据if (!magicalManager->getTPlayerMagical().activate){//神兵还没激活CErrorCodeManager::throwException("ErrorGate_MagicalNotActivate");}

11.尽量不要把int当bool来使用。代码有变动之后很容易出错,而且就算用int来存放结果,很多时候0不一定代表错误。在java中,返回0通常表示成功的。

if (!magicalManager->getTPlayerMagical().activate){//神兵还没激活CErrorCodeManager::throwException("ErrorGate_MagicalNotActivate");}
if (autoBuy){int price = 0;int shopCode = 10003;//商店类型


12.代码换行之后,该缩进的时候要缩进一下。这个我也不知道什么标准了,不过一般都是按编译器换行后的缩进。

        std::string skinStr = "";for (MapSMagicalSkinInfo::iterator iter = _magicalSkin.begin();iter != _magicalSkin.end();//for循环中间的应该缩进吧iter++){//大括号中间的内容应该缩进skinStr += "[";skinStr += ToStr(iter->second.skinCode);skinStr += ",";skinStr += ToStr(iter->second.skinGradeLevel);skinStr += ",";skinStr += ToStr(iter->second.skinStarLevel);skinStr += ",";skinStr += ToStr(iter->second.isLimitTime);skinStr += ",";skinStr += ToStr(iter->second.skinLimitTime);skinStr += "]";}

13.对于一些复杂的内容,要保存到字符串,在放到数据库中。一般都是登陆的时候将字符串分解。保存到数据库的时候才将东西转成字符串。

void GateApp::CMagicalManager::setMagicalPromoteReturnReward(SPromoteReturnRewardInfo sPromoteReturnRewardInfo){_magicalPromoteReturnReward[sPromoteReturnRewardInfo.promoteLevel] = sPromoteReturnRewardInfo; std::string promoteReturnRewardStr = "";for (std::map<int, SPromoteReturnRewardInfo>::iterator iter = _magicalPromoteReturnReward.begin();iter != _magicalPromoteReturnReward.end();iter++){promoteReturnRewardStr += "[";promoteReturnRewardStr += ToStr(iter->second.promoteLevel);promoteReturnRewardStr += ",";promoteReturnRewardStr += ToStr(iter->second.consumeNum);promoteReturnRewardStr += ",";promoteReturnRewardStr += ToStr(iter->second.isGet);promoteReturnRewardStr += "]";}_tPlayerMagical.promoteReturnReward = promoteReturnRewardStr;}

这个每次变化都转一次,是没必要的。在save函数中执行,save函数在隔五分钟才会保存一次,不会过多执行。

void GateApp::CMagicalManager::save(bool logOut){cdf::CDateTime now;SSaveInfo& saveInfo = getSaveInfo(EMPlayerMagical);if (!saveInfo.needToSave(logOut, now)){return;}std::string skinStr = "";for (MapSMagicalSkinInfo::iterator iter = _magicalSkin.begin();iter != _magicalSkin.end();iter++){skinStr += "[";skinStr += ToStr(iter->second.skinCode);skinStr += ",";skinStr += ToStr(iter->second.skinGradeLevel);skinStr += ",";skinStr += ToStr(iter->second.skinStarLevel);skinStr += ",";skinStr += ToStr(iter->second.isLimitTime);skinStr += ",";skinStr += ToStr(iter->second.skinLimitTime);skinStr += "]";}_tPlayerMagical.skinStr = skinStr;std::string promoteReturnRewardStr = "";for (MapSPromoteReturnRewardInfo::iterator iter = _magicalPromoteReturnReward.begin();iter != _magicalPromoteReturnReward.end();iter++){skinStr += "[";skinStr += ToStr(iter->second.promoteLevel);skinStr += ",";skinStr += ToStr(iter->second.consumeNum);skinStr += ",";skinStr += ToStr(iter->second.isGet);skinStr += "]";}_tPlayerMagical.promoteReturnReward = promoteReturnRewardStr;saveInfo.reset(now);Message::Db::IMagicalDbPrx prx = Message::Db::IMagicalDbPrx::dynamicCast(Common::CCoreChannelManager::instance()->getProxy(Common::ECHANNEL_TYPE_DB_CACHE, Common::IMagicalDb));prx->updatePlayerMagical_async(NULL, _tPlayerMagical);}
14.一般来说一个功能一个configManager,除非很大,代码太多才会分开。

MagicalConfigManager

MagicalSkinConfigManager

MagicalAwakenConfigManager

这三个内容都不多,是在没多大必要。











0 0
原创粉丝点击