1 强化概述
在游戏中,强化模块是我们经常需要实现的模块,一般来说,强化可以提供装备的等级,属性,或者品质。强化也需要一定的条件,比如银币等。
2 强化规则
初始装备的等级为1级
每强化一次,装备的等级提高一次
装备被强化的最高等级为10级
每次强化需要银币,且随着等级的不断升高,所需要的银币数量就增加
越高档次的装备,强化相同等级,需要的银币的数量越多
强化概率随着等级的升高而减少
不同档次的装备强化到相同等级时,概率相同
加入宝石,可以增加强化的概率
使用保护道具,强化失败后,也不损坏装备
3 强化结果
每次强化等级提升一次,同时,属性也有所增加,并且具有一定的概率
强化失败,装备摔坏
随着属性值的增加(所有增加的属性值的总和),装备的品质会发生改变。
4 强化的数据库设计
在游戏中,我们可以获取到2件相同的装备(备注:有的游戏不允许获取到两件一模一样的装备),如果我们有2件相同的装备,在数据库里面的存储就会有两种方式:堆叠和不堆叠。我们该如何选择存储方式呢?在我们的游戏中,因为装备涉及到强化,也就是说,起初,我获取到2件一模一样的装备 即装备的ID相同,如果我强化成功其中的一个,那么导致的结果是,我有了2件"不一样"的装备,虽然装备的ID是一样,但是它们的属性可能不一样。这样的设定就要求我们在存储这2件装备时,不能堆叠,否则,我就不知道,我到底强化的是哪一个装备。
强化系统中,设计的表: 我的装备表,装备配置表,强化配置表,宝石配置表,我的宝石表。
我的装备表设计:
这是我的一个装备的表的设计
备注: 我们的装备的类型可能不止一种,在我们命名装备的ID时,我们采用的方式是 装备的类型+装备的id 如:333001 333为装备的类型 001为装备的id
在这个表中,我们需要注意的是,equipped_by_usid 表中这个装备是否装配到我的某个船上,如果是0表示没有使用,如果不为零,则表示为我的船的id.在需求上,我们可能需要知道这个装备装配到了哪个船上,还有一个需求是,我需要知道我的船装配了那几个装备,所以,需要通过船的id找到他装配了哪些装备
cannon_num, armor_num, hp 这些属性是如果把这个装备装配到船上,改变船的对应的属性。
装备静态配置表:
在装备的配置表中,hp表示是这个装备装配到船上后,增加船的耐久度,还有一些改变船增益的属性,我没有列出来。
装备强化后,可能修改的属性有:hp,rank , inclination, sell_price 等。
强化的配置表:
这个表中,forged_level 表示的是强化到某个等级 cost_price 表示,强化到这个等级需要的银币 success_odds 表示强化到这个等级的概率
cannon_num_incr_config 这个属性的值是0:3250;1:4500;2:2250这样的类型 表示,强化后,增加0的概率是3250/10000 增加1的概率是4500/10000。
程序设计
在装备系统中,我们采用面向对象的面向思想设计,这是一个强化炉的对象,需要的属性操作强化的人,本次要强化的装备对象,是否使用保护道具,强化放入的宝石,本次强化的配置信息,强化后,更属性的增量, 强化后的结果清单等。
在强化炉里面,我们需要知道本次强化成功的概率,强化成功后属性增加的范围。执行强化操作后,增加装备的各个属性,增加强化记录等各种操作。
强化流程
强化前,我们需要知道被强化的装备对象,操作者的对象,本次强化成功的概率,强化成功装备属性增加的范围,是否使用了宝石等各种信息。
选择一个被强化的装备后,我们需要得到强化这个装备的各种信息。 这些操作是控制层Controller的函数
public function beforefoundryAction()
{
// 准备强化的船首像 userFhId
$userFhId = $this->getInt('uniq_id');
// 是否选择了【圣殿祝福石】保护
$useProtection = $this->getBool('use_protection');
// 当前选中的船首像
if ($userFhId > 0) {
// 实例化一个锻造炉
$forge = new Model_Forge();
// 设置操作者
$forge->setOwner($this->_user);
// 实例化一个船首像
if (! $item = $this->_user->item->getOneItem($userFhId)) {
throws('Invalid TargetItem');
}
// 已是顶级,无需强化
if ($item->isTopForgedLevel()) {
throws(_('该船首像已经是顶级了,无需继续强化'));
}
// 把船首像放入炉中
$forge->setItem($item);
// 强化配置(预计强化效果)
$forgeConfig = $forge->getForgeConfig();
// 解析得到本次强化各属性的提升范围
$forgeIncrRanges = Model_Forge::parseForgeIncrRanges($forgeConfig);
// 本次强化价格
$forgePrice = $forgeConfig['cost_price'];
// 计算成功率(N/10000)
$successOdds = $forge->calcSuccessOdds();
// 该船首像下一级的图片
$item['next_img_path'] = MyHelper_View::getFigureheadImg($item['img_path'], $item['forged_level'] + 1);
// 五级以上的不能使用【圣殿祝福石】
if ($item['forged_level'] > 5) {
$useProtection = false;
}
// 传出模板变量
$this->assign('item', $item);
$this->assign('successOdds', $successOdds / 100);
$this->assign('forgePrice', $forgePrice);
$this->assign('forgeIncrRanges', $forgeIncrRanges);
}
执行强化
在执行强化前,我们需要根据已经得到的数据,对装备的某些属性进行修改。
/**
* 执行强化
*/
public function forgeAction()
{
$userFhId = $this->getInt('uniq_id'); // 船首像 userFhId
$jewelIds = $this->getInts('jewel_ids'); // 强化宝石 itemIds
$useProtection = $this->getBool('use_protection'); // 是否使用保护道具(即消费金块)
// 实例化一个锻造炉
$forge = new Model_Forge();
// 设置操作者
$forge->setOwner($this->_user);
// 实例化一个船首像
if (! $item = $this->_user->item->getOneItem($userFhId)) {
throws('Invalid TargetItem');
}
// 已是顶级,无需强化
if ($item->isTopForgedLevel()) {
throws(_('该船首像已经是顶级了,无需继续强化'));
}
// 把船首像放入炉中
$forge->setItem($item);
// 放入保护道具
// 保护5级以下的物品,强化失败后不被损毁
if ($useProtection) {
$forge->useProtection();
}
// 放入强化材料:宝石(提高强化成功率)
if ($jewelIds) {
$forge->addJewels($jewelIds);
}
// 开始锻造
$forge->process();
// 获取锻造结果
$result = $forge->getResult();
// 强化失败
if (! $result['forge_result']) {
if ($result['is_destroyed']) {
$message = _('很可惜,此次强化失败,强化的船首像损坏了,不要气馁,下次继续努力');
} else {
$message = _('很可惜,此次强化失败,不要气馁,下次继续努力');
}
$this->jsonx($message, 'success', array(
'forge_result' => $result['forge_result'],
'is_destroyed' => $result['is_destroyed']
));
// 强化成功
} else {
// 强化后的实例
$itemForged = $result['item_forged'];
$this->jsonx(_('恭喜您,船首像强化成功'), 'success', array(
'forge_result' => $result['forge_result'],
'is_top' => $itemForged->isTopForgedLevel(), // 是否已经强化到顶级
'content' => $this->render('item-forged', array(
'item' => $itemForged, // 强化后的实例
'incrs' => $result['incrs'], // 本次强化后的升级量
))
));
}
}
以上,就是面向对象的方式,实现的强化的基本步骤。 下面是Model层重要的具体方法的详细介绍。
在Model层中,我定义了强化类需要的属性和方法
<?php
/**
* 锻造炉 模型(强化船首像)
*
* @author JiangJian <[email protected]>
* $Id: Forge.php 4024 2013-07-15 06:11:58Z sunli $
*
* @version 2013.05.13 备注:按产品需求要去除 quality 品质的作用
* 为防止需求反复,代码暂不做修改,quality 只在内部默默更新,实际上没什么作用,也不体现在前端UI上
*/
class Model_Forge extends Core_Model_Abstract
{
/**
* 当前操作人
*
* @var Model_User
*/
private $_user;
/**
* 本次要强化的对象
*
* @var Model_Item_*
*/
private $_item;
/**
* 是否使用保护道具(金块)
*
* @var array
*/
private $_useProtection = false;
/**
* 被放入炉中的宝石
*
* @var array
*/
private $_jewels = array();
/**
* 本次强化等级配置信息
*
* @var array
*/
private $_forgeConfig = array();
/**
* 强化成功后各属性获得的增量
*
* @var array
*/
private $_incrs = array();
/**
* 强化结果清单
*
* @var array
*/
private $_result = array(
'is_destroyed' => 0, // 原物品是否损毁
'forge_result' => 0, // 强化结果:成败
'success_odds' => 0, // 本次成功率
'incrs' => array(), // 强化增量效果
'item_forged' => null, // 强化后的装备实例
'quality_changed' => 0, // 是否产生质变(变色)
);
/**
* 保护道具需消费的金块数
*
* @var int
*/
const PROTECTION_COST_GOLD = 20;
/**
* 放入要锻造的装备
*
* @param object Model_Item_* $item
* @return array
*/
public function setItem(Model_Item_Abstract $item)
{
if (! Model_Item::isType('figurehead', $item['type'])) {
throws(_('只有“船首像”可被强化'));
}
$this->_item = $item;
// 初始化本次强化配置信息
$this->_initForgeConfig();
}
/**
* 设置操作人
*
* @param object Model_User $item
* @return void
*/
public function setOwner(Model_User $user)
{
$this->_user = $user;
}
/**
* 设置是否使用保护道具(金块保护)
*
* @param object Model_User $item
* @return void
*/
public function useProtection($bool = true)
{
$this->_useProtection = (bool) $bool;
}
/**
* 放入强化材料:宝石(提高强化成功率)
*
* @param array $jewelIds
* @return void
*/
public function addJewels(array $jewelIds)
{
}
private function _consumeJewels()
{
}
/**
* 初始化当前强化配置
*
* @return void
*/
private function _initForgeConfig()
{
// 获取强化等级配置信息
if (! $this->_forgeConfig = self::getExpectedForgedEffect($this->_item)) {
throws(_('该装备强化配置信息缺失,无法进行强化'));
}
}
public function getForgeConfig()
{
}
/**
* 锻造前检测
*
* @return void
*/
private function _initCheck()
{
// 检测银币余额
// 检测金块余额
}
/**
* 锻造进行(外观模式)
*
* @return bool
*/
public function process()
{
// 前提检测
$this->_initCheck();
// 锻造进行
$forgeResult = $this->_process();
// 每日任务行为统计 累计强化船首像次数(不论成功与否)
$this->_user->dailyTask->process(506012);
// 保存锻造日志
$this->_saveLog();
return $forgeResult;
}
/**
* 锻造进行核心流程
*
* @return bool
*/
private function _process()
{
// 消费银币
$this->_user->base->consumeSilver($this->_forgeConfig['cost_price']);
// 使用保护道具(即扣金块)
if ($this->_useProtection) {
$this->_user->base->consumeGold(self::PROTECTION_COST_GOLD, 0, '强化时使用了【圣殿祝福石】');
}
// 消耗强化宝石
$this->_consumeJewels();
// 计算成功率(N/10000)
$successOdds = $this->calcSuccessOdds();
// 强化结果 true/false
$forgeResult = Helper_Probability::isHit($successOdds);
// 强化失败
if (! $forgeResult) {
// 保护石(圣殿祝福石)可保护5级(含)及以下的船首像失败后不被损毁
if (! ($this->_useProtection && $this->_item['forged_level'] <= 5)) {
// 如果该船首像已装配到船上,则先从船上卸载
// 特别注意:为了提高UE,卸载时不检测仓容,即允许仓容超出
if ($this->_item['equipped_by_usid']) {
$this->_user->ship->unloadItem($this->_item['equipped_by_usid'], 'figurehead', false);
}
// 原物品损毁
$this->_user->item->remove($this->_item['uniq_id']);
// 记录日志
$this->_result['is_destroyed'] = 1;
}
// 强化成功
} else {
// 强化成功后各属性的增量
$this->_getIncrement();
// 保存强化成果
$this->_saveIncrement();
// 检测是否发生了变色(品质提升、质变)
$this->_qualityChanged();
// 增加船首像锻造成功次数(统计)
$this->_user->stats->addTotalItemForgeSuccessTimes();
// 每日任务行为统计 累计强化成功次数
// 2013.06.28 按陆超的新版每日任务需求,暂时去除该行为埋点
// $this->_user->dailyTask->process(504008);
// 每日任务行为统计 把一个船首像强化到指定等级
// 2013.06.28 按陆超的新版每日任务需求,暂时去除该行为埋点
// $this->_user->dailyTask->process(504035, 1, $this->_forgeConfig['forged_level']);
// 强化船首像达到5级,既可获取成就熠熠生辉
if ($this->_forgeConfig['forged_level'] == 5) {
$this->_user->achievement->achieve(721051);
}
// 强化船首像达到10级,既可获取成就神乎其技
if ($this->_forgeConfig['forged_level'] == 10) {
$this->_user->achievement->achieve(721052);
}
}
// 记录日志
$this->_result['success_odds'] = $successOdds;
$this->_result['forge_result'] = $forgeResult;
return $forgeResult;
}
/**
* 计算成功率(累计宝石的加成)
*
* @return int
*/
public function calcSuccessOdds()
{
}
/**
* 强化成功后各属性获得的增量
*
* @return void
*/
private function _getIncrement()
{
}
/**
* 保存强化成果
*
* @return bool
*/
private function _saveIncrement()
{
}
/**
* 质变检测和处理(颜色变化)
* 如果发生质变,则更新 quality 字段
*
* @return void
*/
private function _qualityChanged()
{
}
/**
* 静态检测函数
* 判断是否发生颜色变化(质变)
*
* @param array $itemForged 强化后的物品
* @param array $itemOrginal 强化前的物品
* @return int $quality 1/2/3/4/false (false 表示未发生改变)
*/
public static function isQualityChanged($itemForged, $itemOrginal)
{
}
/**
* 保存本次强化记录
*
* @return bool
*/
private function _saveLog()
{
}
/**
* 原物品是否损坏(强化失败后)
*
* @return bool
*/
public function isDestroyed()
{
}
/**
* 返回本次强化详细结果
*
* @return array
*/
public function getResult()
{
}
/**
* 本次强化使用宝石情况
*
* @return string json
*/
public function _getJewelsLog()
{
$return = '';
if ($this->_jewels) {
foreach ($this->_jewels as $value) {
$jewel = $value['object'];
$jewels[] = array(
'item_id' => $jewel['id'],
'amount' => $value['amount'],
'success_odds_incr' => $jewel['success_odds'] * $value['amount'],
);
}
$return = json_encode($jewels); // 使用json保存数据的结果
}
return $return;
}
/**
* 获取本次使用的强化配置
*
* @param int $rank 当前装备档次
* @param int $inclination 当前装备偏重方向
* @param int $forgedLevel 强化等级
* @return array
*/
public static function getStaticForgeConfig($rank, $inclination, $forgedLevel)
{
}
/**
* 返回某装备强化后的预计效果
* 通俗说:强化后,装备会有哪些改进
*
* @param Model_Item_Abstract $item
* @return array
*/
public static function getExpectedForgedEffect(Model_Item_Abstract $item)
{
// 本次准备强化到哪个等级
$nextForgedLevel = $item['forged_level'] + 1;
// 获取强化等级配置信息
return self::getStaticForgeConfig($item['rank'], $item['inclination'], $nextForgedLevel);
}
/**
* 解析得到本次强化各属性的提升范围
*
* @param array $forgeConfig
* @return array
*/
public static function parseForgeIncrRanges(array $forgeConfig)
{
}
}
在这个强化系统的设计中,我们采用的面向对象的方式,提供的代码的重用率,外观模式的使用,保证了代码的整洁可读性。
强化容易出现bug,请特别重点留意。
在我们设计的游戏中,我们需要冗余一些信息在玩家的user表中,因为游戏中,需要经常读取玩家的战斗力,耐久度等各种信息,例如舰队的战斗力,耐久度。舰队是由出航的船组成的,如果出航的船的战斗力发现变化,需要修改冗余在user表中的冗余信息。
这里,就有一个问题,如果装备没有被使用,那么强化后,不需要更新某些冗余字段。
如果装备被装配在某个船上,那么就需要更新这个船的某些信息,如,战斗力,耐久度
如果这个船时出航状态,也就是说,这个船在舰队中,那么需要更新user表中的冗余字段。