凡人修真3D(2)神兵

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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值