遊戲強化系統的實現

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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章