• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            Heath's Blog

            There is no end, it is just the beginning! - A Game Developer's Notes

            一個(gè)QTE原型框架

                 QTE為Quick Time Event的簡(jiǎn)寫,多見于主機(jī)游戲中,通常以在規(guī)定時(shí)間內(nèi)根據(jù)提示完成(一系列)按鍵操作的形式出現(xiàn)。就表現(xiàn)上看,其實(shí)是過場(chǎng)動(dòng)畫的一種分解觸發(fā)機(jī)制,用于表現(xiàn)看似復(fù)雜實(shí)則固定的動(dòng)作或者場(chǎng)景效果,一方面在消除了單純過場(chǎng)乏味感的同時(shí)增強(qiáng)了游戲的互動(dòng)性,另一方面還降低了表現(xiàn)復(fù)雜效果的開發(fā)難度。

            5_a 10_a

            16_a 17_a

            圖1 QTE in GOD OF WAR III

                 目前MMORPG的一個(gè)開發(fā)趨勢(shì)就是融入主機(jī)游戲中的一些元素,提升網(wǎng)游在傳統(tǒng)游戲性之外的可玩性。本文主要根據(jù)自己在項(xiàng)目中開發(fā)的QTE系統(tǒng),介紹一個(gè)相對(duì)比較簡(jiǎn)單的原型框架。

            一、分析

                 以一個(gè)限時(shí)按鍵的QTE來(lái)分析,其中包括的元素有:時(shí)間、鍵、結(jié)果。時(shí)間與鍵可看作Event的約束條件,它們共同決定該Event是否達(dá)成。而結(jié)果可作為一條消息發(fā)送給關(guān)心者,然后由后者決定與之相關(guān)的表現(xiàn)。

            Requirements Model

            圖2

                 鼠標(biāo)作為PC上重要的外設(shè),當(dāng)然會(huì)被用于QTE,其形式可能會(huì)包括:搖晃、按鍵、滾輪滾動(dòng)等等。Event是否達(dá)成的判斷流程,與限時(shí)按鍵大同小異。

                 有時(shí)候Designer可能會(huì)設(shè)計(jì)一系列Event,增加操作難度,這時(shí)就需要考慮將多個(gè)Event串聯(lián)起來(lái),只有所有Event達(dá)成時(shí),該QTE才能算達(dá)成。因此,在圖1之上,需要加入另一個(gè)判斷邏輯。

            Requirements Model Extend

            圖3

            二、實(shí)現(xiàn)

                 通過分析,不難得出一個(gè)典型的QTE系統(tǒng)的核心數(shù)據(jù)結(jié)構(gòu):Event鏈表。此外,為了將結(jié)果反饋給QTE請(qǐng)求者,還應(yīng)該提供一個(gè)通用的通知機(jī)制。在這個(gè)原型框架中,通過加入一個(gè)中間層來(lái)隔離異構(gòu)的請(qǐng)求者,實(shí)現(xiàn)了回調(diào)機(jī)制。

            System

            圖4

                 QTEFunctor作為處理Event的仿函數(shù)基類,給出了各種QTE的處理接口。

            Code Snippet
            1. class QTEFunctor
            2. {
            3. public:
            4.     QTE_TYPE m_type;
            5. protected:
            6.     float _fTimer;
            7.     float _fDuration;
            8.     unsigned int _uValue;    ///< condition
            9.     int _iRetValue;            ///< returned value
            10. public:
            11.     virtual QTEFUNCTOR_RETVAL operator() (float) = 0;
            12.     unsigned int GetValue() { return _iRetValue; }
            13. };
            14.  
            15. class MouseShakeFunctor : public QTEFunctor
            16. {
            17. private:
            18.     CPoint _point;
            19. public:
            20.     MouseShakeFunctor(const QTECondition&);
            21.     ~MouseShakeFunctor() {}
            22.     QTEFUNCTOR_RETVAL operator() (float);
            23. };
            24.  
            25. class KeyDownFunctor : public QTEFunctor
            26. {
            27. public:
            28.     KeyDownFunctor(const QTECondition&);
            29.     ~KeyDownFunctor() {}
            30.     QTEFUNCTOR_RETVAL operator() (float);
            31. };

                 QTEDelegateBase提供了回調(diào)函數(shù)的統(tǒng)一接口,為兼容類函數(shù)和非類函數(shù),分別派生出了QTETypeDelegate和QTENoTypeDelegate。

            Code Snippet
            1. class QTEDelegateBase
            2. {
            3. public:
            4.     virtual void Call(QTEManager::QTE_TYPE , int) = 0;
            5.     virtual ~QTEDelegateBase() {}
            6. protected:
            7.     QTEDelegateBase() {}
            8. };
            9.  
            10. /// non-class method callback
            11. typedef void (*CallbackFuncPtrType)(QTEManager::QTE_TYPE , int);    ///< FAILED: second parameter <=0, OK : >0 (may include additional meanings)
            12. class QTENoTypeDelegate : public QTEDelegateBase
            13. {
            14. public:
            15.     QTENoTypeDelegate(CallbackFuncPtrType func) : _pCallbackFunc(func) {}
            16.     ~QTENoTypeDelegate() {}
            17.     void Call(QTEManager::QTE_TYPE , int) {}
            18. private:
            19.     CallbackFuncPtrType _pCallbackFunc;
            20. };
            21.  
            22. /// class method callback
            23. template<class C>
            24. class QTETypeDelegate : public QTEDelegateBase
            25. {
            26. public:
            27.     QTETypeDelegate(C* , void (C::*)(QTEManager::QTE_TYPE , int));
            28.     ~QTETypeDelegate() {}
            29.     void Call(QTEManager::QTE_TYPE , int);
            30. private:
            31.     C* _pObj;
            32.     void (C::*_pCallbackFunc)(QTEManager::QTE_TYPE , int);
            33. };
            34.  
            35. template<class C>
            36. QTETypeDelegate<C>::QTETypeDelegate(C* pObj , void (C::*func)(QTEManager::QTE_TYPE , int))
            37. : _pObj(pObj) , _pCallbackFunc(func)
            38. {
            39.  
            40. }
            41.  
            42. template<class C>
            43. void QTETypeDelegate<C>::Call(QTEManager::QTE_TYPE type , int value)
            44. {
            45.     (_pObj->*_pCallbackFunc)(type , value);
            46. }

                 QTEManager中采用了vector容器來(lái)保存待處理的多個(gè)Event鏈,并提供申請(qǐng)QTE、取消QTE的接口,以及Event是否達(dá)成的邏輯更新。

            Code Snippet
            1. void QTEManager::RequestQTE(QTEDelegateBase* pQTE , std::vector<QTECondition>& condList)
            2. {
            3.     std::vector<QTECondition>::iterator iter = condList.begin();
            4.     QTELinkNode* pNode = NULL;
            5.     QTELinkNode* pNextNode = NULL;
            6.  
            7.     for(; iter != condList.end(); ++iter)
            8.     {
            9.         if(pNextNode)
            10.         {
            11.             pNextNode->pNext = new QTELinkNode;
            12.             pNextNode = pNextNode->pNext;
            13.         }
            14.         else
            15.         {
            16.             pNode = new QTELinkNode;
            17.             pNextNode = pNode;
            18.         }
            19.  
            20.         switch(iter->type)
            21.         {
            22.         case QT_MOUSE_SHAKE:
            23.             pNextNode->pDelegate = pQTE;
            24.             pNextNode->pFunctor = new MouseShakeFunctor(*iter);
            25.             break;
            26.         case QT_KEY_DOWN:
            27.             pNextNode->pDelegate = pQTE;
            28.             pNextNode->pFunctor = new KeyDownFunctor(*iter);
            29.             break;
            30.         case QT_KEY_PRESS:
            31.             pNextNode->pDelegate = pQTE;
            32.             pNextNode->pFunctor = new KeyPressFunctor(*iter);
            33.             break;
            34.         }
            35.     }
            36.  
            37.     if(pNode)
            38.         _RequestList.push_back(pNode);
            39. }
            40.  
            41. void QTEManager::CancelQTE(QTEDelegateBase* pQTE)
            42. {
            43.     QTEListType::iterator iter = _RequestList.begin();
            44.  
            45.     for(; _RequestList.end() != iter; ++iter)
            46.     {
            47.         if(pQTE == (*iter)->pDelegate)
            48.         {
            49.             (*iter)->pDelegate->Call((*iter)->pFunctor->m_type , -1 , 0);    ///< failed
            50.  
            51.             QTELinkNode* pNode = *iter;
            52.             /// delete the rest node
            53.             while(pNode)
            54.             {
            55.                 *iter = pNode->pNext;
            56.                 delete pNode;
            57.                 pNode = *iter;
            58.             }
            59.             _RequestList.erase(iter);
            60.             break;
            61.         }
            62.     }
            63. }

             

            Code Snippet
            1. #define STEP_OK_BASE 1000
            2. #define SUCCESS_BASE 2000
            3.  
            4. void QTEManager::Update(float dt)
            5. {    
            6.     QTEListType::iterator iter = _RequestList.begin();
            7.     for(; iter != _RequestList.end();)
            8.     {
            9.         QTEFUNCTOR_RETVAL ret = (*iter)->pFunctor->operator ()(dt);
            10.         if(QTEFR_FAILED == ret)
            11.         {
            12.             (*iter)->pDelegate->Call((*iter)->pFunctor->m_type , -1);    ///< failed
            13.  
            14.             QTELinkNode* pNode = *iter;
            15.             /// delete the rest event
            16.             while(pNode)
            17.             {
            18.                 *iter = pNode->pNext;
            19.                 delete pNode;
            20.                 pNode = *iter;
            21.             }
            22.             iter = _RequestList.erase(iter);
            23.         }
            24.         else if(QTEFR_OK == ret)
            25.         {
            26.             /// get next event
            27.             if((*iter)->pNext)
            28.             {
            29.                 QTELinkNode* pNode = *iter;
            30.                 pNode->pDelegate->Call(pNode->pFunctor->m_type ,
            31.                     STEP_OK_BASE + pNode->pFunctor->GetValue());        ///< step ok
            32.                 *iter = (*iter)->pNext;
            33.                 delete pNode;
            34.                 ++iter;
            35.             }
            36.             else
            37.             {
            38.                 (*iter)->pDelegate->Call((*iter)->pFunctor->m_type ,
            39.                     SUCCESS_BASE + (*iter)->pFunctor->GetValue());        ///< finally ok
            40.                 delete *iter;
            41.                 iter = _RequestList.erase(iter);
            42.             }
            43.         }
            44.         else if(QTEFR_PENDING == ret)
            45.         {
            46.             (*iter)->pDelegate->Call((*iter)->pFunctor->m_type ,
            47.                 (*iter)->pFunctor->GetValue());    ///< continue progressing
            48.             ++iter;
            49.         }
            50.     }
            51. }

            posted on 2011-08-13 10:25 Heath 閱讀(6263) 評(píng)論(4)  編輯 收藏 引用 所屬分類: Game Development

            Feedback

            # re: 一個(gè)QTE原型框架 2011-08-13 18:11 戰(zhàn)魂小筑

            主機(jī)上都是用腳本寫這層系統(tǒng)  回復(fù)  更多評(píng)論   

            # re: 一個(gè)QTE原型框架 2011-12-09 11:50 周中良

            請(qǐng)問那個(gè)class 圖是用什么工具寫的?謝謝!是rational rose嗎?  回復(fù)  更多評(píng)論   

            # re: 一個(gè)QTE原型框架[未登錄] 2011-12-22 16:56 Heath

            @周中良
            EA  回復(fù)  更多評(píng)論   

            99久久精品毛片免费播放| 久久午夜福利电影| 久久久久久狠狠丁香| 国产精品99久久久久久www| 一级做a爰片久久毛片毛片| 久久久久99精品成人片欧美| 国产福利电影一区二区三区久久老子无码午夜伦不 | 国内精品久久久久影院优| 精品久久人人爽天天玩人人妻| 国产一区二区久久久| 久久精品国产91久久麻豆自制 | 国产精品久久久福利| 久久久高清免费视频| 国产精品欧美久久久久无广告 | 精品久久久无码21p发布| 伊人丁香狠狠色综合久久| 99久久精品国产一区二区 | 久久人妻少妇嫩草AV无码专区| 国产精品美女久久久免费| 精品熟女少妇av免费久久| 国产成人精品三上悠亚久久| 欧美性猛交xxxx免费看久久久| 97久久精品人人做人人爽| 久久天天躁狠狠躁夜夜96流白浆| 亚洲国产成人精品无码久久久久久综合 | 99久久精品免费观看国产| 久久久久亚洲av无码专区| 伊人情人综合成人久久网小说| 久久国产香蕉视频| 国内精品久久久久久中文字幕| 久久久精品午夜免费不卡| 97久久超碰国产精品2021| 国产综合久久久久| 国产精品女同久久久久电影院| 亚洲av伊人久久综合密臀性色| 综合久久一区二区三区| 麻豆国内精品久久久久久| 中文国产成人精品久久亚洲精品AⅤ无码精品 | 色欲综合久久中文字幕网| 久久天天婷婷五月俺也去| 久久精品国产久精国产果冻传媒 |