![基于unity的回合制網(wǎng)游戰(zhàn)斗系統(tǒng)的研究報告及實現(xiàn)_第1頁](http://file4.renrendoc.com/view/8ebf1b08ff2b3bf8e782c45dc7546cbd/8ebf1b08ff2b3bf8e782c45dc7546cbd1.gif)
![基于unity的回合制網(wǎng)游戰(zhàn)斗系統(tǒng)的研究報告及實現(xiàn)_第2頁](http://file4.renrendoc.com/view/8ebf1b08ff2b3bf8e782c45dc7546cbd/8ebf1b08ff2b3bf8e782c45dc7546cbd2.gif)
![基于unity的回合制網(wǎng)游戰(zhàn)斗系統(tǒng)的研究報告及實現(xiàn)_第3頁](http://file4.renrendoc.com/view/8ebf1b08ff2b3bf8e782c45dc7546cbd/8ebf1b08ff2b3bf8e782c45dc7546cbd3.gif)
![基于unity的回合制網(wǎng)游戰(zhàn)斗系統(tǒng)的研究報告及實現(xiàn)_第4頁](http://file4.renrendoc.com/view/8ebf1b08ff2b3bf8e782c45dc7546cbd/8ebf1b08ff2b3bf8e782c45dc7546cbd4.gif)
![基于unity的回合制網(wǎng)游戰(zhàn)斗系統(tǒng)的研究報告及實現(xiàn)_第5頁](http://file4.renrendoc.com/view/8ebf1b08ff2b3bf8e782c45dc7546cbd/8ebf1b08ff2b3bf8e782c45dc7546cbd5.gif)
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
摘要本文主要闡述網(wǎng)絡(luò)回合制戰(zhàn)斗系統(tǒng)的實現(xiàn),包括回合制戰(zhàn)斗系統(tǒng)的整個流程〔戰(zhàn)斗開場、玩家下達(dá)戰(zhàn)斗指令、戰(zhàn)斗動畫、戰(zhàn)斗完畢〕,和網(wǎng)絡(luò)回合制戰(zhàn)斗系統(tǒng)常見的主要功能〔攻擊、使用技能、使用物品〕的實現(xiàn),并且在游戲工程"PKer"中進展實踐和測試。在開發(fā)環(huán)境方面,效勞器采用國IOCP高性能開源框架“HP-Socket〞(Windows平臺),并且連接到Mysql數(shù)據(jù)庫,客戶端采用近年比擬熾熱的強大跨平臺引擎Unity3D〔2D,C*〕并且使用Sqlite作為嵌入式數(shù)據(jù)庫。除此以外,本文還對戰(zhàn)斗系統(tǒng)實現(xiàn)所涉及到的相關(guān)技術(shù)如Unity引擎的協(xié)同程序、單例設(shè)計模式和分包算法進展簡要介紹。
關(guān)鍵詞回合制戰(zhàn)斗系統(tǒng),網(wǎng)絡(luò)游戲,Unity3D,協(xié)同程序,游戲編程
ABSTRACTThisarticlemainlye*poundstheimplementationofnetworkturn-basedbatsystem,includingthewholeprocessofturn-basedbatsystem(battlebegins,theplayersfightinginstructions,batanimation,battleends),andthemainfunctionofmon(attack,usingskills,usingitems)implementation,andinthegame"PKer"inpracticeandtestoftheproject.Intheaspectofdevelopmentenvironment,C++IOCPserverwithWindowsplatformandconnecttotheMysqldatabase,theclientusesUnity3D(2D,C*)andusesSqliteasanembeddeddatabase.Inadditiontothis,thisarticlealsoinvolvedtobatsystemrelatedtechnologiessuchastheUnityenginecoroutines,singletondesignpatternandthesubcontractalgorithmarebrieflyintroduced.
KEYWORDSTurn-basedbatsystem,onlinegame,Unity3D,Coroutine,Singletondesignpattern
目錄
TOC\f\h\z\t"樣式1,1,樣式2,2,樣式3,3"
前言
3
第1章緒論
3
1.1回合制游戲簡介
3
1.1.1廣義上的回合制游戲
3
1.1.2狹義上的回合制游戲
3
1.2回合制戰(zhàn)斗系統(tǒng)簡介
3
1.3實踐工程"PKer"簡介
3
第2章開發(fā)環(huán)境和局部涉及技術(shù)簡介
3
2.1開發(fā)環(huán)境簡介
3
2.2Unity協(xié)同程序
3
2.2.1Unity協(xié)同程序簡介
3
2.2.2Unity協(xié)同程序的運用
3
2.3單例設(shè)計模式
3
2.3.1單例設(shè)計模式
3
2.3.2單例設(shè)計模式的運用
3
2.3.3單例設(shè)計模式在Unity中的運用
3
2.4分包算法
3
2.4.1分包的原因
3
2.4.2環(huán)形緩沖區(qū)〔CircularBuffer〕
3
2.4.3分包算法流程圖
3
第3章戰(zhàn)斗動畫實現(xiàn)方案的研究與比照
3
3.1研究背景
3
3.2實現(xiàn)方案一:有限狀態(tài)機
3
3.3實現(xiàn)方案二:協(xié)同程序(Coroutine)
3
3.4方案抉擇結(jié)論
3
第4章回合制網(wǎng)游戰(zhàn)斗系統(tǒng)設(shè)計
3
4.1回合制網(wǎng)游戰(zhàn)斗系統(tǒng)設(shè)計
3
4.2回合制網(wǎng)游戰(zhàn)斗系統(tǒng)效勞器實現(xiàn)思路
3
4.3回合制網(wǎng)游戰(zhàn)斗系統(tǒng)客戶端實現(xiàn)思路
3
4.4戰(zhàn)斗系統(tǒng)框架構(gòu)造〔以實踐工程"PKer"為例〕
3
第5章回合制戰(zhàn)斗系統(tǒng)實現(xiàn)
3
5.1戰(zhàn)斗系統(tǒng)相關(guān)消息構(gòu)造體的定義
3
5.2效勞器戰(zhàn)斗系統(tǒng)的實現(xiàn)
3
5.2.1效勞器戰(zhàn)斗系統(tǒng)相關(guān)構(gòu)造體
3
5.2.2初始化一個戰(zhàn)局
3
5.2.3接收客戶端的戰(zhàn)斗指令消息
3
5.2.4處理戰(zhàn)斗指令并發(fā)送動畫消息
3
5.2.5說明
3
5.3客戶端戰(zhàn)斗系統(tǒng)的實現(xiàn)
3
5.3.1客戶端戰(zhàn)斗系統(tǒng)功能模塊
3
5.3.2客戶端戰(zhàn)斗系統(tǒng)相關(guān)數(shù)據(jù)類型
3
5.3.3進入戰(zhàn)斗后初始化戰(zhàn)斗角色
3
5.3.4下達(dá)戰(zhàn)斗指令并發(fā)送戰(zhàn)斗指令消息
3
5.3.5接收戰(zhàn)斗動畫消息
3
5.3.6收到戰(zhàn)斗動畫播放消息并播放戰(zhàn)斗動畫
3
5.3.7戰(zhàn)斗動畫實現(xiàn)細(xì)述
3
第6章工程測試
3
6.1進入戰(zhàn)斗測試
3
6.2普通攻擊功能測試
3
6.3使用技能功能測試
3
6.4使用物品功能測試
3
結(jié)論
3
參考文獻
3
致
3
前言
隨著網(wǎng)絡(luò)的普及與迅速開展,網(wǎng)絡(luò)游戲已經(jīng)成為電子游戲中的主流。網(wǎng)絡(luò)游戲的戰(zhàn)斗系統(tǒng)主要可分為即時制和回合制兩種模式。即時制戰(zhàn)斗系統(tǒng)側(cè)重于刺激、反響、操作性,戰(zhàn)斗節(jié)奏快。而回合制戰(zhàn)斗系統(tǒng)側(cè)重于休閑、戰(zhàn)略、配合,戰(zhàn)斗節(jié)奏慢。早期的電子游戲由于設(shè)備硬件條件有限,大多采用回合制戰(zhàn)斗系統(tǒng)。
隨著科技的開展和設(shè)備硬件的提升,如今回合制游戲的數(shù)量比例有所下降,但回合制游戲在國游戲市場依舊占據(jù)著想當(dāng)大的份額,仍有大量玩家熱衷這種戰(zhàn)斗模式,幾款眾所周知的國產(chǎn)單機游戲如"軒轅劍"系列、"仙劍奇?zhèn)b傳"系列、"古劍奇譚"系列以及國在線人數(shù)最多的MMORPG"夢幻西游"均是采用回合制戰(zhàn)斗系統(tǒng)的游戲。
本人也是熱衷于回合制戰(zhàn)斗系統(tǒng)的玩家之一,可縱觀近年來國回合制游戲的開展,國回合制游戲一直止步不前,"軒轅劍"系列、"仙劍奇?zhèn)b傳"系列、"古劍奇譚"銷量下降,MMORPG"夢幻西游"也有降溫跡象,甚至國大多回合制網(wǎng)游只是復(fù)制在"夢幻西游"或“換皮〞,缺少創(chuàng)新和突破。本人希望在研究和實現(xiàn)回合制戰(zhàn)斗系統(tǒng)的根底上,能夠找到突破和創(chuàng)新點。同時在游戲編程方面,即時制邏輯較為簡單明了清晰,而回合制則比擬繁瑣復(fù)雜,而且在Unity引擎上實現(xiàn)回合制戰(zhàn)斗系統(tǒng)的相關(guān)資料較少。綜上原因,本人撰寫本文,希望能對志同道合者有所啟發(fā),同時也尋求學(xué)術(shù)交流。
工程將在2017年6月開源,開源地址s://pan.baidu./share/home"uk=1017424337
By江正覬
2016.6
第1章緒論
1.1回合制游戲簡介
1.1.1廣義上的回合制游戲
凡“我方與敵方在單個回合輪流行動,只有輪到我方〔自己〕的回合或者是新的回合開場時,才可進展行動〞的游戲,都可歸類為廣義上的回合制游戲,而且絕大大多數(shù)情況下,單個回合敵我雙方行動次數(shù)一樣。從廣義上來說,回合制游戲圍非常廣,棋牌、卡牌、戰(zhàn)棋策略、回合制戰(zhàn)斗模式都能歸為此類。
1.1.2狹義上的回合制游戲
狹義上的回合制游戲,是從廣義回合制游戲中細(xì)分,特指回合制戰(zhàn)斗模式的游戲,與即時制戰(zhàn)斗模式相對。
1.2回合制戰(zhàn)斗系統(tǒng)簡介
在回合制戰(zhàn)斗模式下,每個回合開場時,敵我雙方各自為雙方戰(zhàn)斗角色下達(dá)戰(zhàn)斗指令,待雙方所有角色下達(dá)完戰(zhàn)斗指令或超過時限〔回合制網(wǎng)絡(luò)游戲均會設(shè)置下達(dá)戰(zhàn)斗指令的時間限制〕后雙方所有角色開場行動,一般根據(jù)角色自身“速度〔敏捷〕〞的屬性數(shù)值輪流行動,期間假設(shè)果*一方符合戰(zhàn)敗條件〔*方全體陣亡或全體人物陣亡〕則戰(zhàn)斗完畢,如所有角色行動完后敵我雙方均沒符合戰(zhàn)敗條件,則進入下回合,如此循環(huán)。
1.3實踐工程"PKer"簡介
"PKer"是一個以回合制競技和社交為賣點的PC和移動端跨平臺網(wǎng)絡(luò)游戲,是游戲與社交APP的融合體。游戲主要玩法是玩家與玩家之間的回合制戰(zhàn)斗PK。
通過移動設(shè)備GPS定位功能〔PC端無法使用〕,能夠快速搜索在你身邊的游戲房間和玩家,與其開展戰(zhàn)斗。
游戲提供一定數(shù)量的根底裝備和寵物讓玩家任意領(lǐng)取,故玩家可以隨時更換裝備和寵物,新玩家也能以此為根底投入到戰(zhàn)斗中。更強的裝備和稀有的寵物通過合成、付費租用等渠道獲得。角色的屬性和職業(yè)也可以隨時更改,以便隨時改變戰(zhàn)術(shù)和改變在隊伍里中的定位。
第2章開發(fā)環(huán)境和局部涉及技術(shù)簡介
2.1開發(fā)環(huán)境簡介
本文實踐工程的效勞器采用國IOCP開源框架“HP-Socket〞,并且連接到Mysql數(shù)據(jù)庫,客戶端采用近年比擬熾熱的強大跨平臺引擎Unity3D〔2D,C*〕并且使用Sqlite作為嵌入式數(shù)據(jù)庫。
2.2Unity協(xié)同程序
2.2.1Unity協(xié)同程序簡介
協(xié)同程序〔Coroutine〕,通常簡稱“協(xié)程〞,顧名思義,是一段協(xié)助的程序〔方法〕,很多人以為它是另開一個線程執(zhí)行一段程序,其不然,實際上它是從主線程每幀或每隔一定時間調(diào)用的程序。當(dāng)協(xié)程創(chuàng)立后,主線程中創(chuàng)立協(xié)程的語句后面的代碼塊會“掛起〞,直到協(xié)同程序完畢后,才會繼續(xù)執(zhí)行創(chuàng)立協(xié)程語句后面的代碼。當(dāng)協(xié)程中的代碼執(zhí)行完或者使用yieldbreak語句時,協(xié)程才會完畢,并且返回到主線程中的創(chuàng)立該協(xié)程的語句的位置,繼續(xù)執(zhí)行后面的代碼。協(xié)程中使用yieldreturn幀數(shù)/newWaitForSeconds(秒數(shù))語句可以實現(xiàn)隔多少幀或多少秒后再執(zhí)行后續(xù)代碼。另外協(xié)程可以嵌套協(xié)程,利用協(xié)程的特點和嵌套,可以實現(xiàn)很多復(fù)雜和有趣的功能,十分強大。
2.2.2Unity協(xié)同程序的運用
協(xié)程廣泛地運用在計時、延遲、控制物體運動、等待物體狀態(tài)的改變、有順序地讓物體執(zhí)行一系列動作等方面上。
根據(jù)協(xié)程的特點,協(xié)程中可以使用“循環(huán)+條件判斷+yieldreturn幀數(shù)/newWaitForSeconds(秒數(shù))〞實現(xiàn)每隔多少幀或者多少秒后再次執(zhí)行條件判斷語句,當(dāng)判斷語句滿足跳出循環(huán),從而讓協(xié)程代碼執(zhí)行完完畢,回到主線程繼續(xù)執(zhí)行后續(xù)代碼,利用此功能,可以很方便地實現(xiàn)*物體到達(dá)*狀態(tài)后再執(zhí)行程序。
例如代碼:
主線程代碼
StartCoroutine(actor.Move(getAttackPosition(nTargetInde*)));
Inti=0;
協(xié)同程序Move方法
publicIEnumeratorMove(Vector3destPos)
{
while(transform.localPosition!=destPos)
{
transform.localPosition=Vector3.MoveTowards(transform.localPosition,destPos,GlobalData.BATTLE_SPRITE_MOVE_SPEED*Time.deltaTime);
yieldreturn0;
}
}
上述代碼中,主線程StartCoroutine方法創(chuàng)立一個協(xié)程Move,待協(xié)程Move執(zhí)行完成返回后,主線程才執(zhí)行i=0語句??墒菂f(xié)程Move的返回條件有點特殊,yieldreturn0語句表示協(xié)程運行到此處掛起,等下一幀再從本語句繼續(xù)運行,由于yieldreturn0在while循環(huán),所以不管yieldreturn0多少次,都依然在while循環(huán),而且while循環(huán)每一幀循環(huán)一次。直到while不滿足循環(huán)條件〔即transform.localPosition==destPos〕,則協(xié)程能夠完成使命執(zhí)行完成并返回??梢圆孪氲?,所控制的物體可能通過Update方法或者其他方法每幀在移動,直到移動到目標(biāo)地點,才執(zhí)行主線程后面的代碼。
2.3單例設(shè)計模式
2.3.1單例設(shè)計模式
單例設(shè)計模式是常見和簡單的一種軟件設(shè)計模式,單例模式下的類能確保在整個工程工程中只允許存在最多一個實例對象。單例模式下的類通常不能直接通過構(gòu)造函數(shù)new出一個實例,而且構(gòu)造函數(shù)通常會設(shè)置成私有,外部不可訪問。只有通過類的一個靜態(tài)方法可以創(chuàng)立或獲取有且只有唯一一個的對象實例。
2.3.2單例設(shè)計模式的運用
單例設(shè)計模式下的類往往具有通用性或全局性,用于保存全局?jǐn)?shù)據(jù),需要訪問其變量的外部類只需要通過單例類的靜態(tài)方法即可獲得其唯一的實例,從而訪問其部變量。
例如代碼:
publicclassClientSocket//單例類ClientSocket
{
privatestaticClientSocket_client_socket;//保存本類的唯一實例
privatestaticMessageManager_msg_mgr;
privatestaticSocket_socket;
privatestring_web="";
privateIPAddress_ip;
privateint_port=8000;
privatebyte[]_buf=newbyte[1024];
privateCircularBuffer_circularBuf=newCircularBuffer(4096);
privateClientSocket(){
}
publicstaticClientSocketgetInstance()
{
if(_client_socket==null)//假設(shè)實例不存在則創(chuàng)立,實例已存在則直接返回
{
_client_socket=newClientSocket();
_msg_mgr=MessageManager.getInstance();
}
return_client_socket;
}
……
}
2.3.3單例設(shè)計模式在Unity中的運用
在Unity中使用單例設(shè)計模式,有時會有額外的意義。在Unity中,通常一個類會作為一個組件掛載到一個物體上,可是如果進展了場景切換,當(dāng)前場景所有物體以及物體所掛載的所有組件都會被銷毀,這時如果想要所有場景都能訪問一個類的實例以及其變量,則需要把該類設(shè)置成單例類,并且不能繼承MonoBehaviour,而且不能掛載到任何一個物體上,這樣就可以保證整個游戲中不管場景怎么切換,該類的實例一直存在,而且只有唯一一個實例,所有場景均可通過靜態(tài)方法獲取實例并且訪問。
2.4分包算法
2.4.1分包的原因
TCP在發(fā)送消息時,如果發(fā)送間隔太短,發(fā)送方有可能出現(xiàn)一次發(fā)送多個消息的情況,而接收方便會一次接收到多個消息,另外,很多時候網(wǎng)絡(luò)情況較差或不穩(wěn)定,接收方遲遲收不到消息,過一段時間有可能一次過接收到此前該接收的多個消息,這些現(xiàn)象就是粘包。
由于粘包現(xiàn)象的存在,如果不進展分包,接收方可能只能讀取到粘包數(shù)據(jù)的頭一個消息,后面的消息將會喪失,甚至影響后續(xù)接收的消息,嚴(yán)重影響程序的運行。因此,我們需要一個分包算法來檢測粘包情況并進展分包,以便正確讀取所有來自發(fā)送方的消息。
2.4.2環(huán)形緩沖區(qū)〔CircularBuffer〕
在分包算法中,我們需要用到一個數(shù)據(jù)構(gòu)造——環(huán)形緩沖區(qū)。之所以要用到環(huán)形緩沖區(qū),是因為分包前我們要把接收到的所有數(shù)據(jù)存放在一個緩沖區(qū)中,分包時根據(jù)消息的長度從緩沖區(qū)里取數(shù)據(jù),取出后緩沖區(qū)相應(yīng)地移除對應(yīng)的數(shù)據(jù),這樣反復(fù)頻繁進展添加和刪除操作如果只用普通的緩沖區(qū)(byte數(shù)組/char數(shù)組)的話,則要頻繁地移動數(shù)據(jù)存放的位置,十分影響程序運行效率,為此需要引入環(huán)形緩沖區(qū)。
下面是環(huán)形緩沖區(qū)〔CricularBuffer〕類的UML類圖〔C++〕:
圖2-1環(huán)形緩沖區(qū)UML類圖
說明:
buf:指向緩沖區(qū)的指針
front:緩沖區(qū)的數(shù)據(jù)的起始位置
rear:緩沖區(qū)的數(shù)據(jù)的尾部位置
lock:用于多線程同步的臨界區(qū),防止多個線程訪問修改緩沖區(qū)數(shù)據(jù)
size:緩沖區(qū)數(shù)據(jù)的長度
capacity:緩沖區(qū)的容量
CircularBuffer:構(gòu)造函數(shù),創(chuàng)立一個指定容量為參數(shù)大小的緩沖區(qū)
~CircularBuffer:析構(gòu)函數(shù),釋放緩沖區(qū)
clear:清空緩沖區(qū)
pushBuf:往緩沖區(qū)尾部添加數(shù)據(jù)
popBuf:從緩沖區(qū)頭部得到數(shù)據(jù),并且緩沖區(qū)移除相應(yīng)數(shù)據(jù)
getBuf:從緩沖區(qū)頭部得到數(shù)據(jù),但緩沖區(qū)不移除數(shù)據(jù)
isEmpty:判斷緩沖區(qū)是否為空
由于環(huán)形緩沖區(qū)使用front起始位置和rear尾部位置記錄數(shù)據(jù)存放的位置,添加或移除數(shù)據(jù)不需要移動數(shù)據(jù)的儲存位置,運行效率高。
2.4.3分包算法流程圖
圖2-2分包算法流程圖
說明:
定義或獲得一個容量足夠大的環(huán)形緩沖區(qū)〔具體大小請根據(jù)實際情況考慮〕;
接收到數(shù)據(jù)后,往環(huán)形緩沖區(qū)尾部添加數(shù)據(jù);
判斷緩沖區(qū)的數(shù)據(jù)長度是否大于等于4〔消息頭的長度〕,本文實踐工程的構(gòu)造體消息頭由消息類型〔ushort〕和消息長度〔ushort〕組成,共4字節(jié)。假設(shè)緩沖區(qū)數(shù)據(jù)長度小于消息頭長度,則無法獲取第一條消息的長度,也無法分包,也說明數(shù)據(jù)接收不全,回到〔2〕繼續(xù)接收數(shù)據(jù),不進展任何操作;假設(shè)緩沖區(qū)數(shù)據(jù)長度大于等于消息頭長度,則開場進展分包;
從緩沖區(qū)頭部getBuf獲得4字節(jié)數(shù)據(jù)〔消息頭〕,不改變緩沖區(qū)數(shù)據(jù),從消息頭得到第一包消息的長度;
判斷緩沖區(qū)數(shù)據(jù)長度,假設(shè)緩沖區(qū)數(shù)據(jù)長度大于第一包消息的長度,則第一包消息接收完并可取,根據(jù)第一包消息的長度popBuf得到第一包消息數(shù)據(jù),并且緩沖區(qū)移除相應(yīng)數(shù)據(jù),處理該消息;假設(shè)緩沖區(qū)數(shù)據(jù)長度小于第一包消息長度〔此時緩沖區(qū)數(shù)據(jù)長度大于等于4,但是小于第一包消息的長度〕,則說明第一包消息還沒接收完,回到〔2〕繼續(xù)接收,不進展任何操作;
回到〔4〕,一直循環(huán)。
第3章戰(zhàn)斗動畫實現(xiàn)方案的研究與比照
3.1研究背景
筆者認(rèn)為回合制戰(zhàn)斗系統(tǒng)實現(xiàn)的最大難點,那無疑就是客戶端戰(zhàn)斗動畫的實現(xiàn)。回合制戰(zhàn)斗系統(tǒng)的戰(zhàn)斗動畫,不是平常我們說的“動畫〞,它是由數(shù)據(jù)轉(zhuǎn)換過來的動態(tài)動畫,動畫容由數(shù)據(jù)決定。例如動畫數(shù)據(jù)是“*個角色攻擊*個角色〞,動畫容便是“攻擊者移動到目標(biāo)面前并播放攻擊動作動畫,目標(biāo)播放受傷動作動畫,顯示扣血,攻擊者返回到本來的位置〞;再例如動畫數(shù)據(jù)是“*個角色使用技能攻擊*個角色〞,動畫容便是“施法者播放施法動作動畫,然后在目標(biāo)身上播放技能特效,等到特效播放到*一幀,目標(biāo)播放受傷動作動畫,顯示扣血〞。
上述例子已經(jīng)是回合制戰(zhàn)斗系統(tǒng)最根本的戰(zhàn)斗動畫,更不用說屢次攻擊或者屢次施法,可謂難上加難。更何況,戰(zhàn)斗動畫的質(zhì)量極大影響回合制游戲的可玩性,而且回合制戰(zhàn)斗除了玩家下達(dá)戰(zhàn)斗指令外,其余時間全部都在播放戰(zhàn)斗動畫上。
所以,筆者認(rèn)為客戶端的戰(zhàn)斗動畫實現(xiàn)是整個回合制戰(zhàn)斗系統(tǒng)的重點和難點,為了正確慎重地抉擇實現(xiàn)方案,少走彎路,額外對戰(zhàn)斗動畫的實現(xiàn)展開了研究。
3.2實現(xiàn)方案一:有限狀態(tài)機
這是筆者最先想到的方案,畢竟有限狀態(tài)機在游戲編程中實在極為常用,相信不少讀者也會率先聯(lián)想到這種方式。
有限狀態(tài)機代碼例如:
voidUpdate(){
switch(state)
{
case(int)State.Standby:
……
break;
case(int)State.Attack:
……
break;
case(int)State.Magic:
……
break;
……
}
……
}
有限狀態(tài)機方案下,Update方法每幀檢測記錄狀態(tài)的變量state,從而決定終究要執(zhí)行何種行為,當(dāng)行為執(zhí)行完或者*個事件觸發(fā)時,通過修改狀態(tài)變量state,改變執(zhí)行的行為。
優(yōu)點:
(1)靈活可變,隨時隨地都可以改變狀態(tài),從而改變執(zhí)行的行為
缺點:
每幀都需要檢測狀態(tài)變量,影響程序運行效率;
如果要實現(xiàn)一系列復(fù)雜的行為,代碼量大而且凌亂,邏輯復(fù)雜,例如要實現(xiàn)“攻擊者移動到目標(biāo)面前,攻擊者播放攻擊動畫,目標(biāo)播放受傷動畫,顯示扣血,攻擊者返回原本位置〞這樣的功能,可能需要不止一個狀態(tài)機;
Update方法變得臃腫,很多時候Update還需要做其他事情;
3.3實現(xiàn)方案二:協(xié)同程序(Coroutine)
在感覺方案一可行性不高的情況下,本人開場尋求其他實現(xiàn)方案,直到發(fā)現(xiàn)協(xié)同程序(Coroutine)。假設(shè)讀者不了解協(xié)程可閱本文第二章,協(xié)同程序在本文第2章有簡單介紹,此處不再作介紹。個人感覺Unity的協(xié)同程序跟Cocos2d的CCSequence動作有點像,都能很方便實現(xiàn)按順序執(zhí)行一系列動作,而且協(xié)同程序比CCSequence更靈活。
協(xié)同程序例如代碼:
IEnumeratorAttack(BATTLE_ANIMbattleAnim)
{
BattleSpritesprite=battleSprites[battleAnim.nActorInde*-1];
yieldreturnStartCoroutine(sprite.Move(getAttackPosition(nTargetInde*)));
yieldreturnStartCoroutine(sprite.AttackAnim());
yieldreturnStartCoroutine(sprite.Back(actor.vOrigPos));
}
協(xié)程Attack()能夠簡單清晰實現(xiàn)“控制*個物體移動到*個地點,完成后進展攻擊,攻擊完成后返回到*個地點〞,一步完成之后再進展下一步。
優(yōu)點:
不需要在Update每幀調(diào)用,協(xié)程開啟后根據(jù)代碼邏輯等待〔每〕n幀/n秒自動調(diào)用;
代碼邏輯清晰
能夠很好實現(xiàn)按順序執(zhí)行一系列復(fù)雜的行為
缺點:
如要中途終止協(xié)程,有一定的終止條件
沒狀態(tài)機靈活,難以臨時轉(zhuǎn)變行為
3.4方案抉擇結(jié)論
顯而易見,經(jīng)過筆者的研究和深思熟慮,本文采用了協(xié)同程序方案。理由很簡單,回合制戰(zhàn)斗動畫幾乎全避開了協(xié)程的缺點,表達(dá)了協(xié)程的優(yōu)點。因為回合制戰(zhàn)斗動畫是由效勞器發(fā)來的動畫數(shù)據(jù)轉(zhuǎn)換的,數(shù)據(jù)自始至終沒有改變,客戶端只負(fù)責(zé)播放動畫效果,并沒有修改數(shù)據(jù),則從數(shù)據(jù)轉(zhuǎn)化為動畫那刻開場,動畫就不可能有變化或者中途終止,并不需要程序的靈活性。這么看來,協(xié)程用在回合制戰(zhàn)斗動畫的播放很是適合。
另外,讀者也可考慮行為樹方案,由于筆者時間和能力有限,截至目前未能深入學(xué)習(xí)研究行為樹,不知是否能比協(xié)程更好地實現(xiàn)戰(zhàn)斗動畫,所以本文未能提及,懇請體諒。
第4章回合制網(wǎng)游戰(zhàn)斗系統(tǒng)設(shè)計
4.1回合制網(wǎng)游戰(zhàn)斗系統(tǒng)設(shè)計
我們從回合制網(wǎng)游中不難發(fā)現(xiàn),在客戶端面前,我們可以看到一場回合制戰(zhàn)斗可劃分為以下階段:進入戰(zhàn)斗-玩家下達(dá)戰(zhàn)斗指令〔很多情況下需要下達(dá)人物和寵物兩個戰(zhàn)斗指令〕-戰(zhàn)斗動畫-戰(zhàn)斗完畢。經(jīng)過本人對上述戰(zhàn)斗過程的研究、思考和分析,得出個人的回合制戰(zhàn)斗系統(tǒng)實現(xiàn)思路,戰(zhàn)斗系統(tǒng)流程圖如圖:
圖4-1回合制網(wǎng)游戰(zhàn)斗系統(tǒng)流程圖
4.2回合制網(wǎng)游戰(zhàn)斗系統(tǒng)效勞器實現(xiàn)思路
〔1〕戰(zhàn)斗開場發(fā)送“戰(zhàn)斗初始化消息〞給客戶端,“戰(zhàn)斗初始化消息〞包含所有戰(zhàn)斗角色〔人物和寵物〕的名字、圖形及動畫控制器ID、最大Hp、當(dāng)前Hp、最大Mp、當(dāng)前Mp等數(shù)據(jù),客戶端只關(guān)心需要顯示的容;
〔2〕根據(jù)戰(zhàn)斗角色的數(shù)量,等待接收并保存數(shù)量與角色數(shù)量想當(dāng)?shù)膩碜钥蛻舳说摹皯?zhàn)斗指令消息〞,即等待所有戰(zhàn)斗角色都下達(dá)完戰(zhàn)斗指令;
〔3〕接收到足夠數(shù)量的“角色戰(zhàn)斗指令消息〞后,根據(jù)角色的“速度〞屬性數(shù)值,倒序〔即速度高者先行動〕處理每一個戰(zhàn)斗指令所造成的影響,并更新效勞器各個角色的數(shù)值,發(fā)送對應(yīng)的“動畫消息〞給所有客戶端,每處理一個“戰(zhàn)斗指令消息〞就發(fā)送一個對應(yīng)的“動畫消息〞;
〔4〕待所有“戰(zhàn)斗指令消息〞處理完并發(fā)送完對應(yīng)的“動畫消息〞后,發(fā)送“動畫播放消息〞;
〔5〕判斷雙方角色的陣亡情況,假設(shè)一方符合戰(zhàn)敗條件〔所有角色陣亡或者所有人物陣亡,具體根據(jù)游戲設(shè)定決定〕則完畢戰(zhàn)斗,否則回到步驟〔2〕進入下一個回合,如此循環(huán)。
4.3回合制網(wǎng)游戰(zhàn)斗系統(tǒng)客戶端實現(xiàn)思路
〔1〕假設(shè)接收到“戰(zhàn)斗初始化消息〞,則進入戰(zhàn)斗,并根據(jù)消息里的數(shù)據(jù),初始化每一個戰(zhàn)斗角色;
〔2〕顯示人物戰(zhàn)斗指令菜單,根據(jù)玩家的操作,發(fā)送“戰(zhàn)斗指令消息〞,人物戰(zhàn)斗指令菜單消失;
〔3〕假設(shè)沒有參戰(zhàn)寵物,直接跳到下一步,假設(shè)有參戰(zhàn)寵物,顯示寵物戰(zhàn)斗指令菜單,根據(jù)玩家的操作,發(fā)送“戰(zhàn)斗指令消息〞,寵物戰(zhàn)斗指令菜單消失;
〔4〕接收并保存每一個來自效勞器的“動畫消息〞或“動畫播放消息〞;
〔5〕收到“動畫播放消息〞后,讀取并處理每一個“動畫消息〞,轉(zhuǎn)化為對應(yīng)等量的戰(zhàn)斗動畫類并用容器保存,遍歷容器播放所有動畫;
〔6〕當(dāng)前回合所有戰(zhàn)斗動畫播放完后,判斷雙方陣亡情況,假設(shè)一方符合戰(zhàn)敗條件〔所有角色陣亡或者所有人物陣亡,具體根據(jù)游戲設(shè)定決定〕則完畢戰(zhàn)斗,否則回到步驟〔2〕進入下一個回合,如此循環(huán)。
4.4戰(zhàn)斗系統(tǒng)框架構(gòu)造〔以實踐工程"PKer"為例〕
雖然本文主要闡述戰(zhàn)斗系統(tǒng),但是由于戰(zhàn)斗系統(tǒng)較為復(fù)雜,為了讓讀者更好的理解本文所述戰(zhàn)斗系統(tǒng)的實現(xiàn)思路,以實踐工程"PKer"為例,對游戲的戰(zhàn)斗系統(tǒng)架構(gòu)和相關(guān)功能架構(gòu)進展簡單的羅列和說明。
圖4-2實踐工程"PKer"戰(zhàn)斗系統(tǒng)及相關(guān)功能架構(gòu)
說明:
玩家從游戲大廳可以搜索參加房間或創(chuàng)立房間,與房間其他玩家進展對戰(zhàn)進入戰(zhàn)斗〔讀者可根據(jù)自身游戲玩法考慮如何觸發(fā)戰(zhàn)斗,如常見的回合制游戲通過暗雷或明雷遇敵、玩家對點觸發(fā)戰(zhàn)斗〕;
"PKer"中玩家可以直接在玩家屬性配置界面過點選“寵物庫〞的寵物即可獲得對應(yīng)寵物,并且通過設(shè)置“參戰(zhàn)寵物〞可讓寵物在戰(zhàn)斗中出戰(zhàn)〔讀者可根據(jù)自身游戲玩法考慮寵物的獲得途徑,常見的途徑有戰(zhàn)斗捕捉、任務(wù)獎勵等〕;
"PKer"中玩家可以直接在玩家屬性配置界面過點選“裝備物品庫〞的裝備/物品即可獲得對應(yīng)裝備/物品,裝上裝備將提高角色的屬性使角色更具戰(zhàn)斗力,放在物品欄的物品可以在戰(zhàn)斗中使用回復(fù)Hp/Mp〔讀者可根據(jù)自身游戲玩法考慮裝備物品的獲得途徑,常見的途徑有戰(zhàn)斗獎勵、任務(wù)獎勵等〕;
"PKer"中玩家可以直接在玩家屬性配置界面中更改職業(yè),從而獲得在戰(zhàn)斗中使用的技能;
進入戰(zhàn)斗后,參戰(zhàn)角色的屬性由各個玩家配置〔屬性加點、裝備、參戰(zhàn)寵物、職業(yè)等〕所決定;
各玩家通過指令菜單下達(dá)指令從而控制自身角色和自身參戰(zhàn)寵物〔如有設(shè)置參戰(zhàn)寵物〕的行動。其中,使用技能能夠選擇使用自身職業(yè)的技能,使用物品能夠選擇使用物品欄的物品;
戰(zhàn)斗動畫主要由多個協(xié)同程序組成來實現(xiàn),根據(jù)各個參戰(zhàn)人物/寵物的下達(dá)的戰(zhàn)斗指令對應(yīng)的播放其行為的動畫,不同的行為動畫容不一樣;
而在技能動畫中,為了增加回合制戰(zhàn)斗的畫面感和可玩性,對不同的技能配置了不同的特效播放方式,讓特效動畫更華美更多元化,詳細(xì)實現(xiàn)方式在本文和小節(jié)有闡述;
第5章回合制戰(zhàn)斗系統(tǒng)實現(xiàn)
5.1戰(zhàn)斗系統(tǒng)相關(guān)消息構(gòu)造體的定義
構(gòu)造體消息是效勞器與客戶端溝通的“共同語言〞,構(gòu)造體消息在客戶端和效勞器分別定義并且數(shù)據(jù)構(gòu)造是一樣,發(fā)送方填寫構(gòu)造體數(shù)據(jù),接收方先獲取消息頭的消息類型ID和長度,再判斷是哪種類型的消息并轉(zhuǎn)換成該類型構(gòu)造體,然后讀取容并進展對應(yīng)的處理。
以下是Unity客戶端〔C*〕中定義的相關(guān)構(gòu)造體消息,效勞器的定義與其一致,但由于效勞器〔C++〕與客戶端〔C*〕的編程語言不同所以定義語法有些許區(qū)別。
//戰(zhàn)斗初始化消息
publicstructMSG_BATTLE_INIT
{
publicushortnMsgID;//消息類型ID
publicushortnLen;//構(gòu)造體長度
publicuintnBattleID;//戰(zhàn)局ID
[MarshalAs(UnmanagedType.ByValArray,SizeConst=20)]
publicBATTLE_SPRITE_INIT[]battleSprites;//所有戰(zhàn)斗角色根本數(shù)據(jù)
};
//戰(zhàn)斗角色〔人物/寵物〕根本數(shù)據(jù)消息
publicstructBATTLE_SPRITE_INIT
{
publicuintnID;//玩家/寵物ID〔客戶端用此值判斷是否有戰(zhàn)斗成員,可能還會用來標(biāo)識自身和自身寵物〕
[MarshalAs(UnmanagedType.ByValArray,SizeConst=22)]
publicbyte[]strName;//戰(zhàn)斗人物/寵物名字
publicuintnImageID;//圖形及動畫控制器ID
publicshortnHpMa*;//最大HP
publicshortnHp;//當(dāng)前HP
publicshortnMpMa*;//最大MP
publicshortnMp;//當(dāng)前MP
};
//戰(zhàn)斗指令消息
publicstructMSG_BATTLE_MAND
{
publicushortnMsgID;//消息類型ID
publicushortnLen;//構(gòu)造體長度
publicushortnActorType;//行動者類型〔1=人物2=寵物,由效勞端賦值,客戶端不需要賦值〕
publicushortnActorInde*;//行動者索引〔由效勞端賦值,客戶端不需要賦值〕
publicushortnActionType;//行動的類型
publicushortnTargetInde*;//目標(biāo)索引
publicushortnParam;//參數(shù)〔根據(jù)行動類型而定,如使用技能則是技能ID,使用物品則是物品欄位置,切換戰(zhàn)寵則是寵物欄位置〕
};
//戰(zhàn)斗動畫播放消息〔客戶端收到此消息后開場播放戰(zhàn)斗動畫〕
publicstructMSG_BATTLE_ANIM_BEGIN
{
publicushortnMsgID;//消息類型ID
publicushortnLen;//構(gòu)造體長度
};
//戰(zhàn)斗動畫消息
publicstructMSG_BATTLE_ANIM
{
publicushortnMsgID;//消息類型ID
publicushortnLen;//構(gòu)造體長度
publicushortnActorInde*;//行動者索引
[MarshalAs(UnmanagedType.ByValArray,SizeConst=10)]
publicushort[]nTargetInde*;//目標(biāo)索引〔初始值為0,0則無目標(biāo)〕
publicushortaction_type;//行動類型
publicushortnParam;//參數(shù)〔根據(jù)行動類型而定,如使用技能則是技能ID,使用物品則是物品欄位置〕
[MarshalAs(UnmanagedType.ByValArray,SizeConst=10)]
publicshort[]nActorHp;//行動者Hp影響〔<0:扣血,>0:加血,0=無任何影響〕
[MarshalAs(UnmanagedType.ByValArray,SizeConst=10)]
publicshort[]nActorMp;//行動者Mp影響
[MarshalAs(UnmanagedType.ByValArray,SizeConst=10)]
publicshort[]nTargetHp;//目標(biāo)Hp影響〔<0:扣血,>0:加血,0=無任何影響〕
[MarshalAs(UnmanagedType.ByValArray,SizeConst=10)]
publicshort[]nTargetMp;//目標(biāo)Mp影響
};
5.2效勞器戰(zhàn)斗系統(tǒng)的實現(xiàn)
5.2.1效勞器戰(zhàn)斗系統(tǒng)相關(guān)構(gòu)造體
圖5-1效勞器戰(zhàn)斗系統(tǒng)的相關(guān)構(gòu)造體的關(guān)系圖
//戰(zhàn)局構(gòu)造體
structBATTLE
{
UINTnBattleID;//戰(zhàn)局ID
BATTLE_SPRITEbattleSprites[20];//戰(zhàn)斗角色〔人物/寵物〕數(shù)組
std::list<USHORT>team1_survivors_inde*;//隊伍1存活者索引list
std::list<USHORT>team2_survivors_inde*;//隊伍2存活者索引list
USHORTnSpriteTotal;//參戰(zhàn)角色總數(shù)
std::multimap<float,MSG_BATTLE_MAND*>m_mandMap;//玩家戰(zhàn)斗指令字典,用于保存每回合接收的戰(zhàn)斗指令消息,Key為角色速度數(shù)值
}
說明:
battleSprites數(shù)組的索引0-4位置分別為隊伍1人物1、隊伍1人物2……,索引5-9位置分別為隊伍1人物1的寵物、隊伍1人物2的寵物……,類似的,索引10-14為隊伍2人物,索引15-19為隊伍2寵物,人物索引+5即該人物的寵物的索引,根據(jù)人物索引即可獲得其寵物索引
//戰(zhàn)斗角色〔人物/寵物〕
structBATTLE_SPRITE
{
BATTLE_SPRITE_DATA*pBattleData;//戰(zhàn)斗數(shù)據(jù)(包含Hp、Mp、攻擊力等)
CLIENT_DATA*pClient;//客戶端數(shù)據(jù)〔CLIENT_DATA包含客戶端IOCP完成鍵、套接字、玩家游戲數(shù)據(jù)等數(shù)據(jù),本文不闡述,請讀者根據(jù)自身游戲效勞器架構(gòu)設(shè)計〕
USHORTnType;//角色類型,1=人,2=寵物
USHORTbmand;//是否已經(jīng)下命令,0=沒下命令,1=已下命令
}
//戰(zhàn)斗數(shù)據(jù)(人物與寵物通用)
structBATTLE_SPRITE_DATA
{
UINTnID;//玩家/寵物ID
charstrName[22];//戰(zhàn)斗人物/寵物名字
UINTnImageID;//圖形及動畫控制器ID
USHORTnLevel;//等級
shortnHpMa*;//最大Hp
shortnHp;//當(dāng)前Hp
shortnMpMa*;//最大Mp
shortnMp;//當(dāng)前Mp
shortnAtk;//物理攻擊力
shortnDef;//物理防御力
shortnMat;//魔法攻擊力
shortnMdf;//魔法防御力
shortnSpd;//速度
}
5.2.2初始化一個戰(zhàn)局
即初始化一個戰(zhàn)局BATTLE實例,并根據(jù)參戰(zhàn)玩家的數(shù)據(jù)對戰(zhàn)局所有成員進展賦值,由于成員較多,并且游戲邏輯復(fù)雜,讀者可根據(jù)自身游戲邏輯賦值,此處初始化的方式不影響后續(xù)的實現(xiàn),所以這里不進展詳細(xì)闡述,最后在客戶端數(shù)據(jù)存放指向戰(zhàn)局的指針,以便后面通過完成鍵以及客戶端數(shù)據(jù)能夠獲得戰(zhàn)局?jǐn)?shù)據(jù)。
本文假設(shè)一個戰(zhàn)局最多能5位玩家對戰(zhàn)5位玩家,包括每位玩家可出戰(zhàn)的一個戰(zhàn)斗寵物,所以一個戰(zhàn)局最多能有20個戰(zhàn)斗角色,故battleSprites戰(zhàn)斗角色數(shù)組長度為20,讀者可根據(jù)自身游戲邏輯進展變更。另外,如果戰(zhàn)局缺乏20個戰(zhàn)斗角色,本文通過檢查battleSprites中的戰(zhàn)斗數(shù)據(jù)pBattleData是否為NULL進展判斷并計數(shù),用成員nSpriteTotal保存戰(zhàn)斗角色總數(shù)。戰(zhàn)局初始時所有戰(zhàn)斗角色理應(yīng)是存活的,battleSprites中所有存在的戰(zhàn)斗角色的索引相應(yīng)的存放到隊伍1存活索引list或隊伍2存活索引list中,本文假設(shè)索引0-9為隊伍1〔0-4隊伍1人物,5-9隊伍1寵物〕,10-19為隊伍2〔10-14為隊伍2人物,15-19為隊伍2寵物〕,并且人物和其寵物的索引相差5〔即0索引上的人物其寵物索引為5,如此類推〕。
5.2.3接收客戶端的戰(zhàn)斗指令消息
圖5-2接收戰(zhàn)斗指令消息流程圖
收到客戶端發(fā)來的消息后,通過消息頭和消息類型ID〔可用宏定義或定義枚舉類型〕的判斷,確定是否為戰(zhàn)斗指令消息后,然后處理戰(zhàn)斗指令消息。
本文實踐工程從IOCP完成鍵可以獲取玩家數(shù)據(jù)進而獲取玩家所在的戰(zhàn)局指針〔BATTLE*〕。收到戰(zhàn)斗指令消息后,通過消息中的行動者索引nActorInde*從戰(zhàn)局的戰(zhàn)斗角色battleSprites數(shù)組中獲取該角色,根據(jù)該角色的“速度〞數(shù)值和戰(zhàn)斗指令消息一并參加到戰(zhàn)斗指令字典m_mandMap中,以便之后遍歷逐個處理。檢測m_mandMap的元素個數(shù)是否等于戰(zhàn)斗角色總數(shù)〔即檢測是否所有戰(zhàn)斗角色都已下達(dá)戰(zhàn)斗指令,假設(shè)等于則開場遍歷m_mandMap處理本回合的所有戰(zhàn)斗指令。
5.2.4處理戰(zhàn)斗指令并發(fā)送動畫消息
圖5-3效勞器處理戰(zhàn)斗指令消息流程圖
當(dāng)本回合所有戰(zhàn)斗角色都下達(dá)戰(zhàn)斗指令〔效勞器收到的指令數(shù)等于角色數(shù)量〕后,開場倒序遍歷〔倒序的原因是,multimap按從小到大排序,而我們的邏輯是速度高的先行動〕處理每一條戰(zhàn)斗指令。
倒序遍歷時,先判斷發(fā)出該戰(zhàn)斗指令消息的角色是否已經(jīng)死亡,假設(shè)死亡則不能進展任何行為,直接跳出進入下一次循環(huán)。假設(shè)發(fā)出指令的角色沒有死亡,根據(jù)指令的nActionType行動類型〔攻擊、使用技能、使用物品、更換寵物等〕進展不同的處理,計算每一條戰(zhàn)斗指令所造成的影響,并發(fā)送對應(yīng)的動畫消息。
假設(shè)在計算完每一條戰(zhàn)斗指令所造成的影響后,檢查雙方存活狀況,假設(shè)一方全員陣亡則戰(zhàn)斗完畢,并發(fā)送戰(zhàn)斗動畫播放消息,客戶端開場播放動畫。
假設(shè)計算完所有戰(zhàn)斗指令后戰(zhàn)斗并沒有完畢,發(fā)送戰(zhàn)斗動畫播放消息,客戶端開場播放動畫,進入下一回合,清空m_mandMap所有元素,效勞器繼續(xù)接收新回合的來自客戶端的戰(zhàn)斗指令消息。
下面是不同的行動類型的不同處理方式:
攻擊:
聲明一個戰(zhàn)斗動畫消息,nActionType賦值為“攻擊〔枚舉或自定義宏〕〞,根據(jù)戰(zhàn)斗指令消息里的nActorInde*行動者索引和nTargetInde*目標(biāo)索引從戰(zhàn)局中獲取對應(yīng)的戰(zhàn)斗角色〔battleSprites[nActorInde*]和battleSprites[nTargetInde*]〕,假設(shè)目標(biāo)死亡則從對應(yīng)隊伍的存活者列表中隨機一個新目標(biāo)索引。把目標(biāo)索引值賦值給戰(zhàn)斗動畫消息的nTargetInde*[0]。
根據(jù)行動者攻擊和目標(biāo)防御力計算傷害值,賦值給nTargetHp[0],并且目標(biāo)扣除對應(yīng)Hp,判斷目標(biāo)扣除Hp后Hp是否小于等于0〔即死亡〕,假設(shè)死亡則從對應(yīng)隊伍的存活者列表中移除。
最后,發(fā)送戰(zhàn)斗動畫消息給戰(zhàn)局所有玩家。
使用技能:
本文的實踐工程通過數(shù)據(jù)庫配置所有技能的相關(guān)數(shù)據(jù),包括技能的ID、作用目標(biāo)數(shù)量、特效動畫ID、特效播放方式〔僅在客戶端使用〕、Mp消耗、傷害公式等。
聲明一個戰(zhàn)斗動畫消息,nActionType賦值為“使用技能〔枚舉或自定義宏〕〞,通過戰(zhàn)斗指令消息的nParam查找數(shù)據(jù)庫的技能表獲取該技能的相關(guān)數(shù)據(jù),根據(jù)戰(zhàn)斗指令消息的nActorInde*和nTargetInde*從戰(zhàn)局獲得對應(yīng)的角色battleSprites[nActorInde*]和battleSprites[nTargetInde*]〕,根據(jù)技能Mp消耗數(shù)值賦值到動畫消息的nActorMp上,并且減少使用者角色的Mp。如果目標(biāo)角色死亡,則從目標(biāo)角色的隊伍存活者列表中隨機得到新的目標(biāo)索引,并賦值多體戰(zhàn)斗動畫消息nTargetInde*數(shù)組的對應(yīng)索引位置上,再根據(jù)行動者的魔法攻擊力和目標(biāo)的魔法防御力以及技能的傷害公式計算傷害數(shù)值,賦值nTargetHp數(shù)組對應(yīng)的索引位置上,并且目標(biāo)扣除對應(yīng)Hp,判斷目標(biāo)扣除Hp后Hp是否小于等于0〔即死亡〕,假設(shè)死亡則從對應(yīng)隊伍的存活者列表中移除。之后再隨機目標(biāo),并計算傷害數(shù)值,直到目標(biāo)數(shù)量到達(dá)技能的作用目標(biāo)數(shù)量。
最后,發(fā)送戰(zhàn)斗動畫消息給戰(zhàn)局所有玩家。
使用物品:
本文的實踐工程通過數(shù)據(jù)庫配置所有物品的相關(guān)數(shù)據(jù),包括物品的ID、作用于單體/全體、Hp回復(fù)量、Mp回復(fù)量等。
聲明一個戰(zhàn)斗動畫消息,nActionType賦值為“使用物品〔枚舉或自定義宏〕〞,通過戰(zhàn)斗指令消息的nParam獲取玩家對應(yīng)物品欄位置的物品ID〔物品欄的實現(xiàn)本文不闡述〕,把物品ID賦值給戰(zhàn)斗動畫消息的nParam,根據(jù)物品ID查找數(shù)據(jù)庫的物品表獲取該物品的相關(guān)數(shù)據(jù),根據(jù)戰(zhàn)斗指令消息的nActorInde*賦值給動畫消息的nActorInde*,根據(jù)物品是作用于單體還是全體對動畫消息的nTargetInde*數(shù)組進展賦值,根據(jù)物品的Hp回復(fù)量和Mp回復(fù)量分別對nTargetHp和nTargetMp數(shù)組進展賦值。根據(jù)物品回復(fù)量更新目標(biāo)的Hp/Mp,注意不能超出最大Hp上限/最大Mp上限。
最后,發(fā)送戰(zhàn)斗動畫消息給戰(zhàn)局所有玩家。
5.2.5說明
本文為了盡量簡短地闡述實現(xiàn)方式,戰(zhàn)斗指令消息的行動者索引nActorInde*由客戶端直接賦值,效勞器并沒有對此進展檢查而直接使用。假設(shè)客戶端并沒有使用自身角色的索引賦值而對nActorInde*進展修改作弊,則能夠冒充其他玩家角色下達(dá)戰(zhàn)斗指令,存在隱患,所以戰(zhàn)斗指令消息的nActorInde*應(yīng)該由效勞器賦值并檢查,但由于本文篇幅所限并且考慮到游戲邏輯的復(fù)雜性和不一性,上述實現(xiàn)方式并沒有過多考慮防客戶端作弊,懇請讀者體諒。
而實際上,效勞器在很多地方都應(yīng)該對客戶端發(fā)來的消息進展合法性檢查,防客戶端外掛或作弊,還請讀者根據(jù)自身游戲邏輯另外考慮。
5.3客戶端戰(zhàn)斗系統(tǒng)的實現(xiàn)
5.3.1客戶端戰(zhàn)斗系統(tǒng)功能模塊
圖5-4客戶端戰(zhàn)斗系統(tǒng)功能模塊
說明:
戰(zhàn)斗系統(tǒng)主要包含戰(zhàn)斗角色、戰(zhàn)斗動畫和戰(zhàn)斗指令菜單三個模塊;
戰(zhàn)斗指令菜單類型分為人物和寵物兩種,分別用于下達(dá)人物和寵物戰(zhàn)斗指令,并發(fā)送戰(zhàn)斗指令消息給效勞器;
戰(zhàn)斗角色由角色圖形、動畫控制器和血條組成,通過動畫控制器切換不同動作的動畫,主要負(fù)責(zé)戰(zhàn)斗角色的圖形顯示;
戰(zhàn)斗動畫模塊主要有動畫計數(shù)、把接收到的所有動畫消息轉(zhuǎn)換為戰(zhàn)斗動畫類以及播放戰(zhàn)斗動畫三個功能;
動畫計數(shù)主要是為了等待戰(zhàn)斗中所有正在播放的角色動作動畫、特效動畫播放完,角色動作動畫或特效動畫開場時會+1動畫計數(shù),完畢時會-1動畫計數(shù),動畫計數(shù)為0后,當(dāng)前單位行動完畢,下一個行動單位開場行動;
播放戰(zhàn)斗動畫模塊根據(jù)戰(zhàn)斗動畫類數(shù)據(jù)播放不同行為的動畫〔主要使用協(xié)程來控制戰(zhàn)斗角色的移動、切換戰(zhàn)斗角色的動作動畫、添加特效等〕。
5.3.2客戶端戰(zhàn)斗系統(tǒng)相關(guān)數(shù)據(jù)類型
//戰(zhàn)斗動畫類
publicclassBATTLE_ANIM
{
publicushortnActorInde*;//行動方索引
publicushort[]nTargetInde*=newushort[10];//目標(biāo)索引
publicushortaction_type;//行動類型
publicushortnParam;//參數(shù)〔根據(jù)行動類型而定,如使用技能則是技能ID,使用物品則是物品欄位置〕
publicushortnAnimType;//技能動畫類型
publicushortnEffectID;//技能特效ID
publicushortnTargetCount;//目標(biāo)總數(shù)〔nTargetInde*數(shù)組中值不為0的個數(shù)〕
publicushortnReactionInde*;//當(dāng)前受影響的目標(biāo)索引
publicshortnActorMp;//行動方Mp影響〔多用于計算技能使用者的Mp消耗〕
publicshort[]nTargetHp=newshort[10];//目標(biāo)索引對應(yīng)的目標(biāo)Hp影響
}
5.3.3進入戰(zhàn)斗后初始化戰(zhàn)斗角色
收到來自效勞器的戰(zhàn)斗初始化消息后,切換到戰(zhàn)斗場景,并根據(jù)戰(zhàn)斗初始化消息中的battleSprites數(shù)組〔包含戰(zhàn)斗角色的玩家ID、圖形及動畫控制器ID、名字、Hp和Mp等數(shù)據(jù)〕動態(tài)生成對應(yīng)的戰(zhàn)斗角色。
并且從戰(zhàn)斗初始化消息中的battleSprites數(shù)組中,比照玩家ID〔客戶端在登錄游戲后,理應(yīng)早已得到玩家ID,則在這里與battleSprites數(shù)組的玩家ID進展比照〕查找自身角色和寵物的索引,用變量保存該索引,用于下達(dá)戰(zhàn)斗指令。
5.3.4下達(dá)戰(zhàn)斗指令并發(fā)送戰(zhàn)斗指令消息
下達(dá)戰(zhàn)斗指令實質(zhì)是地對戰(zhàn)斗指令消息的賦值。
一般是先下達(dá)人物戰(zhàn)斗指令,如有參戰(zhàn)寵物,再下達(dá)戰(zhàn)斗指令。在本文中,進入戰(zhàn)斗時,客戶端已能獲得自身人物和寵物在戰(zhàn)斗中的索引,假設(shè)是輪到人物下達(dá)戰(zhàn)斗指令,則戰(zhàn)斗指令消息的nActorInde*是人物的索引,假設(shè)是輪到寵物下達(dá)戰(zhàn)斗指令,則指令消息的nActorInde*是寵物的索引,分情況賦值即可,然后根據(jù)不同的行動類型對指令消息的nActionType行動類型賦值,最后通過點選目標(biāo)對指令消息的nTargetInde*進展賦值。
當(dāng)下達(dá)完人物和寵物的戰(zhàn)斗指令后,分別發(fā)送對應(yīng)的戰(zhàn)斗指令消息。
戰(zhàn)斗指令菜單的UI實現(xiàn)千變?nèi)f化,本文不作闡述,使用最簡單的按鈕即可實現(xiàn)。
下列圖為實踐工程的指令菜單,其中玩家選擇了使用技能的行動,并即將點選技能:
圖5-5指令菜單
5.3.5接收戰(zhàn)斗動畫消息
根據(jù)每一條接收到的戰(zhàn)斗動畫消息對new出來的戰(zhàn)斗動畫類賦值,并push_back到一個順序容器〔可考慮List〕。
5.3.6收到戰(zhàn)斗動畫播放消息并播放戰(zhàn)斗動畫
當(dāng)接收到來自效勞器的戰(zhàn)斗動畫播放消息后,客戶端開場從頭到尾遍歷存放了多個戰(zhàn)斗動畫類的順序容器,根據(jù)戰(zhàn)斗動畫類的數(shù)據(jù),逐個播放動畫。
戰(zhàn)斗動畫的實現(xiàn)方式主要是依靠協(xié)同程序和動畫計數(shù)器。角色播放動作動畫〔除待機〕或每往場景中添加一個特效動畫,動畫計數(shù)加1,角色播放動作動畫〔除待機〕完畢時調(diào)用方法切回待機動畫并且動畫計數(shù)-1,特效動畫播放完畢時銷毀自身并且調(diào)用方法把動畫計數(shù)減1,當(dāng)動畫所有協(xié)程完畢返回并且動畫計數(shù)為0時,當(dāng)前動畫播放完畢,開場播放下一個動畫。
當(dāng)播放完所有戰(zhàn)斗動畫類后,清空容器,假設(shè)一方全體陣亡,則戰(zhàn)斗完畢退出戰(zhàn)斗場景,否則進入下一回合,玩家開場下達(dá)新回合的戰(zhàn)斗指令。
根據(jù)戰(zhàn)斗動畫類的行動類型和特效播放方式的不同,動畫播放實現(xiàn)方式也不同,由于動畫的實現(xiàn)較為復(fù)雜,本文在小節(jié)單獨以普通攻擊動畫進展較詳細(xì)的闡述,讀者可結(jié)合本小節(jié)和小節(jié)進展理解。
下面是各種戰(zhàn)斗動畫的實現(xiàn)方式:
普通攻擊動畫協(xié)程
①行動者角色執(zhí)行協(xié)程Move(),從自身位置移動到目標(biāo)角色位置,到達(dá)后協(xié)程完畢返回;
②行動者播放攻擊動作動畫,目標(biāo)播放受傷動作動畫并顯示目標(biāo)扣血數(shù)值,更新角色Hp/Mp,假設(shè)角色Hp為0則播放死亡動作動畫;
③使用循環(huán)和yieldreturn0語句直到動畫計數(shù)為0〔即攻擊動畫、受傷動畫播放完〕跳出循環(huán);
④行動者角色執(zhí)行協(xié)程Back(),回到原本的位置,到達(dá)原本的位置后協(xié)程完畢返回;
⑤協(xié)程完畢返回。
攻擊技能動畫協(xié)程
①行動者角色執(zhí)行協(xié)程Move(),從自身位置移動到目標(biāo)角色位置,到達(dá)后協(xié)程完畢返回;
②行動者播放攻擊動作動畫,添加并播放技能特效動畫,目標(biāo)播放受傷動作動畫并顯示目標(biāo)扣血數(shù)值,更新角色Hp/Mp,假設(shè)角色Hp為0則播放死亡動作動畫;
③使用while循環(huán)和yieldreturn0語句直到動畫計數(shù)為0〔即攻擊動畫、受傷動畫、特效動畫播放完〕,后跳出循環(huán);
④行動者角色執(zhí)行協(xié)程Back(),回到原本的位置,到達(dá)原本的位置后Back()協(xié)程完畢返回;
⑤協(xié)程完畢返回。
魔法技能〔同步型特效〕動畫協(xié)程
①行動者播放施法動作動畫,遍歷所有目標(biāo),并在目標(biāo)位置上添加并播放特效動畫,目標(biāo)播放受傷動作動畫并顯示扣血數(shù)值,更新角色Hp/Mp,假設(shè)角色Hp為0則播放死亡動作動畫;
②使用while循環(huán)和yieldreturn0語句直到動畫計數(shù)為0〔即攻擊動畫、受傷動畫、特效動畫播放完〕,后跳出循環(huán);
③協(xié)程完畢返回。
動畫效果如下列圖:
圖5-6魔法技能〔同步型特效〕動畫效果
魔法技能〔異步型特效〕動畫協(xié)程
①行動者播放施法動作動畫,遍歷所有目標(biāo),并在目標(biāo)位置上添加并播放特效動畫,目標(biāo)播放受傷動作動畫并顯示扣血數(shù)值,更新角色Hp/Mp,假設(shè)角色Hp為0則播放死亡動作動畫,遍歷中使用yieldreturn幀數(shù)/秒數(shù)實現(xiàn)延遲,從而到達(dá)每個目標(biāo)身上出現(xiàn)的特效動畫時間不一樣;
②使用while循環(huán)和yieldreturn0語句直到動畫計數(shù)為0〔即攻擊動畫、受傷動畫、特效動畫播放完〕,后跳出循環(huán);
③協(xié)程完畢返回。
動畫效果如下列圖:
圖5-7魔法技能〔異步型特效〕動畫效果
魔法技能〔彈射型特效〕動畫協(xié)程
①行動者播放施法動作動畫,行動者身上添加一個循環(huán)播放的特效動畫;
②遍歷目標(biāo),使用協(xié)程控制特效動畫的移動,使特效移動到目標(biāo)的位置,到達(dá)位置后,目標(biāo)播放受傷動作動畫并顯示扣血數(shù)值,更新角色Hp/Mp,假設(shè)角色Hp為0則播放死亡動作動畫,再讓特效移動到下一個目標(biāo)的位置,如此類推,直到最后一個目標(biāo),手動摧毀特效;
③協(xié)程完畢返回。
動畫效果如下列圖:
圖5-8魔法技能〔彈射型特效〕動畫效果
魔法技能〔發(fā)射型特效〕動畫協(xié)程
①行動者播放施法動作動畫,遍歷目標(biāo),行動者身上添加數(shù)量與目標(biāo)數(shù)一樣循環(huán)播放的特效動畫,并增加同等的動畫計數(shù);
②每個特效自身執(zhí)行協(xié)程讓自身移向?qū)?yīng)目標(biāo)的位置,到達(dá)后動畫計數(shù)減1,特效銷毀自身,目標(biāo)播放受傷動作動畫并顯示扣血數(shù)值,更新角色Hp/Mp,假設(shè)角色Hp為0則播放死亡動作動畫;
③使用while循環(huán)和yieldreturn0語句直到動畫計數(shù)為0〔即攻擊動畫、受傷動畫、特效動畫播放完〕,后跳出循環(huán);
④協(xié)程完畢返回。
動畫效果如下列圖:
圖5-9魔法技能〔發(fā)射型特效〕動畫效果
使用物品動畫協(xié)程
①行動者播放施法動作動畫,并在所有目標(biāo)身上添加并播放用于恢復(fù)的特效動畫并顯示數(shù)值,更新角色Hp/Mp;
②使用while循環(huán)和yieldreturn0語句直到動畫計數(shù)為0〔即攻擊動畫、受傷動畫、特效動畫播放完〕,后跳出循環(huán);
③協(xié)程完畢返回。
5.3.7戰(zhàn)斗動畫實現(xiàn)細(xì)述
本小節(jié)以魔法技能動畫〔彈射型特效〕的實現(xiàn)為例進展細(xì)述,以便讀者理解實現(xiàn)原理。
相關(guān)偽代碼如下:
//動畫播放協(xié)程
IEnumeratorPlayAnim()
{
while(l_AnimList不為空)//存放戰(zhàn)斗動畫類的list容器不為空
{
//沉著器中獲得頭一個戰(zhàn)斗動畫類
BATTLE_ANIMbattleAnim=l_AnimList[0];
switch(battleAnim.action_type)//判斷行動類型
{
case普通攻擊:
yieldreturnStartCoroutine(Attack(battleAnim));
break;
case使用技能:
根據(jù)battleAnim.nParam查詢數(shù)據(jù)庫技能表獲得技能動畫類型
battleAnim.nAnimType=技能動畫類型
switch(battleAnim.nAnimType)//判斷技能動畫類型
{
case攻擊技能動畫:
yieldreturnStartCoroutine(MagicAttack(battleAnim));
break;
case魔法技能動畫〔彈射型特效〕:
yieldreturnStartCoroutine(MagicBounce(battleAnim));
break;
……
}
break;
case使用物品:
yieldreturnStartCoroutine(Item(battleAnim));
break;
}
while(動畫計數(shù)器!=0)//〔一幀一次循環(huán)〕
{
//下一幀再回到這里執(zhí)行下一次循環(huán)
yieldreturn1;
}
l_AnimList.Remove(0);//去除本次播放完的戰(zhàn)斗動畫類
}
//所有動畫播放完
if(一方全體死亡)
戰(zhàn)斗完畢
else
進入下一回合,玩家下達(dá)指令
}
說明:
PlayAnim協(xié)同程序主要是遍歷存放戰(zhàn)斗動畫類的list容器,通過遍歷逐個播放戰(zhàn)斗動畫類數(shù)據(jù)所包含的動畫,通過類型的判斷,執(zhí)行不同的協(xié)同程序?qū)崿F(xiàn)不同類型動畫的播放。
//魔法技能動畫〔彈射型特效〕協(xié)程
IEnumeratorMagicBounce(BATTLE_ANIMbattleAnim)
{
行動者〔施法者〕播放施法動作動畫;
根據(jù)特效ID動態(tài)加載特效預(yù)設(shè);
由特效預(yù)設(shè)動態(tài)生成特效effect;
把effect移到到施法者的位置上;
動畫計數(shù)+1;
for(inti=0;i<battleAnim.nTargetCount;i++)//遍歷目標(biāo)
{
獲得battleAnim.nTargetInde*[i]目標(biāo)索引并根據(jù)索引獲取目標(biāo)角色
destPos=目標(biāo)角色的位置
while(effect的位置!=destPos)
{
特效的位置=Vector3.MoveTowards(特效的位置,destPos,400*Time.deltaTime);//即根據(jù)速度移向目標(biāo)位置
yieldreturn0;
}
目標(biāo)播放受傷動作動畫并顯示扣血
}
遍歷完所有目標(biāo)后,銷毀特效
動畫計數(shù)-1
}
說明:
MagicBounce協(xié)同程序主要是控制特效的移動,實現(xiàn)彈射型特效動畫的播放。
最終的動畫效果為:行動者施法,技能特效從行動者身上移向第一個目標(biāo),特效到達(dá)第一個目標(biāo)的位置后目標(biāo)受傷并扣血,特效繼續(xù)移向下一個目標(biāo),如此類推,直到最后一個目標(biāo)后,技能動畫完畢,銷毀特效,協(xié)程完畢返回到PlayAnim(),PlayAnim()繼續(xù)遍歷播放下一個動畫。
其他動畫類型與上
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- I can play the piano. 拓展(教學(xué)設(shè)計)-2023-2024學(xué)年外研版(一起)英語六年級下冊
- 粵教版(B版)三年級上冊第11課《多彩風(fēng)車園》教學(xué)設(shè)計
- Unit 1 Festivals and Celebrations Discovering Useful Structures 全英文教學(xué)設(shè)計-2023-2024學(xué)年高中英語人教版(2019)必修第三冊
- 識字2《樹之歌》教學(xué)設(shè)計-2024-2025學(xué)年統(tǒng)編版語文二年級上冊
- 第14課 網(wǎng)絡(luò)身份認(rèn)證 教學(xué)設(shè)計 2023-2024學(xué)年 浙教版(2023)信息科技八年級上冊
- 2024年字典行業(yè)市場深度分析及發(fā)展前景預(yù)測報告
- Unit 1 This is me!Welcome to the unit 教學(xué)設(shè)計 -2024-2025學(xué)年譯林版(2024)七年級上冊英語
- 第21課《北冥有魚》教學(xué)設(shè)計-2023-2024學(xué)年統(tǒng)編版語文八年級下冊
- 第二課 國家的結(jié)構(gòu)形式 教學(xué)設(shè)計-2024-2025學(xué)年高中政治統(tǒng)編版選擇性必修一當(dāng)代國際政治與經(jīng)濟
- 煙草大棚監(jiān)理質(zhì)量評估報告
- 突發(fā)公共衛(wèi)生事件衛(wèi)生應(yīng)急
- 做賬實操-農(nóng)貿(mào)市場的賬務(wù)處理示例
- 余華《活著》解讀課件
- 部編版2024-2025學(xué)年三年級上冊語文期末測試卷(含答案)
- 護理帶教老師述職報告
- 《中國居民膳食指南》課件
- 銀行柜面業(yè)務(wù)操作流程手冊
- 門窗安裝施工安全管理方案
- 婦科手術(shù)麻醉
- Unit1RelationshipsLesson2HowDoWeLikeTeachers'Feedback課件高中英語北師大版選擇性
- 庫存管理規(guī)劃
評論
0/150
提交評論