游戏强化系统的实现

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表中的冗余字段。




  


  

发布了41 篇原创文章 · 获赞 14 · 访问量 14万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章