基于Unity3D的網(wǎng)絡(luò)多人對(duì)戰(zhàn)策略游戲的開發(fā)與實(shí)_第1頁(yè)
基于Unity3D的網(wǎng)絡(luò)多人對(duì)戰(zhàn)策略游戲的開發(fā)與實(shí)_第2頁(yè)
基于Unity3D的網(wǎng)絡(luò)多人對(duì)戰(zhàn)策略游戲的開發(fā)與實(shí)_第3頁(yè)
基于Unity3D的網(wǎng)絡(luò)多人對(duì)戰(zhàn)策略游戲的開發(fā)與實(shí)_第4頁(yè)
基于Unity3D的網(wǎng)絡(luò)多人對(duì)戰(zhàn)策略游戲的開發(fā)與實(shí)_第5頁(yè)
已閱讀5頁(yè),還剩85頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

摘要在如今的互聯(lián)網(wǎng)時(shí)代影響下,人們的生活交往方式產(chǎn)生了變化。在學(xué)習(xí)工作的時(shí)間之外,游戲娛樂已經(jīng)成為人們休閑娛樂的主要方式之一,尤其是在互聯(lián)網(wǎng)高速發(fā)展的今天,網(wǎng)絡(luò)游戲成為了越來越多人的選擇。網(wǎng)絡(luò)游戲不僅是人們放松身心的娛樂方式,也是溝通交友的有效途徑,網(wǎng)絡(luò)游戲已然成為人們休閑之時(shí)的很好選擇,網(wǎng)絡(luò)游戲的發(fā)展越來越受到重視。Unity3D是目前最流行的游戲開發(fā)引擎之一,以其低成本與高效率被多數(shù)游戲開發(fā)者所使用。本文主要描述了使用Unity3D開發(fā)基于網(wǎng)絡(luò)的多人策略放置類型游戲的實(shí)際開發(fā)過程,以及開發(fā)過程中所應(yīng)用到的網(wǎng)絡(luò)連接與信息交流的原理與方法。在具體的開發(fā)流程中,主要描述了使用Unity3D作為開發(fā)引擎的游戲客戶端的開發(fā),隨后實(shí)現(xiàn)基于TCP的服務(wù)端的簡(jiǎn)單實(shí)現(xiàn),以及服務(wù)端與客戶端進(jìn)行交流的實(shí)現(xiàn),然后會(huì)實(shí)現(xiàn)游戲熱更新的相關(guān)步驟,最后進(jìn)行游戲的打包與功能的測(cè)試。為后續(xù)的同類型游戲開發(fā)提供借鑒與參考。關(guān)鍵詞:Unity3D;策略類游戲;網(wǎng)絡(luò)游戲

AbstractUndertheinfluenceoftheInternetera,people'swayoflifeandcommunicationhaschanged.Inadditiontostudyandworktime,gameentertainmenthasbecomeoneofthemainwaysofpeople'sleisureandentertainment,especiallyintherapiddevelopmentoftheInternettoday,onlinegameshavebecomemoreandmorepeople'schoice.Onlinegamesarenotonlyawayforpeopletorelaxphysicallyandmentally,butalsoaneffectivewaytocommunicateandmakefriends.Onlinegameshavebecomeagoodchoiceforpeopleintheirleisuretime,andthedevelopmentofonlinegameshasattractedmoreandmoreattention.Unity3Disoneofthemostpopulargamedevelopmentengines,whichisusedbymostgamedeveloperswithitslowcostandhighefficiency.Thispapermainlydescribestheactualdevelopmentprocessofdevelopingnetwork-basedmultiplayerstrategyplacementtypegameswithUnity3D,andtheprinciplesandmethodsofnetworkconnectionandinformationexchangeappliedinthedevelopmentprocess.Inthespecificdevelopmentprocess,itmainlydescribesthedevelopmentofthegameclientwhichUSESUnity3Dasthedevelopmentengine,thenrealizesthesimpleimplementationoftheserverbasedonTCP,aswellasthecommunicationbetweentheserverandtheclient,thenrealizestherelevantstepsofthegamehotupdate,andfinallycarriesoutthepackagingandfunctionaltestofthegame.Itprovidesreferenceforthefollowingdevelopmentofthesametypeofgames.Keywords:Unity3D;Strategygame;Networkgame

目錄第一章 緒論 緒論選題的目的和意義隨著人民生活水平的提高和互聯(lián)網(wǎng)終端硬件設(shè)施的改善,更多的人選擇在線上游戲里釋放生活中的壓力,為自己的生活增添更多的樂趣,游戲產(chǎn)業(yè)因此飛速發(fā)展。在眾多不同類型的游戲中,人們更趨向于選擇網(wǎng)絡(luò)游戲,所以網(wǎng)絡(luò)游戲占據(jù)絕對(duì)主體地位。選擇開發(fā)一款網(wǎng)絡(luò)游戲能夠獲得更大的市場(chǎng)需求和更多的機(jī)會(huì)。計(jì)算機(jī)的持續(xù)普及和網(wǎng)絡(luò)技術(shù)的不斷發(fā)展,為網(wǎng)絡(luò)游戲的發(fā)展提供了硬件基礎(chǔ)和技術(shù)支持。一款好的游戲開發(fā)引擎可以幫助開發(fā)者快速將游戲構(gòu)想付諸實(shí)現(xiàn)。在眾多游戲開發(fā)引擎中的Unity3D,以它的多平臺(tái)開發(fā)、上手難度低等特點(diǎn)脫穎而出。選用Unity3D作為開發(fā)引擎,可以幫助開發(fā)者更加便捷、高效地開發(fā)出一款完整的游戲。由于Unity3D游戲開發(fā)的成本較低、周期較短、適應(yīng)不同終端平臺(tái)、支持多種游戲類型開發(fā)等特點(diǎn),是許多游戲開發(fā)公司的首選,因此Unity3D開發(fā)等相關(guān)崗位擁有比較廣闊的市場(chǎng)和發(fā)展前景。研究現(xiàn)狀隨著互聯(lián)網(wǎng)技術(shù)和終端硬件的發(fā)展與完善、人們生活水平的提高,游戲市場(chǎng)越來越受到重視,游戲產(chǎn)業(yè)高速發(fā)展。2019年全球數(shù)字游戲總營(yíng)收高達(dá)1201億美元,其中的移動(dòng)端游戲營(yíng)收644億美元。移動(dòng)端游戲的收入占免費(fèi)游戲營(yíng)收的比重高達(dá)74%,在這其中騰訊的王者榮耀穩(wěn)定強(qiáng)勁的營(yíng)收占據(jù)了較大比重。這也體現(xiàn)了如今的游戲產(chǎn)業(yè)中,移動(dòng)端網(wǎng)絡(luò)游戲是比較受歡迎,有較大的市場(chǎng)和前景。論文組織結(jié)構(gòu)論文從最初的構(gòu)思到最終的完成,結(jié)合應(yīng)用了游戲開發(fā)與網(wǎng)絡(luò)交流相關(guān)的知識(shí)和技術(shù),成功實(shí)現(xiàn)了一個(gè)基于Unity3D的網(wǎng)絡(luò)多人策略游戲的開發(fā),其中具體介紹了游戲框架設(shè)計(jì)以及游戲制作的關(guān)鍵步驟,也包括游戲的系統(tǒng)功能設(shè)計(jì)和一系列代碼的編寫。論文分為六章,各章節(jié)安排如下:?第一部分:緒論,主要闡述了該畢業(yè)設(shè)計(jì)制作的背景、相關(guān)課題的研究現(xiàn)狀以及本設(shè)計(jì)的大概介紹;?第二部分:介紹了本文制作游戲使用的各類開發(fā)工具和Unity3D的大致介紹;第三部分:介紹游戲流程設(shè)計(jì);第四部分:游戲?qū)嵺`開發(fā)的關(guān)鍵步驟;?第五部分:對(duì)游戲進(jìn)行打包并測(cè)試;第六部分:進(jìn)行最終總結(jié),回顧游戲的缺陷以及改進(jìn)方法。

開發(fā)工具介紹Unity3D游戲引擎Unity3D是一款3D跨平臺(tái)次時(shí)代游戲引擎。作為一款專業(yè)的游戲開發(fā)引擎,它有資深技術(shù)團(tuán)隊(duì)的支持、友善的圖形化界面、豐富的拓展插件和多平臺(tái)的導(dǎo)出配置。Unity降低了游戲開發(fā)門檻,引擎的上手難度較小,對(duì)新手比較友好。使用Unity開發(fā)游戲的成本低,開發(fā)周期較短,是大多數(shù)游戲公司和游戲開發(fā)者的最佳選擇。C#開發(fā)語(yǔ)言C#是微軟公司發(fā)布的一種運(yùn)行于.NETFramework和.NetCore上的高級(jí)程序設(shè)計(jì)語(yǔ)言,是由C和C++衍生出來的面向?qū)ο蟮木幊陶Z(yǔ)言,擁有較高的運(yùn)行效率和較強(qiáng)的操作能力,因?yàn)槠鋭?chuàng)新性的語(yǔ)言特性以及面向組件的編程支持,成為了Unity3D開發(fā)選用的主流語(yǔ)言。C#不僅能用于開發(fā)傳統(tǒng)Windows環(huán)境中的應(yīng)用程序,還可以用來開發(fā)原生的Android、iOS、WindowsPhone和MacApp應(yīng)用程序,甚至還能整合Azure或Hadoop技術(shù)開發(fā)云計(jì)算和大數(shù)據(jù)應(yīng)用系統(tǒng)。[5]C#也提供了網(wǎng)絡(luò)編程相關(guān)類庫(kù),因此也可被用于服務(wù)端的開發(fā)。VisualStudio2017VisualStudio2017(以下簡(jiǎn)稱VS)是微軟公司推出的集成開發(fā)環(huán)境。提供強(qiáng)大的調(diào)試和性能分析工具,快捷地查找和修復(fù)錯(cuò)誤的方式,強(qiáng)大的庫(kù)調(diào)用和云集成,為Unity3D游戲開發(fā)提高了效率。MySQL數(shù)據(jù)庫(kù)MySQL是由瑞典MySQLAB公司開發(fā)的一個(gè)關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng)。因?yàn)槠潢P(guān)系型的特點(diǎn),存儲(chǔ)時(shí)將數(shù)據(jù)保存在不同的表中,提高了讀寫速度和整個(gè)數(shù)據(jù)庫(kù)的靈活性。也擁有體積小、速度快、運(yùn)營(yíng)成本低等優(yōu)點(diǎn),是中小型項(xiàng)目開發(fā)時(shí)數(shù)據(jù)庫(kù)使用的較好選擇。Lua開發(fā)語(yǔ)言Lua是由巴西里約熱內(nèi)盧天主教大學(xué)里的一個(gè)由RobertoIerusalimschy、WaldemarCeles和LuizHenriquedeFigueiredo三人所組成的研究小組于1993年開發(fā)的一個(gè)小巧的腳本語(yǔ)言,該腳本語(yǔ)言設(shè)計(jì)之初就是為了嵌入到應(yīng)用程序中,為其提供擴(kuò)展和定制等功能。由于C#是預(yù)編譯語(yǔ)言,在手機(jī)端的熱更新上不太兼容,所以使用Lua語(yǔ)言嵌入C#實(shí)現(xiàn)游戲代碼的熱更新。

游戲設(shè)計(jì)游戲玩法設(shè)計(jì)本游戲是根據(jù)目前比較流行的策略放置類型游戲:自走棋,進(jìn)行設(shè)計(jì)和開發(fā)的。在游戲中,玩家有金幣欄、生命值和經(jīng)驗(yàn)欄。每一小局系統(tǒng)會(huì)給玩家若干金幣,提供5個(gè)英雄讓玩家購(gòu)買,玩家通過點(diǎn)擊UI使用金幣購(gòu)買英雄、刷新英雄或提升自身的等級(jí),通過賣出英雄獲得金幣。玩家收集不同的英雄搭配,為英雄佩戴裝備,提升自己的陣容強(qiáng)度,在對(duì)戰(zhàn)時(shí)刻來臨時(shí),對(duì)戰(zhàn)雙方的英雄陣營(yíng)進(jìn)行自動(dòng)對(duì)戰(zhàn),失敗一方扣除生命。玩家的生命值小于等于0,就淘汰出局,游戲一直持續(xù)至出現(xiàn)唯一存活下來的勝利玩家。游戲熱更新在游戲以及上架后,如果我們發(fā)現(xiàn)游戲中有Bug或者想要修改游戲中的模型貼圖甚至是發(fā)行DLC等等,我們可以選擇在Unity3D編輯器中修改,然后再打包后發(fā)行。當(dāng)是這樣操作后,游戲就得重新花費(fèi)時(shí)間進(jìn)行審核,玩家也得重新下載整個(gè)游戲。這就會(huì)造成玩家的流失,尤其在手機(jī)玩家的流失方面更為嚴(yán)重。因此游戲熱更新應(yīng)運(yùn)而生。游戲熱更,只需下載需要更新的部分覆蓋舊的部分,極大的降低了游戲更新地代價(jià)。尤其在網(wǎng)絡(luò)游戲方面,如果出現(xiàn)一個(gè)BUG可能會(huì)破壞游戲平衡甚至導(dǎo)致整個(gè)游戲的終結(jié),熱更新的及時(shí)性,可以降低游戲修復(fù)的時(shí)間和難度。在每次打開游戲的時(shí)候,都會(huì)進(jìn)行更新檢查,如果發(fā)現(xiàn)新的版本,就會(huì)進(jìn)行熱更新。圖3-1游戲進(jìn)行熱更新游戲登錄界面在熱更新完成之后,就會(huì)進(jìn)入游戲登錄界面。玩家可以在登錄界面進(jìn)行賬號(hào)注冊(cè)和登錄。登錄及注冊(cè)的內(nèi)容會(huì)通過協(xié)議發(fā)送到服務(wù)端,服務(wù)端解析后,通過SQL語(yǔ)句訪問數(shù)據(jù)庫(kù),完成玩家的操作。圖3-2游戲登錄界面游戲大廳及房間在玩家成功登錄后,會(huì)進(jìn)入游戲大廳。大廳會(huì)顯示出所有的游戲房間。左側(cè)為玩家的賬號(hào)信息,右側(cè)為大廳界面,提供創(chuàng)建房間和刷新界面的按鈕。玩家可以創(chuàng)建房間或者進(jìn)入別人的房間進(jìn)行游戲。圖3-3游戲大廳界面當(dāng)玩家進(jìn)入一個(gè)房間后,游戲會(huì)切換至房間界面。房間界面提供了離開、添加機(jī)器人玩家、開始游戲三個(gè)按鈕。一個(gè)房間最多可以進(jìn)入8位玩家,當(dāng)房間內(nèi)的玩家數(shù)量至少為2名時(shí),才能進(jìn)行游戲。圖3-4房間界面游戲流程英雄和裝備購(gòu)買房主點(diǎn)擊開始游戲按鈕后發(fā)送開始游戲協(xié)議到服務(wù)端,服務(wù)端接收到消息后在派送給所有客戶端,客戶端接收到開始游戲協(xié)議后,開始加載游戲資源,當(dāng)資源加載完成后,發(fā)送完成協(xié)議到服務(wù)端,服務(wù)端收集到全部的協(xié)議后,廣播正式開始游戲協(xié)議,所有玩家進(jìn)入游戲界面。通過點(diǎn)擊游戲右下角的棋簍按鈕可進(jìn)入英雄和裝備購(gòu)買界面,英雄購(gòu)買界面顯示英雄的價(jià)格、羈絆等信息。玩家通過購(gòu)買英雄和裝備并使用,從而與其它玩家進(jìn)行對(duì)戰(zhàn)。圖3-5英雄和裝備購(gòu)買界面玩家點(diǎn)擊英雄后進(jìn)行購(gòu)買,購(gòu)買的英雄會(huì)出現(xiàn)在等待區(qū)域,通過拖拽方式將英雄放置到戰(zhàn)斗區(qū)域,拖拽時(shí)會(huì)出現(xiàn)綠色的UI提示可放置位置。購(gòu)買后的裝備會(huì)出現(xiàn)在左下角的倉(cāng)庫(kù)內(nèi),拖拽倉(cāng)庫(kù)內(nèi)的裝備至英雄身上進(jìn)行裝備。圖3-6拖拽英雄至戰(zhàn)斗區(qū)域圖3-7拖拽裝備至英雄身上英雄羈絆在游戲畫面的左側(cè)有英雄羈絆界面,玩家將購(gòu)買后的英雄放置到戰(zhàn)斗區(qū)后,系統(tǒng)會(huì)統(tǒng)計(jì)戰(zhàn)斗區(qū)域英雄的羈絆組合,將羈絆組合顯示在羈絆界面并為英雄增加相應(yīng)的屬性,玩家可以通過不同的羈絆組合實(shí)現(xiàn)屬于自己的英雄陣容,游戲的可玩性得到提升。圖3-8羈絆界面升級(jí)英雄當(dāng)玩家購(gòu)買且集齊三個(gè)同等級(jí)同類型的英雄后,可以點(diǎn)擊英雄屬性界面的升級(jí)按鈕,將三個(gè)一級(jí)英雄升級(jí)為一個(gè)二級(jí)英雄,獲得更高的英雄屬性,更少的位置占用。圖3-9英雄升級(jí)畫面戰(zhàn)斗階段當(dāng)游戲畫面上方的倒計(jì)時(shí)結(jié)束后,進(jìn)入戰(zhàn)斗階段,戰(zhàn)斗區(qū)域的雙方英雄進(jìn)行戰(zhàn)斗。戰(zhàn)斗階段結(jié)束后,又會(huì)回到準(zhǔn)備階段。玩家需要不斷調(diào)整自己的英雄組合和裝備,確保自己贏得更多的戰(zhàn)斗。圖3-10英雄戰(zhàn)斗畫面結(jié)算界面每個(gè)戰(zhàn)斗階段結(jié)束后,如果任何一方有英雄存活,就會(huì)對(duì)對(duì)方玩家造成基于英雄數(shù)量的傷害。在游戲畫面的右方是游戲中玩家的生命值,當(dāng)某位玩家的生命值為0時(shí),就表示失敗,不再繼續(xù)參加游戲。當(dāng)只剩下一位玩家存活時(shí),這位玩家就是勝利者,同時(shí)游戲畫面會(huì)切換至結(jié)算畫面。結(jié)算界面會(huì)根據(jù)玩家們游戲失敗時(shí)的時(shí)間長(zhǎng)短,顯示玩家們的名次,對(duì)應(yīng)增加勝敗次數(shù)。圖3-11結(jié)算畫面在游戲結(jié)算后,玩家可以在結(jié)算界面查看自己的名次及勝負(fù)場(chǎng)次。然后可以點(diǎn)擊游戲畫面右下角的返回大廳按鈕,返回到游戲大廳,繼續(xù)進(jìn)入房間進(jìn)行游戲,或是退出游戲。

游戲?qū)崿F(xiàn)UI界面的實(shí)現(xiàn)UI界面框架PureMVC是一個(gè)基于MVC模式建立的輕量級(jí)框架,實(shí)現(xiàn)了經(jīng)典MVC設(shè)計(jì)模式中的Model、View、Controller三層分離的方式,有利于減少應(yīng)用程序與視圖間的依賴,降低整個(gè)程序的耦合程度。PureMVC框架非常適用于UI界面的構(gòu)造。UI視圖、數(shù)據(jù)和控制命令間的解耦,有利于UI界面的管理和更新。圖4-1PureMVC框架的結(jié)構(gòu)圖PureMVC大致分為四大部分:View:由具體的UI組件和對(duì)應(yīng)的Mediator組成。UI組件只負(fù)責(zé)UI的獲取。Mediator負(fù)責(zé)接收操作UI組件的命令和對(duì)UI組件進(jìn)行具體操作。Model:由Data和Proxy組成。Data保存了View層的數(shù)據(jù),可以是本地的或是下載得到的數(shù)據(jù)。Proxy是Data的封裝層,負(fù)責(zé)Data的獲取和操作。Controller:由自己編寫的許多Command組成,通過這些Command在其它兩層之間進(jìn)行交互,或是MVC系統(tǒng)外部對(duì)內(nèi)部的訪問。Fa?ade:是整個(gè)PureMVC體系的唯一外部接口,外部通過Fa?ade和對(duì)應(yīng)的Command對(duì)內(nèi)部進(jìn)行訪問。所有的Mediator、Proxy、Command都要在Fa?ade內(nèi)進(jìn)行注冊(cè)和刪除。UI子物體的獲取在Unity的的UI交互設(shè)計(jì)中,初學(xué)者通常是在預(yù)先編寫的腳本內(nèi),通過Find或GetChild獲取到UIPanel下的子物體進(jìn)行邏輯設(shè)計(jì)。當(dāng)我們?cè)谟螒蜷_發(fā)中后期,要對(duì)游戲UI進(jìn)行修改調(diào)整時(shí),如調(diào)整UI的層級(jí)或是添加新的子物體,原本編寫好的代碼就無(wú)法獲取到UI子物體,重新編寫腳本就顯得耗時(shí)耗力。所以可以使用一種便捷地獲取需要進(jìn)行使用的UI子物體的方式。在制作UIPanel之初,我們可以把需要使用的UI子物體的名稱進(jìn)行修改添加標(biāo)記,如“Button_”,在所有子物體的名稱后添加“_”。使用一個(gè)單例類UIManager,存放一個(gè)鍵值對(duì)為父節(jié)點(diǎn)的名稱和所有需要使用的子物體,類型為Dictionary<string,Dictionary<string,Transform>>的字典;以及對(duì)應(yīng)該字典的添加、移除和獲取方法。在每個(gè)UIPanel的初始化時(shí),遍歷自身的所有節(jié)點(diǎn),就能根據(jù)標(biāo)記獲取到所有需要的子物體,保存到字典內(nèi)。使用這種方式后,我們只需要知道父物體的名稱,該物體的名稱,以及該物體的類型,就可以根據(jù)獲得的transform得到對(duì)應(yīng)的組件。當(dāng)我們調(diào)整子物體的層級(jí)時(shí),原腳本無(wú)需修改;而當(dāng)添加新物體時(shí),只需要根據(jù)模板進(jìn)行獲取UI。GameObject

root

=

skin.gameObject;

Transform[]

allChild

=

root.GetComponentsInChildren<Transform>();

foreach

(var

i

in

allChild)

{

if

(.EndsWith("_"))

{

UIManager.Instance.AddUI(,

,

i);

}

}

UI界面流程控制和管理在所有父UI的層面上,我們也應(yīng)該進(jìn)行管理;使用類PanelManager和BasePanel組成界面管理。BasePanel作為所有Panel的基類,與UIManager和PureMve相結(jié)合。在OnShow中預(yù)先編寫之前的UI子物體獲取保存方式,每個(gè)Panel在OnShow時(shí)自動(dòng)運(yùn)行。在MVC的表現(xiàn)上:Panel腳本和其相互對(duì)應(yīng)的Mediator和作為UI界面的View層,對(duì)應(yīng)的Proxy和Data作為Model層,作為兩層間交互的控制命令作為Controller層,其實(shí)例在之后UIPanel的實(shí)際開發(fā)中體現(xiàn)。Panel繼承BasePanel并重寫OnInit、OnShow、OnClose三個(gè)虛函數(shù),編寫各自在不同情況下的邏輯;保存了SkinName和Skin,根據(jù)SkinName加載對(duì)應(yīng)的UIPanel游戲物體。 public

class

BasePanel

:

MonoBehaviour

{

//皮膚路徑

public

string

skinName;

//皮膚

public

GameObject

skin;

//層級(jí)

public

PanelManager.Layer

layer

=

PanelManager.Layer.Panel;

public

SceneEnum

SceneIndex;

public

int

itemIndex;//如果是子面板,索引

public

PanelManager.CanvasEnum

canvasIndex

=

0;//畫布索引

//初始化

public

void

Init(Transform

rootLayer,

Dictionary<string,

BasePanel>

panels,

object[]

para)

public

void

Init(Transform

rootLayer,

List<BasePanel>

childrenPanels,

object[]

para)

//關(guān)閉

public

void

Close()

//初始化時(shí)

public

virtual

void

OnInit()

//顯示時(shí)

public

virtual

void

OnShow(object[]

para)

//關(guān)閉時(shí)

public

virtual

void

OnClose()

}

PanelManager作為所有Panel的管理類,存儲(chǔ)并管理所有的UI界面和子UI界面。提供界面的打開和關(guān)閉,并控制UI界面在其生命周期內(nèi)的運(yùn)行邏輯。public

static

class

PanelManager

{

//Layer

public

enum

Layer

public

enum

CanvasEnum

//層級(jí)列表

private

static

Dictionary<Layer,

Dictionary<int,

Transform>>

layers;

//面板列表

public

static

Dictionary<string,

BasePanel>

panels

=

new

Dictionary<string,

BasePanel>();

public

static

Dictionary<GameObject,

List<BasePanel>>

childPanels

=

new

Dictionary<GameObject,

List<BasePanel>>();

//結(jié)構(gòu)

public

static

Transform

root;

public

static

List<Transform>

canvas;

public

static

FirstFacade

firstFacade;

public

static

SecondFacade

secondFacade;

//初始化

public

static

void

Init()

//打開面板

public

static

void

Open<T>(params

object[]

para)

where

T

:

BasePanel

public

static

void

AddChildPanel<T>(GameObject

parent,

object[]

para)

where

T

:

BasePanel

//關(guān)閉面板

public

static

void

Close(string

name)

public

static

void

Close<T>()

where

T

:

BasePanel

public

static

void

RemoveChildPanels(GameObject

parent)

public

static

void

RemoveChildPanelSelf(GameObject

parent,

string

Name)

}

UI界面是一個(gè)優(yōu)秀游戲中最基礎(chǔ)的、最不可獲取的部分,是玩家更直觀地游玩游戲地依托。為了更好地UI界面的管理和維護(hù),使用了基于PureMVC框架實(shí)現(xiàn)的UI界面設(shè)計(jì),因此需要有View、Model、Command三層分離的實(shí)現(xiàn)方式。接下來以游戲中的英雄羈絆界面為例,進(jìn)行UI界面實(shí)例的實(shí)現(xiàn)。View層的實(shí)現(xiàn)HeroTypePanel創(chuàng)建腳本HeroTypePanel繼承BasePanel,重寫基類的OnInit、OnShow、OnClose三個(gè)方法。在OnInit中,調(diào)用基類的OnInit的多態(tài)實(shí)現(xiàn)的另一個(gè)同名方法,填入?yún)?shù)分別為:SkinName(UI界面的GameObject的名稱,用于加載UI界面的圖形化表示的實(shí)例到游戲中),SceneIndex(GameObject加載時(shí)需要的參數(shù),表示來源于哪個(gè)資源包),PanelIndex(表示將這個(gè)UI界面添加到哪個(gè)層級(jí)(或是當(dāng)前UI界面是什么類型的):例如彈窗類型是永遠(yuǎn)覆蓋于所有的普通界面類型之上的),CanvasIndex(表示UI界面的目標(biāo)畫布)。在OnShow方法中:調(diào)用基類的OnShow方法,遍歷UI界面的所有子物體,保存到UIManager中。調(diào)用Fa?ade的Register進(jìn)行與這個(gè)UI界面相關(guān)的Mediator、Proxy、Command的注冊(cè)。在OnClose方法中:調(diào)用Fa?ade的SendNotification方法進(jìn)行廣播消息,移除該UI界面的子UI界面。調(diào)用Fa?ade的Remove進(jìn)行與該UI界面相關(guān)的MVC三層的移除。public

class

HeroTypePanel

:

BasePanel

{

public

override

void

OnInit()

{

base.OnInit("HeroTypePanel",

SceneEnum.GameScene,

PanelManager.Layer.Panel,

PanelManager.CanvasEnum.World);

}

public

override

void

OnShow(params

object[]

para)

{

base.OnShow(para);

PanelManager.secondFacade.Register(SecondFacade.RegisterPanel.HeroTypePanel,

skin.gameObject,

para);

}

public

override

void

OnClose()

{

base.OnClose();

PanelManager.secondFacade.SendNotification(NotificationCons.RemoveHeroTypeItemPanelMediator);

PanelManager.secondFacade.Remove(SecondFacade.RegisterPanel.HeroTypePanel);

}

}

HeroTypePanelMediator創(chuàng)建腳本HeroTypePanelMediator繼承Mediator。在構(gòu)造函數(shù)中:接收需要的參數(shù),并為Base傳入mediatorName(此Mediator類的索引)用于注冊(cè)。content是該UI界面的子UI界面的根結(jié)點(diǎn),通過UIManager獲取。重寫ListNotificationInterests和HandleNotification。用于Notification(PureMVC內(nèi)部提供的消息系統(tǒng))的注冊(cè)和接收。編寫其它的方法進(jìn)行UI界面的具體操作,通過消息接收觸發(fā)。public

class

HeroTypePanelMetiator

:

Mediator

{

public

const

string

mediatorName="HeroTypePanelMetiator";

private

GameObject

content;

private

string

curId;

public

HeroTypePanelMetiator(GameObject

root)

:

base(mediatorName)

{

content

=

UIManager.Instance.GetUI(,

"content_").gameObject;

}

public

override

string[]

ListNotificationInterests()

public

override

void

HandleNotification(INotification

notification)

public

void

UpdateHeroTypePanel(string

id,

Dictionary<int,int>

dict)

private

void

UpdateHeroTypeItem(string

id,

int

type,

int

count,

bool

newItem

=

false)

private

void

RemoveAllChildItemPanel()

private

void

OnChangePlayerForHeroTypePanelDisplay(string

id,

Dictionary<int,

int>

dict)

}

當(dāng)HeroTypePanelMediator觸發(fā)添加子界面的時(shí)候,會(huì)實(shí)例化一個(gè)HeroTypeItemPanel界面和實(shí)例化其對(duì)應(yīng)的Mediator、Proxy、Command。在HeroTypeItemPanelMediator的構(gòu)造函數(shù)中,通過UIManager獲取UI組件用于使用。public

HeroTypeItemPanelMediator(GameObject

_root,int

_heroTypeIndex)

:

base(string.Format("{0}{1}",

mediatorName,

_heroTypeIndex.ToString()))

{

heroTypeIndex

=

_heroTypeIndex;

root

=

_root;

heroTypeImg

=

UIManager.Instance.GetUI(,

"heroTypeImg_").GetComponent<Image>();

currentCountText

=

UIManager.Instance.GetUI(,

"currentCountText_").GetComponent<TextMeshProUGUI>();

heroTypeNameText

=

UIManager.Instance.GetUI(,

"heroTypeNameText_").GetComponent<TextMeshProUGUI>();

heroTypeCountText

=

UIManager.Instance.GetUI(,

"heroTypeCountText_").GetComponent<TextMeshProUGUI>();

scriptPanel

=

UIManager.Instance.GetUI(,

"scriptPanel_").gameObject;

scriptText

=

UIManager.Instance.GetUI(,

"scriptText_").GetComponent<TextMeshProUGUI>();

scriptMask

=

UIManager.Instance.GetUI(,

"scriptMask_").GetComponent<RectTransform>();

UIManager.Instance.RemoveUI();

MessageMgr.AddMessageListener<object[]>(MessageMgr.MessageType.DisplayHeroTypeScriptPanel,

DisplayHeroTypeScriptPanel);

InitPanel();

}Model層的實(shí)現(xiàn)1)HeroTypePanelProxy創(chuàng)建腳本HeroTypePanelProxy繼承Proxy,ProxyName是該P(yáng)roxy類的索引名稱。在其構(gòu)造函數(shù)中,初始化data并監(jiān)聽更新界面的命令。當(dāng)接收到更新命令,獲取新數(shù)據(jù)后,把數(shù)據(jù)更新到data中。至于View層的更新,可以是Proxy自己在更新data后隨即調(diào)用界面更新方法,或是其它方式通過Command調(diào)用Proxy中的界面更新方法,通過該方法可以調(diào)用Mediator注冊(cè)好的的Notification傳送data數(shù)據(jù)作為參數(shù)進(jìn)行View層的更新。public

class

HeroTypePanelProxy

:

Proxy

{

public

const

string

proxyName

=

"HeroTypePanelProxy";

private

HeroTypePanelData

data;

public

HeroTypePanelProxy()

:

base(proxyName)

{

data=new

Data();

MessageMgr.AddMessageListener<MsgBase>(MessageMgr.MessageType.OnMsgUpdateHeroTypePanel,

OnMsgUpdateHeroTypePanel);

}

public

override

void

OnRemove()

{

MessageMgr.RemoveMessageListener<MsgBase>(MessageMgr.MessageType.OnMsgUpdateHeroTypePanel,

OnMsgUpdateHeroTypePanel);

}

public

void

OnMsgUpdateHeroTypePanel(MsgBase

msgBase)

public

void

OnChangePlayerForHeroTypePanelDisplay(string

id)

}

2)HeroTypePanelDataHeroTypePanelData類的實(shí)例只是數(shù)據(jù)的存放,不做其它操作。public

class

HeroTypePanelData

{

Public

string

id;

public

Dictionary<string

,Dictionary<int,int>>

heroTypeIndexsDict;

public

HeroTypePanelData()

{

HeroTypeIndexsDict=new

Dictionary<string

,Dictionary<int,int>>();

}

}

Command層UpdateHeroTypePanelCommand繼承SimpleCommand,Execute方法實(shí)例化時(shí)便執(zhí)行,該命令執(zhí)行了調(diào)用HeroTypePanelProxy的OnMsgUpdateHeroTypePanel方法,進(jìn)行Model層數(shù)據(jù)的更新。public

class

UpdateHeroTypePanelCommand

:

SimpleCommand

{

public

override

void

Execute(INotification

notification)

{

MsgUpdateHeroTypePanel

data

=

notification.Body

as

MsgUpdateHeroTypePanel;

HeroTypePanelProxy

proxy

=

Facade.RetrieveProxy(HeroTypePanelPxyName)

as

HeroTypePanelProxy;

proxy.OnMsgUpdateHeroTypePanel(data);

}

}

UpdateHeroTypeItemCommand命令進(jìn)行View層數(shù)據(jù)的更新。public

class

UpdateHeroTypeItemCommand

:

SimpleCommand

{

public

override

void

Execute(INotification

notification)

{

HeroTypeItemData

data

=

notification.Body

as

HeroTypeItemData;

SendNotification(NotificationCons.UpdateHeroTypeItemInfoMediator,

data);

}

}ChangePlayerForHeroTypePanelCommand命令調(diào)用方法,執(zhí)行當(dāng)該界面的顯示目標(biāo)ID發(fā)生改變時(shí)的行為。public

class

ChangePlayerForHeroTypePanelCommand

:

SimpleCommand

{

public

override

void

Execute(INotification

notification)

{

HeroTypePanelProxy

proxy

=

Facade.RetrieveProxy(HeroTypePanelPxyName)

as

HeroTypePanelProxy;

proxy.OnChangePlayerForHeroTypePanelDisplay(notification.Body.ToString());

}

}

全局管理層Fa?ade新建類SecondFacade繼承Fa?ade管理第二個(gè)場(chǎng)景內(nèi)的所有UI界面的Fa?ade,方便不同場(chǎng)景內(nèi)UI界面的控制。在SecondFacade中編寫Register方法,做Switch-case判斷不同UI進(jìn)行不同的注冊(cè)內(nèi)容編寫。通過RegisterMediator、RegisterProxy、RegisterCommand進(jìn)行三層的注冊(cè)。removeFun是一個(gè)委托,為委托添加對(duì)應(yīng)的三層注銷方法并存儲(chǔ)到字典內(nèi),當(dāng)該界面移除時(shí),觸發(fā)該委托執(zhí)行,從而進(jìn)行對(duì)應(yīng)三層的注銷。以英雄羈絆UI界面為例,在初始化界面時(shí),F(xiàn)a?ade的注冊(cè)方法執(zhí)行,注冊(cè)進(jìn)行羈絆界面相關(guān)的Mediator、Proxy和Command,并且提前將卸載命令放入委托字典,在卸載UI界面時(shí)調(diào)用委托進(jìn)行卸載相關(guān)類。case

RegisterPanel.HeroTypePanel:

RegisterMediator(new

HeroTypePanelMetiator(root));

RegisterProxy(new

HeroTypePanelProxy());

RegisterCommand(NotificationCons.UpdateHeroTypeItemCommand,

()

=>

{

return

new

UpdateHeroTypeItemCommand();

});

RegisterCommand(NotificationCons.UpdateHeroTypePanelCommand,

()

=>

{

return

new

UpdateHeroTypePanelCommand();

});

RegisterCommand(NotificationCons.ChangePlayerForHeroTypePanelCommand,

()

=>

{

return

new

ChangePlayerForHeroTypePanelCommand();

});

removeFun

+=

()

=>

{

RemoveMediator(HeroTypePanelMetiator.mediatorName);

RemoveProxy(HeroTypePanelPxyName);

RemoveCommand(NotificationCons.UpdateHeroTypeItemCommand);

RemoveCommand(NotificationCons.UpdateHeroTypePanelCommand);

RemoveCommand(NotificationCons.ChangePlayerForHeroTypePanelCommand);

};

AddToRemoveDict(RegisterPanel.HeroTypePanel,removeFun);

break;

游戲資源游戲?qū)傩詳?shù)值游戲的人物是進(jìn)行對(duì)戰(zhàn)的英雄們,英雄們都有著相同的屬性類型(生命,力量,攻速等等),但是不同類型英雄的基礎(chǔ)屬性數(shù)值是不同的;英雄穿戴不同裝備獲得的屬性加成是不同的;不同英雄的上場(chǎng)組合形成的羈絆對(duì)英雄們的加成也是有區(qū)別的。為了更直觀全面地統(tǒng)攬游戲數(shù)值、更便捷地進(jìn)行游戲數(shù)值的修改和完善、更平衡舒適的游戲體驗(yàn),所以使用Excel進(jìn)行游戲數(shù)據(jù)的編輯。先在Excel表格中按照預(yù)先規(guī)定好的格式編寫好Excel表格。分別對(duì)英雄屬性、羈絆屬性、裝備屬性的表格進(jìn)行數(shù)據(jù)填寫。圖4-2游戲人物數(shù)值設(shè)定圖4-3羈絆屬性的設(shè)定圖4-4裝備的屬性設(shè)定在數(shù)據(jù)設(shè)定完成后Excel的數(shù)據(jù)保存為xlsx文件,通過LitJson類庫(kù),將不同表格依托不同的模板類轉(zhuǎn)換成對(duì)應(yīng)的json文件。json文件就是游戲程序可以直接讀取的游戲數(shù)據(jù),不同的模板類是表格格式設(shè)定的依托。表格的第2行的是模板類的屬性名稱,第3行代表屬性的類型,由此可以形成xlsx數(shù)據(jù)于C#類的轉(zhuǎn)換。xlsx數(shù)據(jù)轉(zhuǎn)C#類的過程:獲取要轉(zhuǎn)換Excel表格數(shù)據(jù)和對(duì)應(yīng)的模板類獲取模板類實(shí)例判斷模板類實(shí)例屬性并填入表格數(shù)據(jù)將該實(shí)例保存成json文件當(dāng)需要加載數(shù)據(jù)時(shí),通過json文件轉(zhuǎn)換成模板類(屬性類) private

static

void

ReadSingleSheet(Type

type,

DataTable

dataTable,

string

jsonPath)

{

int

rows

=

dataTable.Rows.Count;

int

Columns

=

dataTable.Columns.Count;

//UnityEngine.Debug.Log(rows

+

"行,"

+

Columns

+

"列");

//

工作表的行數(shù)據(jù)

DataRowCollection

collect

=

dataTable.Rows;

//

xlsx對(duì)應(yīng)的數(shù)據(jù)字段,規(guī)定是第二行

string[]

jsonFileds

=

new

string[Columns];

//

要保存成Json的obj

List<object>

objsToSave

=

new

List<object>();

for

(int

i

=

0;

i

<

Columns;

i++)

{

jsonFileds[i]

=

collect[1][i].ToString();

UnityEngine.Debug.Log(jsonFileds[i]);

}

//

從第三行開始

for

(int

i

=

3;

i

<

rows;

i++)

{

//

生成一個(gè)實(shí)例

object

objIns

=

type.Assembly.CreateInstance(type.ToString());

for

(int

j

=

0;

j

<

Columns;

j++)

{

//

獲取字段

FieldInfo

field

=

type.GetField(jsonFileds[j]);

if

(field

!=

null)

{

object

value

=

null;

try

//

賦值

{

value

=

Convert.ChangeType(collect[i][j],

field.FieldType);

}

catch

(InvalidCastException

e)

{

Console.WriteLine(e.Message);

string

str

=

collect[i][j].ToString();

string[]

strs

=

str.Split(',');

int[]

ints

=

new

int[strs.Length];

for

(int

k

=

0;

k

<

strs.Length;

k++)

{

ints[k]

=

int.Parse(strs[k]);

}

value

=

ints;

}

field.SetValue(objIns,

value);

}

else

{

UnityEngine.Debug.LogFormat("有無(wú)法識(shí)別的字符串:{0}",

jsonFileds[j]);

}

}

objsToSave.Add(objIns);

}

//

保存為Json

string

content

=

JsonMapper.ToJson(objsToSave);

SaveFile(content,

jsonPath);

}

英雄屬性的模板類如下,存儲(chǔ)英雄的基礎(chǔ)屬性數(shù)據(jù):

public

class

HeroInfoTMP

{

public

int

index;

public

string

type_name;

public

string

hero_name;

public

int

max_life;

public

int

mana_recover_value;

public

int

power;

public

int

spell_power;

public

int

power_defend;

public

int

spell_defend;

public

int

atk_cd;

public

bool

isNearAtk;

public

int

atk_distance;

public

int

price;

public

string

type;

}

每個(gè)不同的英雄的基礎(chǔ)屬性都是不同數(shù)值的模板類,為了便于管理,創(chuàng)建HeroInfoMgr單例類作為英雄屬性管理類,存儲(chǔ)了所有英雄的基礎(chǔ)屬性類型,提供提供使用索引查找某個(gè)英雄屬性的方法,便于游戲開發(fā)。以同樣的方式創(chuàng)建HeroTypeMgr和EquipInfoMgr作為英雄羈絆管理類和裝備管理類。準(zhǔn)備游戲資源人物模型作為英雄在游戲中的GameObject,為AI腳本、尋路腳本及其它繼承Mono(需要掛載在場(chǎng)景物體)的腳本提供搭乘實(shí)體。英雄在攻擊和釋放技能時(shí),都會(huì)生成不同的特效、觸發(fā)不同的音效。在英雄攻擊時(shí)實(shí)例化到場(chǎng)景內(nèi)。為了更好地區(qū)分各個(gè)資源,以及方便使用Addressables進(jìn)行調(diào)用。必須規(guī)范化地修改Prefabs的名稱(該名稱是英雄屬性填寫的依托),并添加可尋址標(biāo)記。圖4-5游戲人物模型圖4-6技能預(yù)設(shè)命名資源的管理Unity3D里有場(chǎng)景、模型、聲音、視頻、文本等許多不同類型的游戲資源,為了方便加載使用,我們需要對(duì)這些游戲資源進(jìn)行很好地管理。在之前的資源管理行為上,我們需要把資源添加標(biāo)記并打包成AssetBundle包,在加載資源時(shí),解壓AssetBundle包后讀取資源,在這種方式的操作過程中,繁瑣的操作步驟極易產(chǎn)生錯(cuò)誤。一個(gè)小小的錯(cuò)誤可能會(huì)導(dǎo)致資源無(wú)法加載,而且難以發(fā)現(xiàn)并修正。Unity3D官方也因此推出了新的資源管理系統(tǒng)Addressables。Addressables是對(duì)AssetBundle的高層封裝。優(yōu)化了游戲資源的打包和加載,極大地提升了游戲開發(fā)的整體效率。Addressables會(huì)對(duì)實(shí)例化的資源的個(gè)數(shù)進(jìn)行標(biāo)記,當(dāng)實(shí)例化的資源減少時(shí),減少標(biāo)記數(shù),如果標(biāo)記數(shù)為零,表示沒有該資源的引用,就會(huì)卸載掉該資源的內(nèi)存,從而也幫助開發(fā)者實(shí)現(xiàn)了內(nèi)存的優(yōu)化管理。由于Addressables并非Unity3D內(nèi)置的系統(tǒng),所以需要進(jìn)行導(dǎo)入,打開Unity3D的Window>PackageManager標(biāo)簽找到Addressable包后進(jìn)行導(dǎo)入。圖4-7Addressables包導(dǎo)入添加一個(gè)資源到Addressables時(shí),打開資源的Inspector界面,打上Addressables標(biāo)記并修改標(biāo)記名稱。在Addressables窗口中就會(huì)出現(xiàn)對(duì)應(yīng)的資源,我們還可以為不同的資源添加不同的標(biāo)簽。在資源加載時(shí),就是根據(jù)標(biāo)記名稱和標(biāo)簽進(jìn)行不同資源或是不同的資源包進(jìn)行的。圖4-8Addressables的標(biāo)記和標(biāo)簽要對(duì)標(biāo)記好的資源進(jìn)行加載時(shí),引用UnityEngine.AddressableAssets,Addressables類提供了多種不同的加載方式。通過Addressables.LoadAssetsAsync可以異步地加載多個(gè)labels下的同類型資源。Addressables.LoadAssetsAsync<T>(labels,

null,

loadmode).Completed

+=

(handles)

=>

{

handle

=

handles;

foreach

(var

item

in

handle.Result)

{

result.Add(item);

}

if

(++loadCounter

>=

loadCount)

{

loadFinish();

}

};

人物動(dòng)畫控制器Unity3D中Animator系統(tǒng)可以對(duì)游戲的模型動(dòng)畫進(jìn)行控制和管理。新建一個(gè)AnimatorController作為一個(gè)英雄的動(dòng)畫控制器,添加Idle、Move、Skill、Atk、Death四種狀態(tài)。將Idle狀態(tài)設(shè)置為默認(rèn)狀態(tài),設(shè)置好狀態(tài)間的過度條件:Move、Skill、Atk狀態(tài)只能與Idle狀態(tài)進(jìn)行轉(zhuǎn)換,任何狀態(tài)都能進(jìn)入死亡狀態(tài)。圖4-9動(dòng)畫控制器邏輯連接當(dāng)動(dòng)畫控制器進(jìn)行不同的狀態(tài)時(shí),觸發(fā)對(duì)應(yīng)的不同角色動(dòng)畫。為了區(qū)分游戲人物的個(gè)性,每個(gè)游戲的人物動(dòng)畫應(yīng)是不同的??梢允褂肁nimator系統(tǒng)中的AnimatorOverrideController對(duì)基礎(chǔ)的AnimatortControll進(jìn)行覆蓋,這樣就可以在不會(huì)改變?cè)械膭?dòng)畫間的邏輯情況下,改變具體的模型動(dòng)畫作為另一個(gè)英雄的動(dòng)畫控制器。圖4-10動(dòng)畫控制器的覆蓋游戲人物的創(chuàng)建游戲中使用單例類HeroMgr作為英雄的管理類,負(fù)責(zé)英雄的創(chuàng)建和管理。在英雄購(gòu)買UI界面進(jìn)行英雄購(gòu)買后,會(huì)創(chuàng)建相應(yīng)英雄到游戲場(chǎng)景中的等待區(qū)域供玩家操作。通過HeroMgr的CreateHeroToWait方法創(chuàng)建英雄,通過英雄索引加載對(duì)應(yīng)的屬性,依托英雄屬性的內(nèi)容,通過Addressables異步加載模型和技能,為英雄添加不同的AI控制腳本腳本等等。public

void

CreateHeroToWait(string

id,

int

hero_type_index)

{

//根據(jù)編號(hào)獲得英雄屬性信息

HeroInfoTMP

heroInfoTmp

=

heroInfoMag.GetHeroModel(hero_type_index);

string

model_name

=

heroInfoTmp.heroModel_name;

//加載英雄模型

ResManager.LoadInstantiateAsync(model_name,

hero_model

=>

{

hero_model.AddComponent<AIPath>();

hero_model.AddComponent<AIPathFinder>();

//加入字典

hero_dict[id].Add(hero_model);

//不同歸屬英雄添加不同的基礎(chǔ)腳本

string[]

ids

=

id.Split('_');

if

(id.Equals(NetManager.id)

||

ids[0].Equals(NetManager.id))

(GameManager.AddComponent(hero_model,

"HeroPositive")

as

HeroPositive).OnInit(id,

(sbyte)(indexTarget[id]++),

heroInfoTmp);

else

(GameManager.AddComponent(hero_model,

"HeroNegative")

as

HeroNegative).OnInit(id,

(sbyte)(indexTarget[id]++),

heroInfoTmp);

//英雄的血條,其它特效

ResManager.LoadInstantiateAsync(MainDefine.LifeBarPrefab,

hero_life_bar

=>

{……});

});

//在等待區(qū)放置hero

bool

isPosi

=

true;

PlacePlaneFind

parentPlane

=

PlacePlaneMag.placePlaneDict[id];

PlacePlaneFind

placePlaneTmp

=

parentPlane;

if

(progressMag.gameProgressState

!=

(byte)ProgressMag.GameProgressState.PlaceState)

{

for

(int

i

=

0;

i

<

progressMag.playerId.Count;

i++)

{

if

(NetManager.id.Equals(progressMag.playerId[i])

&&

!progressMag.enemyId[i].Equals("posi"))

{

isPosi

=

false;

placePlaneTmp

=

PlacePlaneMag.placePlaneDict[progressMag.enemyId[i]];

}

}

}

……

});

}

AI控制腳本游戲中的人物主要是自動(dòng)戰(zhàn)斗或者在等待區(qū)域的英雄們。玩家在游戲中扮演的是決策者,因此在游戲創(chuàng)建英雄時(shí)就會(huì)為英雄添加AI腳本,以便游戲中的英雄在戰(zhàn)斗階段進(jìn)行自動(dòng)戰(zhàn)斗。由于采用了單一客戶端進(jìn)行邏輯演算,所以AI腳本也會(huì)有主動(dòng)和被動(dòng)之分。使用HeroBase作為不同類型AI腳本的基類,保存了腳本對(duì)應(yīng)英雄的屬性數(shù)據(jù)、組件引用和其它控制腳本的引用等,為對(duì)單個(gè)英雄的相關(guān)操作提供了方法。HeroBase創(chuàng)建了虛函數(shù)方法表示英雄在不同時(shí)期的邏輯,方便控制英雄在其生命周期內(nèi)的行為。public

class

HeroBase

:MonoBehaviour

{

public

string

id

=

"";

private

sbyte

index;

public

sbyte

Index{}

public

string

only_index;//id-index

protected

float

syncInterval;//同步幀率

protected

bool

isNormalAtking

=

false;

protected

bool

isSkilling

=

false;

public

short

originalPos;//初始位置代碼:index*10+1/0

:準(zhǔn)備/等待

public

sbyte

ready_index_map=-1;//在映射數(shù)組中的位置,用于戰(zhàn)斗尋路

public

int

ready_index_map_before=-1;//預(yù)先占據(jù)位置

public

bool

canLevelUp;

public

HeroInfo

heroInfo;

public

AIPathFinder

aiPath;

public

EquipBase[]

equipArray;

public

Transform

target_enemy;

public

HeroLifeBarCtr

lifeBarCtr;

public

List<Transform>

enemy_list;

private

OtherFXCtr

fxCtr;

public

OtherFXCtr

otherFxCtr

protected

Animator

ani;

protected

AnimationClip[]

clips;

protected

Collider

col;

public

virtual

void

Init(HeroInfo

_heroInfo,string

_id,sbyte

_index)

……

}

主動(dòng)AI基礎(chǔ)腳本HeroBasePositive:繼承于HeroBase,在主機(jī)客戶端創(chuàng)建英雄時(shí)添加的AI腳本。負(fù)責(zé)在此客戶端執(zhí)行英雄的邏輯決策、在規(guī)定的時(shí)間間隔發(fā)送腳本對(duì)應(yīng)英雄的位置、狀態(tài)信息到其它被動(dòng)客戶端內(nèi)進(jìn)行同步。HeroBasePosition發(fā)送同步消息方法如下:public

void

SyncUpdate()

{

//時(shí)間間隔判斷

if

(Time.time

-

lastSendSyncTime

<

syncInterval)

{

return;

}

lastSendSyncTime

=

Time.time;

//發(fā)送同步協(xié)議

MsgMgr.SendMsgSyncTransform(id,transform,

(sbyte)(ani.GetBool("Move")

?

1

:

0),ready_index_map==-1?UpdateSelfReadyMapIndex():ready_index_map);

}

被動(dòng)AI基礎(chǔ)腳本HeroBaseNegative:繼承于HeroBase,在主機(jī)客戶端以外的客戶端創(chuàng)建英雄時(shí)添加的AI腳本,不會(huì)進(jìn)行游戲人物的邏輯決策,只是通過解析接收到的協(xié)議對(duì)場(chǎng)景中的人物的行為狀態(tài)進(jìn)行調(diào)整。HeroBaseNegative的接收并解析人物移動(dòng)協(xié)議的方法如下: public

void

OnMsgSyncTransform(MsgBase

msgBase)

{

MsgSyncTransform

msg

=

(MsgSyncTransform)msgBase;

if

(msg.id.Equals(id)&&msg.index.Equals(Index)&&heroInfo.isPositive==false)

{

ani.SetBool("Move",

msg.move.Equals(0)

?

false

:

true);

//預(yù)測(cè)位置

Vector3

pos

=

new

Vector3(msg.x

,

msg.y,

msg.z);

Vector3

rot

=

new

Vector3(transform.rotation.x,

msg.ey,

transform.rotation.z);

forecastPos

=

pos

+

2

*

(pos

-

lastPos);

forecastRot

=

rot

+

2

*

(rot

-

lastRot);

//更新

lastPos

=

pos;

lastRot

=

rot;

forecastTime

=

Time.time;

PlacePlaneFind

plane

=

PlacePlaneMag.placePlaneDict[PlacePlaneMag.GetTargetPlaneId(msg.id)];

if

(ready_index_map

!=

-1)

{

plane.all_ready_place_map[ready_index_map]

=

null;

}

ready_index_map

=

msg.ready_index_map;

plane.all_ready_place_map[ready_index_map]

=

only_index;

}

}

游戲人物的邏輯決策只在主動(dòng)AI類HeroBasePositive的有限狀態(tài)機(jī)內(nèi)進(jìn)行判斷和控制,在HeroBasePosition中初始化有限狀態(tài)機(jī),為狀態(tài)機(jī)添加多個(gè)不同時(shí)刻的狀態(tài),對(duì)應(yīng)HeroBase中的不同行為。通過SetCurrentIndex方法使?fàn)顟B(tài)機(jī)進(jìn)行空狀態(tài),為運(yùn)行做準(zhǔn)備。public

void

InitFsmsys()

{

fsmsys

=

new

FSMSystemN();

NullState

nullState

=

new

NullState(this);

FightStateBase

fightStateBase

=

new

FightStateBase(this);

IdleState

idleState

=

new

IdleState(this);

MoveState

moveState

=

new

MoveState(this);

AtkState

atkState

=

new

AtkState(this);

DeathState

deathState

=

new

DeathState(this);

fsmsys.AddState(nullState);

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說明,都需要本地電腦安裝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ù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 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)論