基于unity的回合制網(wǎng)游戰(zhàn)斗系統(tǒng)的研究報(bào)告及實(shí)現(xiàn)_第1頁(yè)
基于unity的回合制網(wǎng)游戰(zhàn)斗系統(tǒng)的研究報(bào)告及實(shí)現(xiàn)_第2頁(yè)
基于unity的回合制網(wǎng)游戰(zhàn)斗系統(tǒng)的研究報(bào)告及實(shí)現(xiàn)_第3頁(yè)
基于unity的回合制網(wǎng)游戰(zhàn)斗系統(tǒng)的研究報(bào)告及實(shí)現(xiàn)_第4頁(yè)
基于unity的回合制網(wǎng)游戰(zhàn)斗系統(tǒng)的研究報(bào)告及實(shí)現(xiàn)_第5頁(yè)
已閱讀5頁(yè),還剩30頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

摘要本文主要闡述網(wǎng)絡(luò)回合制戰(zhàn)斗系統(tǒng)的實(shí)現(xiàn),包括回合制戰(zhàn)斗系統(tǒng)的整個(gè)流程〔戰(zhàn)斗開(kāi)場(chǎng)、玩家下達(dá)戰(zhàn)斗指令、戰(zhàn)斗動(dòng)畫、戰(zhàn)斗完畢〕,和網(wǎng)絡(luò)回合制戰(zhàn)斗系統(tǒng)常見(jiàn)的主要功能〔攻擊、使用技能、使用物品〕的實(shí)現(xiàn),并且在游戲工程"PKer"中進(jìn)展實(shí)踐和測(cè)試。在開(kāi)發(fā)環(huán)境方面,效勞器采用國(guó)IOCP高性能開(kāi)源框架“HP-Socket〞(Windows平臺(tái)),并且連接到Mysql數(shù)據(jù)庫(kù),客戶端采用近年比擬熾熱的強(qiáng)大跨平臺(tái)引擎Unity3D〔2D,C*〕并且使用Sqlite作為嵌入式數(shù)據(jù)庫(kù)。除此以外,本文還對(duì)戰(zhàn)斗系統(tǒng)實(shí)現(xiàn)所涉及到的相關(guān)技術(shù)如Unity引擎的協(xié)同程序、單例設(shè)計(jì)模式和分包算法進(jìn)展簡(jiǎn)要介紹。

關(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回合制游戲簡(jiǎn)介

3

1.1.1廣義上的回合制游戲

3

1.1.2狹義上的回合制游戲

3

1.2回合制戰(zhàn)斗系統(tǒng)簡(jiǎn)介

3

1.3實(shí)踐工程"PKer"簡(jiǎn)介

3

第2章開(kāi)發(fā)環(huán)境和局部涉及技術(shù)簡(jiǎn)介

3

2.1開(kāi)發(fā)環(huán)境簡(jiǎn)介

3

2.2Unity協(xié)同程序

3

2.2.1Unity協(xié)同程序簡(jiǎn)介

3

2.2.2Unity協(xié)同程序的運(yùn)用

3

2.3單例設(shè)計(jì)模式

3

2.3.1單例設(shè)計(jì)模式

3

2.3.2單例設(shè)計(jì)模式的運(yùn)用

3

2.3.3單例設(shè)計(jì)模式在Unity中的運(yùn)用

3

2.4分包算法

3

2.4.1分包的原因

3

2.4.2環(huán)形緩沖區(qū)〔CircularBuffer〕

3

2.4.3分包算法流程圖

3

第3章戰(zhàn)斗動(dòng)畫實(shí)現(xiàn)方案的研究與比照

3

3.1研究背景

3

3.2實(shí)現(xiàn)方案一:有限狀態(tài)機(jī)

3

3.3實(shí)現(xiàn)方案二:協(xié)同程序(Coroutine)

3

3.4方案抉擇結(jié)論

3

第4章回合制網(wǎng)游戰(zhàn)斗系統(tǒng)設(shè)計(jì)

3

4.1回合制網(wǎng)游戰(zhàn)斗系統(tǒng)設(shè)計(jì)

3

4.2回合制網(wǎng)游戰(zhàn)斗系統(tǒng)效勞器實(shí)現(xiàn)思路

3

4.3回合制網(wǎng)游戰(zhàn)斗系統(tǒng)客戶端實(shí)現(xiàn)思路

3

4.4戰(zhàn)斗系統(tǒng)框架構(gòu)造〔以實(shí)踐工程"PKer"為例〕

3

第5章回合制戰(zhàn)斗系統(tǒng)實(shí)現(xiàn)

3

5.1戰(zhàn)斗系統(tǒng)相關(guān)消息構(gòu)造體的定義

3

5.2效勞器戰(zhàn)斗系統(tǒng)的實(shí)現(xiàn)

3

5.2.1效勞器戰(zhàn)斗系統(tǒng)相關(guān)構(gòu)造體

3

5.2.2初始化一個(gè)戰(zhàn)局

3

5.2.3接收客戶端的戰(zhàn)斗指令消息

3

5.2.4處理戰(zhàn)斗指令并發(fā)送動(dòng)畫消息

3

5.2.5說(shuō)明

3

5.3客戶端戰(zhàn)斗系統(tǒng)的實(shí)現(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進(jìn)入戰(zhàn)斗后初始化戰(zhàn)斗角色

3

5.3.4下達(dá)戰(zhàn)斗指令并發(fā)送戰(zhàn)斗指令消息

3

5.3.5接收戰(zhàn)斗動(dòng)畫消息

3

5.3.6收到戰(zhàn)斗動(dòng)畫播放消息并播放戰(zhàn)斗動(dòng)畫

3

5.3.7戰(zhàn)斗動(dòng)畫實(shí)現(xiàn)細(xì)述

3

第6章工程測(cè)試

3

6.1進(jìn)入戰(zhàn)斗測(cè)試

3

6.2普通攻擊功能測(cè)試

3

6.3使用技能功能測(cè)試

3

6.4使用物品功能測(cè)試

3

結(jié)論

3

參考文獻(xiàn)

3

3

前言

隨著網(wǎng)絡(luò)的普及與迅速開(kāi)展,網(wǎng)絡(luò)游戲已經(jīng)成為電子游戲中的主流。網(wǎng)絡(luò)游戲的戰(zhàn)斗系統(tǒng)主要可分為即時(shí)制和回合制兩種模式。即時(shí)制戰(zhàn)斗系統(tǒng)側(cè)重于刺激、反響、操作性,戰(zhàn)斗節(jié)奏快。而回合制戰(zhàn)斗系統(tǒng)側(cè)重于休閑、戰(zhàn)略、配合,戰(zhàn)斗節(jié)奏慢。早期的電子游戲由于設(shè)備硬件條件有限,大多采用回合制戰(zhàn)斗系統(tǒng)。

隨著科技的開(kāi)展和設(shè)備硬件的提升,如今回合制游戲的數(shù)量比例有所下降,但回合制游戲在國(guó)游戲市場(chǎng)依舊占據(jù)著想當(dāng)大的份額,仍有大量玩家熱衷這種戰(zhàn)斗模式,幾款眾所周知的國(guó)產(chǎn)單機(jī)游戲如"軒轅劍"系列、"仙劍奇?zhèn)b傳"系列、"古劍奇譚"系列以及國(guó)在線人數(shù)最多的MMORPG"夢(mèng)幻西游"均是采用回合制戰(zhàn)斗系統(tǒng)的游戲。

本人也是熱衷于回合制戰(zhàn)斗系統(tǒng)的玩家之一,可縱觀近年來(lái)國(guó)回合制游戲的開(kāi)展,國(guó)回合制游戲一直止步不前,"軒轅劍"系列、"仙劍奇?zhèn)b傳"系列、"古劍奇譚"銷量下降,MMORPG"夢(mèng)幻西游"也有降溫跡象,甚至國(guó)大多回合制網(wǎng)游只是復(fù)制在"夢(mèng)幻西游"或“換皮〞,缺少創(chuàng)新和突破。本人希望在研究和實(shí)現(xiàn)回合制戰(zhàn)斗系統(tǒng)的根底上,能夠找到突破和創(chuàng)新點(diǎn)。同時(shí)在游戲編程方面,即時(shí)制邏輯較為簡(jiǎn)單明了清晰,而回合制則比擬繁瑣復(fù)雜,而且在Unity引擎上實(shí)現(xiàn)回合制戰(zhàn)斗系統(tǒng)的相關(guān)資料較少。綜上原因,本人撰寫本文,希望能對(duì)志同道合者有所啟發(fā),同時(shí)也尋求學(xué)術(shù)交流。

工程將在2017年6月開(kāi)源,開(kāi)源地址s://pan.baidu./share/home"uk=1017424337

By江正覬

2016.6

第1章緒論

1.1回合制游戲簡(jiǎn)介

1.1.1廣義上的回合制游戲

凡“我方與敵方在單個(gè)回合輪流行動(dòng),只有輪到我方〔自己〕的回合或者是新的回合開(kāi)場(chǎng)時(shí),才可進(jìn)展行動(dòng)〞的游戲,都可歸類為廣義上的回合制游戲,而且絕大大多數(shù)情況下,單個(gè)回合敵我雙方行動(dòng)次數(shù)一樣。從廣義上來(lái)說(shuō),回合制游戲圍非常廣,棋牌、卡牌、戰(zhàn)棋策略、回合制戰(zhàn)斗模式都能歸為此類。

1.1.2狹義上的回合制游戲

狹義上的回合制游戲,是從廣義回合制游戲中細(xì)分,特指回合制戰(zhàn)斗模式的游戲,與即時(shí)制戰(zhàn)斗模式相對(duì)。

1.2回合制戰(zhàn)斗系統(tǒng)簡(jiǎn)介

在回合制戰(zhàn)斗模式下,每個(gè)回合開(kāi)場(chǎng)時(shí),敵我雙方各自為雙方戰(zhàn)斗角色下達(dá)戰(zhàn)斗指令,待雙方所有角色下達(dá)完戰(zhàn)斗指令或超過(guò)時(shí)限〔回合制網(wǎng)絡(luò)游戲均會(huì)設(shè)置下達(dá)戰(zhàn)斗指令的時(shí)間限制〕后雙方所有角色開(kāi)場(chǎng)行動(dòng),一般根據(jù)角色自身“速度〔敏捷〕〞的屬性數(shù)值輪流行動(dòng),期間假設(shè)果*一方符合戰(zhàn)敗條件〔*方全體陣亡或全體人物陣亡〕則戰(zhàn)斗完畢,如所有角色行動(dòng)完后敵我雙方均沒(méi)符合戰(zhàn)敗條件,則進(jìn)入下回合,如此循環(huán)。

1.3實(shí)踐工程"PKer"簡(jiǎn)介

"PKer"是一個(gè)以回合制競(jìng)技和社交為賣點(diǎn)的PC和移動(dòng)端跨平臺(tái)網(wǎng)絡(luò)游戲,是游戲與社交APP的融合體。游戲主要玩法是玩家與玩家之間的回合制戰(zhàn)斗PK。

通過(guò)移動(dòng)設(shè)備GPS定位功能〔PC端無(wú)法使用〕,能夠快速搜索在你身邊的游戲房間和玩家,與其開(kāi)展戰(zhàn)斗。

游戲提供一定數(shù)量的根底裝備和寵物讓玩家任意領(lǐng)取,故玩家可以隨時(shí)更換裝備和寵物,新玩家也能以此為根底投入到戰(zhàn)斗中。更強(qiáng)的裝備和稀有的寵物通過(guò)合成、付費(fèi)租用等渠道獲得。角色的屬性和職業(yè)也可以隨時(shí)更改,以便隨時(shí)改變戰(zhàn)術(shù)和改變?cè)陉?duì)伍里中的定位。

第2章開(kāi)發(fā)環(huán)境和局部涉及技術(shù)簡(jiǎn)介

2.1開(kāi)發(fā)環(huán)境簡(jiǎn)介

本文實(shí)踐工程的效勞器采用國(guó)IOCP開(kāi)源框架“HP-Socket〞,并且連接到Mysql數(shù)據(jù)庫(kù),客戶端采用近年比擬熾熱的強(qiáng)大跨平臺(tái)引擎Unity3D〔2D,C*〕并且使用Sqlite作為嵌入式數(shù)據(jù)庫(kù)。

2.2Unity協(xié)同程序

2.2.1Unity協(xié)同程序簡(jiǎn)介

協(xié)同程序〔Coroutine〕,通常簡(jiǎn)稱“協(xié)程〞,顧名思義,是一段協(xié)助的程序〔方法〕,很多人以為它是另開(kāi)一個(gè)線程執(zhí)行一段程序,其不然,實(shí)際上它是從主線程每幀或每隔一定時(shí)間調(diào)用的程序。當(dāng)協(xié)程創(chuàng)立后,主線程中創(chuàng)立協(xié)程的語(yǔ)句后面的代碼塊會(huì)“掛起〞,直到協(xié)同程序完畢后,才會(huì)繼續(xù)執(zhí)行創(chuàng)立協(xié)程語(yǔ)句后面的代碼。當(dāng)協(xié)程中的代碼執(zhí)行完或者使用yieldbreak語(yǔ)句時(shí),協(xié)程才會(huì)完畢,并且返回到主線程中的創(chuàng)立該協(xié)程的語(yǔ)句的位置,繼續(xù)執(zhí)行后面的代碼。協(xié)程中使用yieldreturn幀數(shù)/newWaitForSeconds(秒數(shù))語(yǔ)句可以實(shí)現(xiàn)隔多少幀或多少秒后再執(zhí)行后續(xù)代碼。另外協(xié)程可以嵌套協(xié)程,利用協(xié)程的特點(diǎn)和嵌套,可以實(shí)現(xiàn)很多復(fù)雜和有趣的功能,十分強(qiáng)大。

2.2.2Unity協(xié)同程序的運(yùn)用

協(xié)程廣泛地運(yùn)用在計(jì)時(shí)、延遲、控制物體運(yùn)動(dòng)、等待物體狀態(tài)的改變、有順序地讓物體執(zhí)行一系列動(dòng)作等方面上。

根據(jù)協(xié)程的特點(diǎn),協(xié)程中可以使用“循環(huán)+條件判斷+yieldreturn幀數(shù)/newWaitForSeconds(秒數(shù))〞實(shí)現(xiàn)每隔多少幀或者多少秒后再次執(zhí)行條件判斷語(yǔ)句,當(dāng)判斷語(yǔ)句滿足跳出循環(huán),從而讓協(xié)程代碼執(zhí)行完完畢,回到主線程繼續(xù)執(zhí)行后續(xù)代碼,利用此功能,可以很方便地實(shí)現(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)立一個(gè)協(xié)程Move,待協(xié)程Move執(zhí)行完成返回后,主線程才執(zhí)行i=0語(yǔ)句??墒菂f(xié)程Move的返回條件有點(diǎn)特殊,yieldreturn0語(yǔ)句表示協(xié)程運(yùn)行到此處掛起,等下一幀再?gòu)谋菊Z(yǔ)句繼續(xù)運(yùn)行,由于yieldreturn0在while循環(huán),所以不管yieldreturn0多少次,都依然在while循環(huán),而且while循環(huán)每一幀循環(huán)一次。直到while不滿足循環(huán)條件〔即transform.localPosition==destPos〕,則協(xié)程能夠完成使命執(zhí)行完成并返回??梢圆孪氲?,所控制的物體可能通過(guò)Update方法或者其他方法每幀在移動(dòng),直到移動(dòng)到目標(biāo)地點(diǎn),才執(zhí)行主線程后面的代碼。

2.3單例設(shè)計(jì)模式

2.3.1單例設(shè)計(jì)模式

單例設(shè)計(jì)模式是常見(jiàn)和簡(jiǎn)單的一種軟件設(shè)計(jì)模式,單例模式下的類能確保在整個(gè)工程工程中只允許存在最多一個(gè)實(shí)例對(duì)象。單例模式下的類通常不能直接通過(guò)構(gòu)造函數(shù)new出一個(gè)實(shí)例,而且構(gòu)造函數(shù)通常會(huì)設(shè)置成私有,外部不可訪問(wèn)。只有通過(guò)類的一個(gè)靜態(tài)方法可以創(chuàng)立或獲取有且只有唯一一個(gè)的對(duì)象實(shí)例。

2.3.2單例設(shè)計(jì)模式的運(yùn)用

單例設(shè)計(jì)模式下的類往往具有通用性或全局性,用于保存全局?jǐn)?shù)據(jù),需要訪問(wèn)其變量的外部類只需要通過(guò)單例類的靜態(tài)方法即可獲得其唯一的實(shí)例,從而訪問(wèn)其部變量。

例如代碼:

publicclassClientSocket//單例類ClientSocket

{

privatestaticClientSocket_client_socket;//保存本類的唯一實(shí)例

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è)實(shí)例不存在則創(chuàng)立,實(shí)例已存在則直接返回

{

_client_socket=newClientSocket();

_msg_mgr=MessageManager.getInstance();

}

return_client_socket;

}

……

}

2.3.3單例設(shè)計(jì)模式在Unity中的運(yùn)用

在Unity中使用單例設(shè)計(jì)模式,有時(shí)會(huì)有額外的意義。在Unity中,通常一個(gè)類會(huì)作為一個(gè)組件掛載到一個(gè)物體上,可是如果進(jìn)展了場(chǎng)景切換,當(dāng)前場(chǎng)景所有物體以及物體所掛載的所有組件都會(huì)被銷毀,這時(shí)如果想要所有場(chǎng)景都能訪問(wèn)一個(gè)類的實(shí)例以及其變量,則需要把該類設(shè)置成單例類,并且不能繼承MonoBehaviour,而且不能掛載到任何一個(gè)物體上,這樣就可以保證整個(gè)游戲中不管場(chǎng)景怎么切換,該類的實(shí)例一直存在,而且只有唯一一個(gè)實(shí)例,所有場(chǎng)景均可通過(guò)靜態(tài)方法獲取實(shí)例并且訪問(wèn)。

2.4分包算法

2.4.1分包的原因

TCP在發(fā)送消息時(shí),如果發(fā)送間隔太短,發(fā)送方有可能出現(xiàn)一次發(fā)送多個(gè)消息的情況,而接收方便會(huì)一次接收到多個(gè)消息,另外,很多時(shí)候網(wǎng)絡(luò)情況較差或不穩(wěn)定,接收方遲遲收不到消息,過(guò)一段時(shí)間有可能一次過(guò)接收到此前該接收的多個(gè)消息,這些現(xiàn)象就是粘包。

由于粘包現(xiàn)象的存在,如果不進(jìn)展分包,接收方可能只能讀取到粘包數(shù)據(jù)的頭一個(gè)消息,后面的消息將會(huì)喪失,甚至影響后續(xù)接收的消息,嚴(yán)重影響程序的運(yùn)行。因此,我們需要一個(gè)分包算法來(lái)檢測(cè)粘包情況并進(jìn)展分包,以便正確讀取所有來(lái)自發(fā)送方的消息。

2.4.2環(huán)形緩沖區(qū)〔CircularBuffer〕

在分包算法中,我們需要用到一個(gè)數(shù)據(jù)構(gòu)造——環(huán)形緩沖區(qū)。之所以要用到環(huán)形緩沖區(qū),是因?yàn)榉职拔覀円呀邮盏降乃袛?shù)據(jù)存放在一個(gè)緩沖區(qū)中,分包時(shí)根據(jù)消息的長(zhǎng)度從緩沖區(qū)里取數(shù)據(jù),取出后緩沖區(qū)相應(yīng)地移除對(duì)應(yīng)的數(shù)據(jù),這樣反復(fù)頻繁進(jìn)展添加和刪除操作如果只用普通的緩沖區(qū)(byte數(shù)組/char數(shù)組)的話,則要頻繁地移動(dòng)數(shù)據(jù)存放的位置,十分影響程序運(yùn)行效率,為此需要引入環(huán)形緩沖區(qū)。

下面是環(huán)形緩沖區(qū)〔CricularBuffer〕類的UML類圖〔C++〕:

圖2-1環(huán)形緩沖區(qū)UML類圖

說(shuō)明:

buf:指向緩沖區(qū)的指針

front:緩沖區(qū)的數(shù)據(jù)的起始位置

rear:緩沖區(qū)的數(shù)據(jù)的尾部位置

lock:用于多線程同步的臨界區(qū),防止多個(gè)線程訪問(wèn)修改緩沖區(qū)數(shù)據(jù)

size:緩沖區(qū)數(shù)據(jù)的長(zhǎng)度

capacity:緩沖區(qū)的容量

CircularBuffer:構(gòu)造函數(shù),創(chuàng)立一個(gè)指定容量為參數(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ù)不需要移動(dòng)數(shù)據(jù)的儲(chǔ)存位置,運(yùn)行效率高。

2.4.3分包算法流程圖

圖2-2分包算法流程圖

說(shuō)明:

定義或獲得一個(gè)容量足夠大的環(huán)形緩沖區(qū)〔具體大小請(qǐng)根據(jù)實(shí)際情況考慮〕;

接收到數(shù)據(jù)后,往環(huán)形緩沖區(qū)尾部添加數(shù)據(jù);

判斷緩沖區(qū)的數(shù)據(jù)長(zhǎng)度是否大于等于4〔消息頭的長(zhǎng)度〕,本文實(shí)踐工程的構(gòu)造體消息頭由消息類型〔ushort〕和消息長(zhǎng)度〔ushort〕組成,共4字節(jié)。假設(shè)緩沖區(qū)數(shù)據(jù)長(zhǎng)度小于消息頭長(zhǎng)度,則無(wú)法獲取第一條消息的長(zhǎng)度,也無(wú)法分包,也說(shuō)明數(shù)據(jù)接收不全,回到〔2〕繼續(xù)接收數(shù)據(jù),不進(jìn)展任何操作;假設(shè)緩沖區(qū)數(shù)據(jù)長(zhǎng)度大于等于消息頭長(zhǎng)度,則開(kāi)場(chǎng)進(jìn)展分包;

從緩沖區(qū)頭部getBuf獲得4字節(jié)數(shù)據(jù)〔消息頭〕,不改變緩沖區(qū)數(shù)據(jù),從消息頭得到第一包消息的長(zhǎng)度;

判斷緩沖區(qū)數(shù)據(jù)長(zhǎng)度,假設(shè)緩沖區(qū)數(shù)據(jù)長(zhǎng)度大于第一包消息的長(zhǎng)度,則第一包消息接收完并可取,根據(jù)第一包消息的長(zhǎng)度popBuf得到第一包消息數(shù)據(jù),并且緩沖區(qū)移除相應(yīng)數(shù)據(jù),處理該消息;假設(shè)緩沖區(qū)數(shù)據(jù)長(zhǎng)度小于第一包消息長(zhǎng)度〔此時(shí)緩沖區(qū)數(shù)據(jù)長(zhǎng)度大于等于4,但是小于第一包消息的長(zhǎng)度〕,則說(shuō)明第一包消息還沒(méi)接收完,回到〔2〕繼續(xù)接收,不進(jìn)展任何操作;

回到〔4〕,一直循環(huán)。

第3章戰(zhàn)斗動(dòng)畫實(shí)現(xiàn)方案的研究與比照

3.1研究背景

筆者認(rèn)為回合制戰(zhàn)斗系統(tǒng)實(shí)現(xiàn)的最大難點(diǎn),那無(wú)疑就是客戶端戰(zhàn)斗動(dòng)畫的實(shí)現(xiàn)?;睾现茟?zhàn)斗系統(tǒng)的戰(zhàn)斗動(dòng)畫,不是平常我們說(shuō)的“動(dòng)畫〞,它是由數(shù)據(jù)轉(zhuǎn)換過(guò)來(lái)的動(dòng)態(tài)動(dòng)畫,動(dòng)畫容由數(shù)據(jù)決定。例如動(dòng)畫數(shù)據(jù)是“*個(gè)角色攻擊*個(gè)角色〞,動(dòng)畫容便是“攻擊者移動(dòng)到目標(biāo)面前并播放攻擊動(dòng)作動(dòng)畫,目標(biāo)播放受傷動(dòng)作動(dòng)畫,顯示扣血,攻擊者返回到本來(lái)的位置〞;再例如動(dòng)畫數(shù)據(jù)是“*個(gè)角色使用技能攻擊*個(gè)角色〞,動(dòng)畫容便是“施法者播放施法動(dòng)作動(dòng)畫,然后在目標(biāo)身上播放技能特效,等到特效播放到*一幀,目標(biāo)播放受傷動(dòng)作動(dòng)畫,顯示扣血〞。

上述例子已經(jīng)是回合制戰(zhàn)斗系統(tǒng)最根本的戰(zhàn)斗動(dòng)畫,更不用說(shuō)屢次攻擊或者屢次施法,可謂難上加難。更何況,戰(zhàn)斗動(dòng)畫的質(zhì)量極大影響回合制游戲的可玩性,而且回合制戰(zhàn)斗除了玩家下達(dá)戰(zhàn)斗指令外,其余時(shí)間全部都在播放戰(zhàn)斗動(dòng)畫上。

所以,筆者認(rèn)為客戶端的戰(zhàn)斗動(dòng)畫實(shí)現(xiàn)是整個(gè)回合制戰(zhàn)斗系統(tǒng)的重點(diǎn)和難點(diǎn),為了正確慎重地抉擇實(shí)現(xiàn)方案,少走彎路,額外對(duì)戰(zhàn)斗動(dòng)畫的實(shí)現(xiàn)展開(kāi)了研究。

3.2實(shí)現(xiàn)方案一:有限狀態(tài)機(jī)

這是筆者最先想到的方案,畢竟有限狀態(tài)機(jī)在游戲編程中實(shí)在極為常用,相信不少讀者也會(huì)率先聯(lián)想到這種方式。

有限狀態(tài)機(jī)代碼例如:

voidUpdate(){

switch(state)

{

case(int)State.Standby:

……

break;

case(int)State.Attack:

……

break;

case(int)State.Magic:

……

break;

……

}

……

}

有限狀態(tài)機(jī)方案下,Update方法每幀檢測(cè)記錄狀態(tài)的變量state,從而決定終究要執(zhí)行何種行為,當(dāng)行為執(zhí)行完或者*個(gè)事件觸發(fā)時(shí),通過(guò)修改狀態(tài)變量state,改變執(zhí)行的行為。

優(yōu)點(diǎn):

(1)靈活可變,隨時(shí)隨地都可以改變狀態(tài),從而改變執(zhí)行的行為

缺點(diǎn):

每幀都需要檢測(cè)狀態(tài)變量,影響程序運(yùn)行效率;

如果要實(shí)現(xiàn)一系列復(fù)雜的行為,代碼量大而且凌亂,邏輯復(fù)雜,例如要實(shí)現(xiàn)“攻擊者移動(dòng)到目標(biāo)面前,攻擊者播放攻擊動(dòng)畫,目標(biāo)播放受傷動(dòng)畫,顯示扣血,攻擊者返回原本位置〞這樣的功能,可能需要不止一個(gè)狀態(tài)機(jī);

Update方法變得臃腫,很多時(shí)候Update還需要做其他事情;

3.3實(shí)現(xiàn)方案二:協(xié)同程序(Coroutine)

在感覺(jué)方案一可行性不高的情況下,本人開(kāi)場(chǎng)尋求其他實(shí)現(xiàn)方案,直到發(fā)現(xiàn)協(xié)同程序(Coroutine)。假設(shè)讀者不了解協(xié)程可閱本文第二章,協(xié)同程序在本文第2章有簡(jiǎn)單介紹,此處不再作介紹。個(gè)人感覺(jué)Unity的協(xié)同程序跟Cocos2d的CCSequence動(dòng)作有點(diǎn)像,都能很方便實(shí)現(xiàn)按順序執(zhí)行一系列動(dòng)作,而且協(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()能夠簡(jiǎn)單清晰實(shí)現(xiàn)“控制*個(gè)物體移動(dòng)到*個(gè)地點(diǎn),完成后進(jìn)展攻擊,攻擊完成后返回到*個(gè)地點(diǎn)〞,一步完成之后再進(jìn)展下一步。

優(yōu)點(diǎn):

不需要在Update每幀調(diào)用,協(xié)程開(kāi)啟后根據(jù)代碼邏輯等待〔每〕n幀/n秒自動(dòng)調(diào)用;

代碼邏輯清晰

能夠很好實(shí)現(xiàn)按順序執(zhí)行一系列復(fù)雜的行為

缺點(diǎn):

如要中途終止協(xié)程,有一定的終止條件

沒(méi)狀態(tài)機(jī)靈活,難以臨時(shí)轉(zhuǎn)變行為

3.4方案抉擇結(jié)論

顯而易見(jiàn),經(jīng)過(guò)筆者的研究和深思熟慮,本文采用了協(xié)同程序方案。理由很簡(jiǎn)單,回合制戰(zhàn)斗動(dòng)畫幾乎全避開(kāi)了協(xié)程的缺點(diǎn),表達(dá)了協(xié)程的優(yōu)點(diǎn)。因?yàn)榛睾现茟?zhàn)斗動(dòng)畫是由效勞器發(fā)來(lái)的動(dòng)畫數(shù)據(jù)轉(zhuǎn)換的,數(shù)據(jù)自始至終沒(méi)有改變,客戶端只負(fù)責(zé)播放動(dòng)畫效果,并沒(méi)有修改數(shù)據(jù),則從數(shù)據(jù)轉(zhuǎn)化為動(dòng)畫那刻開(kāi)場(chǎng),動(dòng)畫就不可能有變化或者中途終止,并不需要程序的靈活性。這么看來(lái),協(xié)程用在回合制戰(zhàn)斗動(dòng)畫的播放很是適合。

另外,讀者也可考慮行為樹(shù)方案,由于筆者時(shí)間和能力有限,截至目前未能深入學(xué)習(xí)研究行為樹(shù),不知是否能比協(xié)程更好地實(shí)現(xiàn)戰(zhàn)斗動(dòng)畫,所以本文未能提及,懇請(qǐng)?bào)w諒。

第4章回合制網(wǎng)游戰(zhàn)斗系統(tǒng)設(shè)計(jì)

4.1回合制網(wǎng)游戰(zhàn)斗系統(tǒng)設(shè)計(jì)

我們從回合制網(wǎng)游中不難發(fā)現(xiàn),在客戶端面前,我們可以看到一場(chǎng)回合制戰(zhàn)斗可劃分為以下階段:進(jìn)入戰(zhàn)斗-玩家下達(dá)戰(zhàn)斗指令〔很多情況下需要下達(dá)人物和寵物兩個(gè)戰(zhàn)斗指令〕-戰(zhàn)斗動(dòng)畫-戰(zhàn)斗完畢。經(jīng)過(guò)本人對(duì)上述戰(zhàn)斗過(guò)程的研究、思考和分析,得出個(gè)人的回合制戰(zhàn)斗系統(tǒng)實(shí)現(xiàn)思路,戰(zhàn)斗系統(tǒng)流程圖如圖:

圖4-1回合制網(wǎng)游戰(zhàn)斗系統(tǒng)流程圖

4.2回合制網(wǎng)游戰(zhàn)斗系統(tǒng)效勞器實(shí)現(xiàn)思路

〔1〕戰(zhàn)斗開(kāi)場(chǎng)發(fā)送“戰(zhàn)斗初始化消息〞給客戶端,“戰(zhàn)斗初始化消息〞包含所有戰(zhàn)斗角色〔人物和寵物〕的名字、圖形及動(dòng)畫控制器ID、最大Hp、當(dāng)前Hp、最大Mp、當(dāng)前Mp等數(shù)據(jù),客戶端只關(guān)心需要顯示的容;

〔2〕根據(jù)戰(zhàn)斗角色的數(shù)量,等待接收并保存數(shù)量與角色數(shù)量想當(dāng)?shù)膩?lái)自客戶端的“戰(zhàn)斗指令消息〞,即等待所有戰(zhàn)斗角色都下達(dá)完戰(zhàn)斗指令;

〔3〕接收到足夠數(shù)量的“角色戰(zhàn)斗指令消息〞后,根據(jù)角色的“速度〞屬性數(shù)值,倒序〔即速度高者先行動(dòng)〕處理每一個(gè)戰(zhàn)斗指令所造成的影響,并更新效勞器各個(gè)角色的數(shù)值,發(fā)送對(duì)應(yīng)的“動(dòng)畫消息〞給所有客戶端,每處理一個(gè)“戰(zhàn)斗指令消息〞就發(fā)送一個(gè)對(duì)應(yīng)的“動(dòng)畫消息〞;

〔4〕待所有“戰(zhàn)斗指令消息〞處理完并發(fā)送完對(duì)應(yīng)的“動(dòng)畫消息〞后,發(fā)送“動(dòng)畫播放消息〞;

〔5〕判斷雙方角色的陣亡情況,假設(shè)一方符合戰(zhàn)敗條件〔所有角色陣亡或者所有人物陣亡,具體根據(jù)游戲設(shè)定決定〕則完畢戰(zhàn)斗,否則回到步驟〔2〕進(jìn)入下一個(gè)回合,如此循環(huán)。

4.3回合制網(wǎng)游戰(zhàn)斗系統(tǒng)客戶端實(shí)現(xiàn)思路

〔1〕假設(shè)接收到“戰(zhàn)斗初始化消息〞,則進(jìn)入戰(zhàn)斗,并根據(jù)消息里的數(shù)據(jù),初始化每一個(gè)戰(zhàn)斗角色;

〔2〕顯示人物戰(zhàn)斗指令菜單,根據(jù)玩家的操作,發(fā)送“戰(zhàn)斗指令消息〞,人物戰(zhàn)斗指令菜單消失;

〔3〕假設(shè)沒(méi)有參戰(zhàn)寵物,直接跳到下一步,假設(shè)有參戰(zhàn)寵物,顯示寵物戰(zhàn)斗指令菜單,根據(jù)玩家的操作,發(fā)送“戰(zhàn)斗指令消息〞,寵物戰(zhàn)斗指令菜單消失;

〔4〕接收并保存每一個(gè)來(lái)自效勞器的“動(dòng)畫消息〞或“動(dòng)畫播放消息〞;

〔5〕收到“動(dòng)畫播放消息〞后,讀取并處理每一個(gè)“動(dòng)畫消息〞,轉(zhuǎn)化為對(duì)應(yīng)等量的戰(zhàn)斗動(dòng)畫類并用容器保存,遍歷容器播放所有動(dòng)畫;

〔6〕當(dāng)前回合所有戰(zhàn)斗動(dòng)畫播放完后,判斷雙方陣亡情況,假設(shè)一方符合戰(zhàn)敗條件〔所有角色陣亡或者所有人物陣亡,具體根據(jù)游戲設(shè)定決定〕則完畢戰(zhàn)斗,否則回到步驟〔2〕進(jìn)入下一個(gè)回合,如此循環(huán)。

4.4戰(zhàn)斗系統(tǒng)框架構(gòu)造〔以實(shí)踐工程"PKer"為例〕

雖然本文主要闡述戰(zhàn)斗系統(tǒng),但是由于戰(zhàn)斗系統(tǒng)較為復(fù)雜,為了讓讀者更好的理解本文所述戰(zhàn)斗系統(tǒng)的實(shí)現(xiàn)思路,以實(shí)踐工程"PKer"為例,對(duì)游戲的戰(zhàn)斗系統(tǒng)架構(gòu)和相關(guān)功能架構(gòu)進(jìn)展簡(jiǎn)單的羅列和說(shuō)明。

圖4-2實(shí)踐工程"PKer"戰(zhàn)斗系統(tǒng)及相關(guān)功能架構(gòu)

說(shuō)明:

玩家從游戲大廳可以搜索參加房間或創(chuàng)立房間,與房間其他玩家進(jìn)展對(duì)戰(zhàn)進(jìn)入戰(zhàn)斗〔讀者可根據(jù)自身游戲玩法考慮如何觸發(fā)戰(zhàn)斗,如常見(jiàn)的回合制游戲通過(guò)暗雷或明雷遇敵、玩家對(duì)點(diǎn)觸發(fā)戰(zhàn)斗〕;

"PKer"中玩家可以直接在玩家屬性配置界面過(guò)點(diǎn)選“寵物庫(kù)〞的寵物即可獲得對(duì)應(yīng)寵物,并且通過(guò)設(shè)置“參戰(zhàn)寵物〞可讓寵物在戰(zhàn)斗中出戰(zhàn)〔讀者可根據(jù)自身游戲玩法考慮寵物的獲得途徑,常見(jiàn)的途徑有戰(zhàn)斗捕捉、任務(wù)獎(jiǎng)勵(lì)等〕;

"PKer"中玩家可以直接在玩家屬性配置界面過(guò)點(diǎn)選“裝備物品庫(kù)〞的裝備/物品即可獲得對(duì)應(yīng)裝備/物品,裝上裝備將提高角色的屬性使角色更具戰(zhàn)斗力,放在物品欄的物品可以在戰(zhàn)斗中使用回復(fù)Hp/Mp〔讀者可根據(jù)自身游戲玩法考慮裝備物品的獲得途徑,常見(jiàn)的途徑有戰(zhàn)斗獎(jiǎng)勵(lì)、任務(wù)獎(jiǎng)勵(lì)等〕;

"PKer"中玩家可以直接在玩家屬性配置界面中更改職業(yè),從而獲得在戰(zhàn)斗中使用的技能;

進(jìn)入戰(zhàn)斗后,參戰(zhàn)角色的屬性由各個(gè)玩家配置〔屬性加點(diǎn)、裝備、參戰(zhàn)寵物、職業(yè)等〕所決定;

各玩家通過(guò)指令菜單下達(dá)指令從而控制自身角色和自身參戰(zhàn)寵物〔如有設(shè)置參戰(zhàn)寵物〕的行動(dòng)。其中,使用技能能夠選擇使用自身職業(yè)的技能,使用物品能夠選擇使用物品欄的物品;

戰(zhàn)斗動(dòng)畫主要由多個(gè)協(xié)同程序組成來(lái)實(shí)現(xiàn),根據(jù)各個(gè)參戰(zhàn)人物/寵物的下達(dá)的戰(zhàn)斗指令對(duì)應(yīng)的播放其行為的動(dòng)畫,不同的行為動(dòng)畫容不一樣;

而在技能動(dòng)畫中,為了增加回合制戰(zhàn)斗的畫面感和可玩性,對(duì)不同的技能配置了不同的特效播放方式,讓特效動(dòng)畫更華美更多元化,詳細(xì)實(shí)現(xiàn)方式在本文和小節(jié)有闡述;

第5章回合制戰(zhàn)斗系統(tǒng)實(shí)現(xiàn)

5.1戰(zhàn)斗系統(tǒng)相關(guān)消息構(gòu)造體的定義

構(gòu)造體消息是效勞器與客戶端溝通的“共同語(yǔ)言〞,構(gòu)造體消息在客戶端和效勞器分別定義并且數(shù)據(jù)構(gòu)造是一樣,發(fā)送方填寫構(gòu)造體數(shù)據(jù),接收方先獲取消息頭的消息類型ID和長(zhǎng)度,再判斷是哪種類型的消息并轉(zhuǎn)換成該類型構(gòu)造體,然后讀取容并進(jìn)展對(duì)應(yīng)的處理。

以下是Unity客戶端〔C*〕中定義的相關(guān)構(gòu)造體消息,效勞器的定義與其一致,但由于效勞器〔C++〕與客戶端〔C*〕的編程語(yǔ)言不同所以定義語(yǔ)法有些許區(qū)別。

//戰(zhàn)斗初始化消息

publicstructMSG_BATTLE_INIT

{

publicushortnMsgID;//消息類型ID

publicushortnLen;//構(gòu)造體長(zhǎng)度

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)斗成員,可能還會(huì)用來(lái)標(biāo)識(shí)自身和自身寵物〕

[MarshalAs(UnmanagedType.ByValArray,SizeConst=22)]

publicbyte[]strName;//戰(zhàn)斗人物/寵物名字

publicuintnImageID;//圖形及動(dòng)畫控制器ID

publicshortnHpMa*;//最大HP

publicshortnHp;//當(dāng)前HP

publicshortnMpMa*;//最大MP

publicshortnMp;//當(dāng)前MP

};

//戰(zhàn)斗指令消息

publicstructMSG_BATTLE_MAND

{

publicushortnMsgID;//消息類型ID

publicushortnLen;//構(gòu)造體長(zhǎng)度

publicushortnActorType;//行動(dòng)者類型〔1=人物2=寵物,由效勞端賦值,客戶端不需要賦值〕

publicushortnActorInde*;//行動(dòng)者索引〔由效勞端賦值,客戶端不需要賦值〕

publicushortnActionType;//行動(dòng)的類型

publicushortnTargetInde*;//目標(biāo)索引

publicushortnParam;//參數(shù)〔根據(jù)行動(dòng)類型而定,如使用技能則是技能ID,使用物品則是物品欄位置,切換戰(zhàn)寵則是寵物欄位置〕

};

//戰(zhàn)斗動(dòng)畫播放消息〔客戶端收到此消息后開(kāi)場(chǎng)播放戰(zhàn)斗動(dòng)畫〕

publicstructMSG_BATTLE_ANIM_BEGIN

{

publicushortnMsgID;//消息類型ID

publicushortnLen;//構(gòu)造體長(zhǎng)度

};

//戰(zhàn)斗動(dòng)畫消息

publicstructMSG_BATTLE_ANIM

{

publicushortnMsgID;//消息類型ID

publicushortnLen;//構(gòu)造體長(zhǎng)度

publicushortnActorInde*;//行動(dòng)者索引

[MarshalAs(UnmanagedType.ByValArray,SizeConst=10)]

publicushort[]nTargetInde*;//目標(biāo)索引〔初始值為0,0則無(wú)目標(biāo)〕

publicushortaction_type;//行動(dòng)類型

publicushortnParam;//參數(shù)〔根據(jù)行動(dòng)類型而定,如使用技能則是技能ID,使用物品則是物品欄位置〕

[MarshalAs(UnmanagedType.ByValArray,SizeConst=10)]

publicshort[]nActorHp;//行動(dòng)者Hp影響〔<0:扣血,>0:加血,0=無(wú)任何影響〕

[MarshalAs(UnmanagedType.ByValArray,SizeConst=10)]

publicshort[]nActorMp;//行動(dòng)者M(jìn)p影響

[MarshalAs(UnmanagedType.ByValArray,SizeConst=10)]

publicshort[]nTargetHp;//目標(biāo)Hp影響〔<0:扣血,>0:加血,0=無(wú)任何影響〕

[MarshalAs(UnmanagedType.ByValArray,SizeConst=10)]

publicshort[]nTargetMp;//目標(biāo)Mp影響

};

5.2效勞器戰(zhàn)斗系統(tǒng)的實(shí)現(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*;//隊(duì)伍1存活者索引list

std::list<USHORT>team2_survivors_inde*;//隊(duì)伍2存活者索引list

USHORTnSpriteTotal;//參戰(zhàn)角色總數(shù)

std::multimap<float,MSG_BATTLE_MAND*>m_mandMap;//玩家戰(zhàn)斗指令字典,用于保存每回合接收的戰(zhàn)斗指令消息,Key為角色速度數(shù)值

}

說(shuō)明:

battleSprites數(shù)組的索引0-4位置分別為隊(duì)伍1人物1、隊(duì)伍1人物2……,索引5-9位置分別為隊(duì)伍1人物1的寵物、隊(duì)伍1人物2的寵物……,類似的,索引10-14為隊(duì)伍2人物,索引15-19為隊(duì)伍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ù),本文不闡述,請(qǐng)讀者根據(jù)自身游戲效勞器架構(gòu)設(shè)計(jì)〕

USHORTnType;//角色類型,1=人,2=寵物

USHORTbmand;//是否已經(jīng)下命令,0=沒(méi)下命令,1=已下命令

}

//戰(zhàn)斗數(shù)據(jù)(人物與寵物通用)

structBATTLE_SPRITE_DATA

{

UINTnID;//玩家/寵物ID

charstrName[22];//戰(zhàn)斗人物/寵物名字

UINTnImageID;//圖形及動(dòng)畫控制器ID

USHORTnLevel;//等級(jí)

shortnHpMa*;//最大Hp

shortnHp;//當(dāng)前Hp

shortnMpMa*;//最大Mp

shortnMp;//當(dāng)前Mp

shortnAtk;//物理攻擊力

shortnDef;//物理防御力

shortnMat;//魔法攻擊力

shortnMdf;//魔法防御力

shortnSpd;//速度

}

5.2.2初始化一個(gè)戰(zhàn)局

即初始化一個(gè)戰(zhàn)局BATTLE實(shí)例,并根據(jù)參戰(zhàn)玩家的數(shù)據(jù)對(duì)戰(zhàn)局所有成員進(jìn)展賦值,由于成員較多,并且游戲邏輯復(fù)雜,讀者可根據(jù)自身游戲邏輯賦值,此處初始化的方式不影響后續(xù)的實(shí)現(xiàn),所以這里不進(jìn)展詳細(xì)闡述,最后在客戶端數(shù)據(jù)存放指向戰(zhàn)局的指針,以便后面通過(guò)完成鍵以及客戶端數(shù)據(jù)能夠獲得戰(zhàn)局?jǐn)?shù)據(jù)。

本文假設(shè)一個(gè)戰(zhàn)局最多能5位玩家對(duì)戰(zhàn)5位玩家,包括每位玩家可出戰(zhàn)的一個(gè)戰(zhàn)斗寵物,所以一個(gè)戰(zhàn)局最多能有20個(gè)戰(zhàn)斗角色,故battleSprites戰(zhàn)斗角色數(shù)組長(zhǎng)度為20,讀者可根據(jù)自身游戲邏輯進(jìn)展變更。另外,如果戰(zhàn)局缺乏20個(gè)戰(zhàn)斗角色,本文通過(guò)檢查battleSprites中的戰(zhàn)斗數(shù)據(jù)pBattleData是否為NULL進(jìn)展判斷并計(jì)數(shù),用成員nSpriteTotal保存戰(zhàn)斗角色總數(shù)。戰(zhàn)局初始時(shí)所有戰(zhàn)斗角色理應(yīng)是存活的,battleSprites中所有存在的戰(zhàn)斗角色的索引相應(yīng)的存放到隊(duì)伍1存活索引list或隊(duì)伍2存活索引list中,本文假設(shè)索引0-9為隊(duì)伍1〔0-4隊(duì)伍1人物,5-9隊(duì)伍1寵物〕,10-19為隊(duì)伍2〔10-14為隊(duì)伍2人物,15-19為隊(duì)伍2寵物〕,并且人物和其寵物的索引相差5〔即0索引上的人物其寵物索引為5,如此類推〕。

5.2.3接收客戶端的戰(zhàn)斗指令消息

圖5-2接收戰(zhàn)斗指令消息流程圖

收到客戶端發(fā)來(lái)的消息后,通過(guò)消息頭和消息類型ID〔可用宏定義或定義枚舉類型〕的判斷,確定是否為戰(zhàn)斗指令消息后,然后處理戰(zhàn)斗指令消息。

本文實(shí)踐工程從IOCP完成鍵可以獲取玩家數(shù)據(jù)進(jìn)而獲取玩家所在的戰(zhàn)局指針〔BATTLE*〕。收到戰(zhàn)斗指令消息后,通過(guò)消息中的行動(dòng)者索引nActorInde*從戰(zhàn)局的戰(zhàn)斗角色battleSprites數(shù)組中獲取該角色,根據(jù)該角色的“速度〞數(shù)值和戰(zhàn)斗指令消息一并參加到戰(zhàn)斗指令字典m_mandMap中,以便之后遍歷逐個(gè)處理。檢測(cè)m_mandMap的元素個(gè)數(shù)是否等于戰(zhàn)斗角色總數(shù)〔即檢測(cè)是否所有戰(zhàn)斗角色都已下達(dá)戰(zhàn)斗指令,假設(shè)等于則開(kāi)場(chǎng)遍歷m_mandMap處理本回合的所有戰(zhàn)斗指令。

5.2.4處理戰(zhàn)斗指令并發(fā)送動(dòng)畫消息

圖5-3效勞器處理戰(zhàn)斗指令消息流程圖

當(dāng)本回合所有戰(zhàn)斗角色都下達(dá)戰(zhàn)斗指令〔效勞器收到的指令數(shù)等于角色數(shù)量〕后,開(kāi)場(chǎng)倒序遍歷〔倒序的原因是,multimap按從小到大排序,而我們的邏輯是速度高的先行動(dòng)〕處理每一條戰(zhàn)斗指令。

倒序遍歷時(shí),先判斷發(fā)出該戰(zhàn)斗指令消息的角色是否已經(jīng)死亡,假設(shè)死亡則不能進(jìn)展任何行為,直接跳出進(jìn)入下一次循環(huán)。假設(shè)發(fā)出指令的角色沒(méi)有死亡,根據(jù)指令的nActionType行動(dòng)類型〔攻擊、使用技能、使用物品、更換寵物等〕進(jìn)展不同的處理,計(jì)算每一條戰(zhàn)斗指令所造成的影響,并發(fā)送對(duì)應(yīng)的動(dòng)畫消息。

假設(shè)在計(jì)算完每一條戰(zhàn)斗指令所造成的影響后,檢查雙方存活狀況,假設(shè)一方全員陣亡則戰(zhàn)斗完畢,并發(fā)送戰(zhàn)斗動(dòng)畫播放消息,客戶端開(kāi)場(chǎng)播放動(dòng)畫。

假設(shè)計(jì)算完所有戰(zhàn)斗指令后戰(zhàn)斗并沒(méi)有完畢,發(fā)送戰(zhàn)斗動(dòng)畫播放消息,客戶端開(kāi)場(chǎng)播放動(dòng)畫,進(jìn)入下一回合,清空m_mandMap所有元素,效勞器繼續(xù)接收新回合的來(lái)自客戶端的戰(zhàn)斗指令消息。

下面是不同的行動(dòng)類型的不同處理方式:

攻擊:

聲明一個(gè)戰(zhàn)斗動(dòng)畫消息,nActionType賦值為“攻擊〔枚舉或自定義宏〕〞,根據(jù)戰(zhàn)斗指令消息里的nActorInde*行動(dòng)者索引和nTargetInde*目標(biāo)索引從戰(zhàn)局中獲取對(duì)應(yīng)的戰(zhàn)斗角色〔battleSprites[nActorInde*]和battleSprites[nTargetInde*]〕,假設(shè)目標(biāo)死亡則從對(duì)應(yīng)隊(duì)伍的存活者列表中隨機(jī)一個(gè)新目標(biāo)索引。把目標(biāo)索引值賦值給戰(zhàn)斗動(dòng)畫消息的nTargetInde*[0]。

根據(jù)行動(dòng)者攻擊和目標(biāo)防御力計(jì)算傷害值,賦值給nTargetHp[0],并且目標(biāo)扣除對(duì)應(yīng)Hp,判斷目標(biāo)扣除Hp后Hp是否小于等于0〔即死亡〕,假設(shè)死亡則從對(duì)應(yīng)隊(duì)伍的存活者列表中移除。

最后,發(fā)送戰(zhàn)斗動(dòng)畫消息給戰(zhàn)局所有玩家。

使用技能:

本文的實(shí)踐工程通過(guò)數(shù)據(jù)庫(kù)配置所有技能的相關(guān)數(shù)據(jù),包括技能的ID、作用目標(biāo)數(shù)量、特效動(dòng)畫ID、特效播放方式〔僅在客戶端使用〕、Mp消耗、傷害公式等。

聲明一個(gè)戰(zhàn)斗動(dòng)畫消息,nActionType賦值為“使用技能〔枚舉或自定義宏〕〞,通過(guò)戰(zhàn)斗指令消息的nParam查找數(shù)據(jù)庫(kù)的技能表獲取該技能的相關(guān)數(shù)據(jù),根據(jù)戰(zhàn)斗指令消息的nActorInde*和nTargetInde*從戰(zhàn)局獲得對(duì)應(yīng)的角色battleSprites[nActorInde*]和battleSprites[nTargetInde*]〕,根據(jù)技能Mp消耗數(shù)值賦值到動(dòng)畫消息的nActorMp上,并且減少使用者角色的Mp。如果目標(biāo)角色死亡,則從目標(biāo)角色的隊(duì)伍存活者列表中隨機(jī)得到新的目標(biāo)索引,并賦值多體戰(zhàn)斗動(dòng)畫消息nTargetInde*數(shù)組的對(duì)應(yīng)索引位置上,再根據(jù)行動(dòng)者的魔法攻擊力和目標(biāo)的魔法防御力以及技能的傷害公式計(jì)算傷害數(shù)值,賦值nTargetHp數(shù)組對(duì)應(yīng)的索引位置上,并且目標(biāo)扣除對(duì)應(yīng)Hp,判斷目標(biāo)扣除Hp后Hp是否小于等于0〔即死亡〕,假設(shè)死亡則從對(duì)應(yīng)隊(duì)伍的存活者列表中移除。之后再隨機(jī)目標(biāo),并計(jì)算傷害數(shù)值,直到目標(biāo)數(shù)量到達(dá)技能的作用目標(biāo)數(shù)量。

最后,發(fā)送戰(zhàn)斗動(dòng)畫消息給戰(zhàn)局所有玩家。

使用物品:

本文的實(shí)踐工程通過(guò)數(shù)據(jù)庫(kù)配置所有物品的相關(guān)數(shù)據(jù),包括物品的ID、作用于單體/全體、Hp回復(fù)量、Mp回復(fù)量等。

聲明一個(gè)戰(zhàn)斗動(dòng)畫消息,nActionType賦值為“使用物品〔枚舉或自定義宏〕〞,通過(guò)戰(zhàn)斗指令消息的nParam獲取玩家對(duì)應(yīng)物品欄位置的物品ID〔物品欄的實(shí)現(xiàn)本文不闡述〕,把物品ID賦值給戰(zhàn)斗動(dòng)畫消息的nParam,根據(jù)物品ID查找數(shù)據(jù)庫(kù)的物品表獲取該物品的相關(guān)數(shù)據(jù),根據(jù)戰(zhàn)斗指令消息的nActorInde*賦值給動(dòng)畫消息的nActorInde*,根據(jù)物品是作用于單體還是全體對(duì)動(dòng)畫消息的nTargetInde*數(shù)組進(jìn)展賦值,根據(jù)物品的Hp回復(fù)量和Mp回復(fù)量分別對(duì)nTargetHp和nTargetMp數(shù)組進(jìn)展賦值。根據(jù)物品回復(fù)量更新目標(biāo)的Hp/Mp,注意不能超出最大Hp上限/最大Mp上限。

最后,發(fā)送戰(zhàn)斗動(dòng)畫消息給戰(zhàn)局所有玩家。

5.2.5說(shuō)明

本文為了盡量簡(jiǎn)短地闡述實(shí)現(xiàn)方式,戰(zhàn)斗指令消息的行動(dòng)者索引nActorInde*由客戶端直接賦值,效勞器并沒(méi)有對(duì)此進(jìn)展檢查而直接使用。假設(shè)客戶端并沒(méi)有使用自身角色的索引賦值而對(duì)nActorInde*進(jìn)展修改作弊,則能夠冒充其他玩家角色下達(dá)戰(zhàn)斗指令,存在隱患,所以戰(zhàn)斗指令消息的nActorInde*應(yīng)該由效勞器賦值并檢查,但由于本文篇幅所限并且考慮到游戲邏輯的復(fù)雜性和不一性,上述實(shí)現(xiàn)方式并沒(méi)有過(guò)多考慮防客戶端作弊,懇請(qǐng)讀者體諒。

而實(shí)際上,效勞器在很多地方都應(yīng)該對(duì)客戶端發(fā)來(lái)的消息進(jìn)展合法性檢查,防客戶端外掛或作弊,還請(qǐng)讀者根據(jù)自身游戲邏輯另外考慮。

5.3客戶端戰(zhàn)斗系統(tǒng)的實(shí)現(xiàn)

5.3.1客戶端戰(zhàn)斗系統(tǒng)功能模塊

圖5-4客戶端戰(zhàn)斗系統(tǒng)功能模塊

說(shuō)明:

戰(zhàn)斗系統(tǒng)主要包含戰(zhàn)斗角色、戰(zhàn)斗動(dòng)畫和戰(zhàn)斗指令菜單三個(gè)模塊;

戰(zhàn)斗指令菜單類型分為人物和寵物兩種,分別用于下達(dá)人物和寵物戰(zhàn)斗指令,并發(fā)送戰(zhàn)斗指令消息給效勞器;

戰(zhàn)斗角色由角色圖形、動(dòng)畫控制器和血條組成,通過(guò)動(dòng)畫控制器切換不同動(dòng)作的動(dòng)畫,主要負(fù)責(zé)戰(zhàn)斗角色的圖形顯示;

戰(zhàn)斗動(dòng)畫模塊主要有動(dòng)畫計(jì)數(shù)、把接收到的所有動(dòng)畫消息轉(zhuǎn)換為戰(zhàn)斗動(dòng)畫類以及播放戰(zhàn)斗動(dòng)畫三個(gè)功能;

動(dòng)畫計(jì)數(shù)主要是為了等待戰(zhàn)斗中所有正在播放的角色動(dòng)作動(dòng)畫、特效動(dòng)畫播放完,角色動(dòng)作動(dòng)畫或特效動(dòng)畫開(kāi)場(chǎng)時(shí)會(huì)+1動(dòng)畫計(jì)數(shù),完畢時(shí)會(huì)-1動(dòng)畫計(jì)數(shù),動(dòng)畫計(jì)數(shù)為0后,當(dāng)前單位行動(dòng)完畢,下一個(gè)行動(dòng)單位開(kāi)場(chǎng)行動(dòng);

播放戰(zhàn)斗動(dòng)畫模塊根據(jù)戰(zhàn)斗動(dòng)畫類數(shù)據(jù)播放不同行為的動(dòng)畫〔主要使用協(xié)程來(lái)控制戰(zhàn)斗角色的移動(dòng)、切換戰(zhàn)斗角色的動(dòng)作動(dòng)畫、添加特效等〕。

5.3.2客戶端戰(zhàn)斗系統(tǒng)相關(guān)數(shù)據(jù)類型

//戰(zhàn)斗動(dòng)畫類

publicclassBATTLE_ANIM

{

publicushortnActorInde*;//行動(dòng)方索引

publicushort[]nTargetInde*=newushort[10];//目標(biāo)索引

publicushortaction_type;//行動(dòng)類型

publicushortnParam;//參數(shù)〔根據(jù)行動(dòng)類型而定,如使用技能則是技能ID,使用物品則是物品欄位置〕

publicushortnAnimType;//技能動(dòng)畫類型

publicushortnEffectID;//技能特效ID

publicushortnTargetCount;//目標(biāo)總數(shù)〔nTargetInde*數(shù)組中值不為0的個(gè)數(shù)〕

publicushortnReactionInde*;//當(dāng)前受影響的目標(biāo)索引

publicshortnActorMp;//行動(dòng)方Mp影響〔多用于計(jì)算技能使用者的Mp消耗〕

publicshort[]nTargetHp=newshort[10];//目標(biāo)索引對(duì)應(yīng)的目標(biāo)Hp影響

}

5.3.3進(jìn)入戰(zhàn)斗后初始化戰(zhàn)斗角色

收到來(lái)自效勞器的戰(zhàn)斗初始化消息后,切換到戰(zhàn)斗場(chǎng)景,并根據(jù)戰(zhàn)斗初始化消息中的battleSprites數(shù)組〔包含戰(zhàn)斗角色的玩家ID、圖形及動(dòng)畫控制器ID、名字、Hp和Mp等數(shù)據(jù)〕動(dòng)態(tài)生成對(duì)應(yīng)的戰(zhàn)斗角色。

并且從戰(zhàn)斗初始化消息中的battleSprites數(shù)組中,比照玩家ID〔客戶端在登錄游戲后,理應(yīng)早已得到玩家ID,則在這里與battleSprites數(shù)組的玩家ID進(jìn)展比照〕查找自身角色和寵物的索引,用變量保存該索引,用于下達(dá)戰(zhàn)斗指令。

5.3.4下達(dá)戰(zhàn)斗指令并發(fā)送戰(zhàn)斗指令消息

下達(dá)戰(zhàn)斗指令實(shí)質(zhì)是地對(duì)戰(zhàn)斗指令消息的賦值。

一般是先下達(dá)人物戰(zhàn)斗指令,如有參戰(zhàn)寵物,再下達(dá)戰(zhàn)斗指令。在本文中,進(jìn)入戰(zhàn)斗時(shí),客戶端已能獲得自身人物和寵物在戰(zhàn)斗中的索引,假設(shè)是輪到人物下達(dá)戰(zhàn)斗指令,則戰(zhàn)斗指令消息的nActorInde*是人物的索引,假設(shè)是輪到寵物下達(dá)戰(zhàn)斗指令,則指令消息的nActorInde*是寵物的索引,分情況賦值即可,然后根據(jù)不同的行動(dòng)類型對(duì)指令消息的nActionType行動(dòng)類型賦值,最后通過(guò)點(diǎn)選目標(biāo)對(duì)指令消息的nTargetInde*進(jìn)展賦值。

當(dāng)下達(dá)完人物和寵物的戰(zhàn)斗指令后,分別發(fā)送對(duì)應(yīng)的戰(zhàn)斗指令消息。

戰(zhàn)斗指令菜單的UI實(shí)現(xiàn)千變?nèi)f化,本文不作闡述,使用最簡(jiǎn)單的按鈕即可實(shí)現(xiàn)。

下列圖為實(shí)踐工程的指令菜單,其中玩家選擇了使用技能的行動(dòng),并即將點(diǎn)選技能:

圖5-5指令菜單

5.3.5接收戰(zhàn)斗動(dòng)畫消息

根據(jù)每一條接收到的戰(zhàn)斗動(dòng)畫消息對(duì)new出來(lái)的戰(zhàn)斗動(dòng)畫類賦值,并push_back到一個(gè)順序容器〔可考慮List〕。

5.3.6收到戰(zhàn)斗動(dòng)畫播放消息并播放戰(zhàn)斗動(dòng)畫

當(dāng)接收到來(lái)自效勞器的戰(zhàn)斗動(dòng)畫播放消息后,客戶端開(kāi)場(chǎng)從頭到尾遍歷存放了多個(gè)戰(zhàn)斗動(dòng)畫類的順序容器,根據(jù)戰(zhàn)斗動(dòng)畫類的數(shù)據(jù),逐個(gè)播放動(dòng)畫。

戰(zhàn)斗動(dòng)畫的實(shí)現(xiàn)方式主要是依靠協(xié)同程序和動(dòng)畫計(jì)數(shù)器。角色播放動(dòng)作動(dòng)畫〔除待機(jī)〕或每往場(chǎng)景中添加一個(gè)特效動(dòng)畫,動(dòng)畫計(jì)數(shù)加1,角色播放動(dòng)作動(dòng)畫〔除待機(jī)〕完畢時(shí)調(diào)用方法切回待機(jī)動(dòng)畫并且動(dòng)畫計(jì)數(shù)-1,特效動(dòng)畫播放完畢時(shí)銷毀自身并且調(diào)用方法把動(dòng)畫計(jì)數(shù)減1,當(dāng)動(dòng)畫所有協(xié)程完畢返回并且動(dòng)畫計(jì)數(shù)為0時(shí),當(dāng)前動(dòng)畫播放完畢,開(kāi)場(chǎng)播放下一個(gè)動(dòng)畫。

當(dāng)播放完所有戰(zhàn)斗動(dòng)畫類后,清空容器,假設(shè)一方全體陣亡,則戰(zhàn)斗完畢退出戰(zhàn)斗場(chǎng)景,否則進(jìn)入下一回合,玩家開(kāi)場(chǎng)下達(dá)新回合的戰(zhàn)斗指令。

根據(jù)戰(zhàn)斗動(dòng)畫類的行動(dòng)類型和特效播放方式的不同,動(dòng)畫播放實(shí)現(xiàn)方式也不同,由于動(dòng)畫的實(shí)現(xiàn)較為復(fù)雜,本文在小節(jié)單獨(dú)以普通攻擊動(dòng)畫進(jìn)展較詳細(xì)的闡述,讀者可結(jié)合本小節(jié)和小節(jié)進(jìn)展理解。

下面是各種戰(zhàn)斗動(dòng)畫的實(shí)現(xiàn)方式:

普通攻擊動(dòng)畫協(xié)程

①行動(dòng)者角色執(zhí)行協(xié)程Move(),從自身位置移動(dòng)到目標(biāo)角色位置,到達(dá)后協(xié)程完畢返回;

②行動(dòng)者播放攻擊動(dòng)作動(dòng)畫,目標(biāo)播放受傷動(dòng)作動(dòng)畫并顯示目標(biāo)扣血數(shù)值,更新角色Hp/Mp,假設(shè)角色Hp為0則播放死亡動(dòng)作動(dòng)畫;

③使用循環(huán)和yieldreturn0語(yǔ)句直到動(dòng)畫計(jì)數(shù)為0〔即攻擊動(dòng)畫、受傷動(dòng)畫播放完〕跳出循環(huán);

④行動(dòng)者角色執(zhí)行協(xié)程Back(),回到原本的位置,到達(dá)原本的位置后協(xié)程完畢返回;

⑤協(xié)程完畢返回。

攻擊技能動(dòng)畫協(xié)程

①行動(dòng)者角色執(zhí)行協(xié)程Move(),從自身位置移動(dòng)到目標(biāo)角色位置,到達(dá)后協(xié)程完畢返回;

②行動(dòng)者播放攻擊動(dòng)作動(dòng)畫,添加并播放技能特效動(dòng)畫,目標(biāo)播放受傷動(dòng)作動(dòng)畫并顯示目標(biāo)扣血數(shù)值,更新角色Hp/Mp,假設(shè)角色Hp為0則播放死亡動(dòng)作動(dòng)畫;

③使用while循環(huán)和yieldreturn0語(yǔ)句直到動(dòng)畫計(jì)數(shù)為0〔即攻擊動(dòng)畫、受傷動(dòng)畫、特效動(dòng)畫播放完〕,后跳出循環(huán);

④行動(dòng)者角色執(zhí)行協(xié)程Back(),回到原本的位置,到達(dá)原本的位置后Back()協(xié)程完畢返回;

⑤協(xié)程完畢返回。

魔法技能〔同步型特效〕動(dòng)畫協(xié)程

①行動(dòng)者播放施法動(dòng)作動(dòng)畫,遍歷所有目標(biāo),并在目標(biāo)位置上添加并播放特效動(dòng)畫,目標(biāo)播放受傷動(dòng)作動(dòng)畫并顯示扣血數(shù)值,更新角色Hp/Mp,假設(shè)角色Hp為0則播放死亡動(dòng)作動(dòng)畫;

②使用while循環(huán)和yieldreturn0語(yǔ)句直到動(dòng)畫計(jì)數(shù)為0〔即攻擊動(dòng)畫、受傷動(dòng)畫、特效動(dòng)畫播放完〕,后跳出循環(huán);

③協(xié)程完畢返回。

動(dòng)畫效果如下列圖:

圖5-6魔法技能〔同步型特效〕動(dòng)畫效果

魔法技能〔異步型特效〕動(dòng)畫協(xié)程

①行動(dòng)者播放施法動(dòng)作動(dòng)畫,遍歷所有目標(biāo),并在目標(biāo)位置上添加并播放特效動(dòng)畫,目標(biāo)播放受傷動(dòng)作動(dòng)畫并顯示扣血數(shù)值,更新角色Hp/Mp,假設(shè)角色Hp為0則播放死亡動(dòng)作動(dòng)畫,遍歷中使用yieldreturn幀數(shù)/秒數(shù)實(shí)現(xiàn)延遲,從而到達(dá)每個(gè)目標(biāo)身上出現(xiàn)的特效動(dòng)畫時(shí)間不一樣;

②使用while循環(huán)和yieldreturn0語(yǔ)句直到動(dòng)畫計(jì)數(shù)為0〔即攻擊動(dòng)畫、受傷動(dòng)畫、特效動(dòng)畫播放完〕,后跳出循環(huán);

③協(xié)程完畢返回。

動(dòng)畫效果如下列圖:

圖5-7魔法技能〔異步型特效〕動(dòng)畫效果

魔法技能〔彈射型特效〕動(dòng)畫協(xié)程

①行動(dòng)者播放施法動(dòng)作動(dòng)畫,行動(dòng)者身上添加一個(gè)循環(huán)播放的特效動(dòng)畫;

②遍歷目標(biāo),使用協(xié)程控制特效動(dòng)畫的移動(dòng),使特效移動(dòng)到目標(biāo)的位置,到達(dá)位置后,目標(biāo)播放受傷動(dòng)作動(dòng)畫并顯示扣血數(shù)值,更新角色Hp/Mp,假設(shè)角色Hp為0則播放死亡動(dòng)作動(dòng)畫,再讓特效移動(dòng)到下一個(gè)目標(biāo)的位置,如此類推,直到最后一個(gè)目標(biāo),手動(dòng)摧毀特效;

③協(xié)程完畢返回。

動(dòng)畫效果如下列圖:

圖5-8魔法技能〔彈射型特效〕動(dòng)畫效果

魔法技能〔發(fā)射型特效〕動(dòng)畫協(xié)程

①行動(dòng)者播放施法動(dòng)作動(dòng)畫,遍歷目標(biāo),行動(dòng)者身上添加數(shù)量與目標(biāo)數(shù)一樣循環(huán)播放的特效動(dòng)畫,并增加同等的動(dòng)畫計(jì)數(shù);

②每個(gè)特效自身執(zhí)行協(xié)程讓自身移向?qū)?yīng)目標(biāo)的位置,到達(dá)后動(dòng)畫計(jì)數(shù)減1,特效銷毀自身,目標(biāo)播放受傷動(dòng)作動(dòng)畫并顯示扣血數(shù)值,更新角色Hp/Mp,假設(shè)角色Hp為0則播放死亡動(dòng)作動(dòng)畫;

③使用while循環(huán)和yieldreturn0語(yǔ)句直到動(dòng)畫計(jì)數(shù)為0〔即攻擊動(dòng)畫、受傷動(dòng)畫、特效動(dòng)畫播放完〕,后跳出循環(huán);

④協(xié)程完畢返回。

動(dòng)畫效果如下列圖:

圖5-9魔法技能〔發(fā)射型特效〕動(dòng)畫效果

使用物品動(dòng)畫協(xié)程

①行動(dòng)者播放施法動(dòng)作動(dòng)畫,并在所有目標(biāo)身上添加并播放用于恢復(fù)的特效動(dòng)畫并顯示數(shù)值,更新角色Hp/Mp;

②使用while循環(huán)和yieldreturn0語(yǔ)句直到動(dòng)畫計(jì)數(shù)為0〔即攻擊動(dòng)畫、受傷動(dòng)畫、特效動(dòng)畫播放完〕,后跳出循環(huán);

③協(xié)程完畢返回。

5.3.7戰(zhàn)斗動(dòng)畫實(shí)現(xiàn)細(xì)述

本小節(jié)以魔法技能動(dòng)畫〔彈射型特效〕的實(shí)現(xiàn)為例進(jìn)展細(xì)述,以便讀者理解實(shí)現(xiàn)原理。

相關(guān)偽代碼如下:

//動(dòng)畫播放協(xié)程

IEnumeratorPlayAnim()

{

while(l_AnimList不為空)//存放戰(zhàn)斗動(dòng)畫類的list容器不為空

{

//沉著器中獲得頭一個(gè)戰(zhàn)斗動(dòng)畫類

BATTLE_ANIMbattleAnim=l_AnimList[0];

switch(battleAnim.action_type)//判斷行動(dòng)類型

{

case普通攻擊:

yieldreturnStartCoroutine(Attack(battleAnim));

break;

case使用技能:

根據(jù)battleAnim.nParam查詢數(shù)據(jù)庫(kù)技能表獲得技能動(dòng)畫類型

battleAnim.nAnimType=技能動(dòng)畫類型

switch(battleAnim.nAnimType)//判斷技能動(dòng)畫類型

{

case攻擊技能動(dòng)畫:

yieldreturnStartCoroutine(MagicAttack(battleAnim));

break;

case魔法技能動(dòng)畫〔彈射型特效〕:

yieldreturnStartCoroutine(MagicBounce(battleAnim));

break;

……

}

break;

case使用物品:

yieldreturnStartCoroutine(Item(battleAnim));

break;

}

while(動(dòng)畫計(jì)數(shù)器!=0)//〔一幀一次循環(huán)〕

{

//下一幀再回到這里執(zhí)行下一次循環(huán)

yieldreturn1;

}

l_AnimList.Remove(0);//去除本次播放完的戰(zhàn)斗動(dòng)畫類

}

//所有動(dòng)畫播放完

if(一方全體死亡)

戰(zhàn)斗完畢

else

進(jìn)入下一回合,玩家下達(dá)指令

}

說(shuō)明:

PlayAnim協(xié)同程序主要是遍歷存放戰(zhàn)斗動(dòng)畫類的list容器,通過(guò)遍歷逐個(gè)播放戰(zhàn)斗動(dòng)畫類數(shù)據(jù)所包含的動(dòng)畫,通過(guò)類型的判斷,執(zhí)行不同的協(xié)同程序?qū)崿F(xiàn)不同類型動(dòng)畫的播放。

//魔法技能動(dòng)畫〔彈射型特效〕協(xié)程

IEnumeratorMagicBounce(BATTLE_ANIMbattleAnim)

{

行動(dòng)者〔施法者〕播放施法動(dòng)作動(dòng)畫;

根據(jù)特效ID動(dòng)態(tài)加載特效預(yù)設(shè);

由特效預(yù)設(shè)動(dòng)態(tài)生成特效effect;

把effect移到到施法者的位置上;

動(dòng)畫計(jì)數(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)播放受傷動(dòng)作動(dòng)畫并顯示扣血

}

遍歷完所有目標(biāo)后,銷毀特效

動(dòng)畫計(jì)數(shù)-1

}

說(shuō)明:

MagicBounce協(xié)同程序主要是控制特效的移動(dòng),實(shí)現(xiàn)彈射型特效動(dòng)畫的播放。

最終的動(dòng)畫效果為:行動(dòng)者施法,技能特效從行動(dòng)者身上移向第一個(gè)目標(biāo),特效到達(dá)第一個(gè)目標(biāo)的位置后目標(biāo)受傷并扣血,特效繼續(xù)移向下一個(gè)目標(biāo),如此類推,直到最后一個(gè)目標(biāo)后,技能動(dòng)畫完畢,銷毀特效,協(xié)程完畢返回到PlayAnim(),PlayAnim()繼續(xù)遍歷播放下一個(gè)動(dòng)畫。

其他動(dòng)畫類型與上

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論