基于Unity3D的3D橫版沙盒游戲的開發(fā)與實現(xiàn)_第1頁
基于Unity3D的3D橫版沙盒游戲的開發(fā)與實現(xiàn)_第2頁
基于Unity3D的3D橫版沙盒游戲的開發(fā)與實現(xiàn)_第3頁
基于Unity3D的3D橫版沙盒游戲的開發(fā)與實現(xiàn)_第4頁
基于Unity3D的3D橫版沙盒游戲的開發(fā)與實現(xiàn)_第5頁
已閱讀5頁,還剩57頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領

文檔簡介

摘要在二十一世紀的現(xiàn)在,據(jù)第一個電子游戲的出現(xiàn)已經(jīng)過了60年以上,在這期間隨著科技的迅速發(fā)展,電子游戲的技術也得到了迅速的發(fā)展,游戲的內(nèi)容和類型開始變得多樣。游戲的自由度越高時游戲類型就越接近類似沙盒游戲的游戲類型。沙盒游戲能夠包含格斗、射擊、駕駛、養(yǎng)成以及冒險等多種不同的游戲要素。沙盒游戲的高自由度甚至可以創(chuàng)造或者毀滅整個游戲世界。目前個人認為最成功的沙盒游戲分別是3D的《我的世界》和2D的《泰拉瑞亞》,二者憑借廣闊的世界,豐富的游戲因素和極高的自由度吸引了大批玩家來到沙盒世界建造屬于自己的世界。本論文是基于Unity3D探索橫版的3D沙盒游戲的開發(fā)與實現(xiàn),既實現(xiàn)2.5D的沙盒游戲。游戲的設計方向是實現(xiàn)一般沙盒游戲擁有的游戲元素,著重在于沙盒世界的地圖的隨機生成,橫版下的建造模塊的探索。關鍵詞:Unity3D沙盒游戲2.5D游戲隨機地圖Abstract□Inthe21stcentury,morethan60yearshavepassedsincethefirstvideogameappeared.Duringthisperiod,withtherapiddevelopmentoftechnology,thetechnologyofvideogameshasalsobeenrapidlydeveloped,andthecontentandgenreofthegamehavebegun.Becomediverse.Thehigherthedegreeoffreedomofthegame,thecloserthegametypeistoagametypesimilartoasandboxgame.Sandboxgamescancontainmanydifferentgameelementssuchasfighting,shooting,driving,trainingandadventure.Thehighdegreeoffreedomofsandboxgamescanevencreateordestroytheentiregameworld.Atpresent,Ipersonallythinkthatthemostsuccessfulsandboxgamesare3D"MyWorld"and2D"Terraria".Thetwohaveattractedalargenumberofplayerswiththeirvastworld,richgamefactorsandextremelyhighdegreesoffreedom.Gotothesandboxworldtobuildyourownworld.Thispaperisbasedonthedevelopmentandimplementationofthe3DsandboxgameofUnity3Dexplorationhorizontalversion,whichistherealizationof2.5Dsandboxgame.Thedesigndirectionofthegameistorealizethegameelementsownedbygeneralsandboxgames,focusingontheautomaticgenerationofmapsinthesandboxworldandtheexplorationofconstructionmodulesundertheplane.□□Keywords:Unity3DSandboxgame2.5DgameRandommap廣東東軟學院本科生畢業(yè)設計(論文)目錄1緒論 游戲需求分析3.1游戲基本介紹開始游戲時,在UI動畫結束后,玩家出現(xiàn)在一片廢棄區(qū)域的傳送通道,玩家可以自由改造初始的廢棄區(qū)域,玩家可以通過傳送通道去往其它隨機生成的地圖上,應付當?shù)氐姆烙鶛C制獲取在初始區(qū)域建造物品的資源。游戲中沒有真實意義上的游戲結束,在玩家的生命歸零后會播放玩家倒地動畫,在初始地圖復活,所有的隨機地圖在探索結束離開后都會消失。3.2需求分析當今快節(jié)奏的社會中,大多數(shù)人的吃穿住行等最基礎的物質(zhì)上的需求基本得到了滿足,人們開始更多的尋求精神上的需求。書籍、游戲、電影和動漫這類的精神上的需求得到了大多數(shù)人的歡迎。游戲更是被人們廣泛接受的文化之一。在如今快節(jié)奏的生活中,人們或許在忙碌之余想靜靜的放松并暫時忘記現(xiàn)實世界的煩惱的時候,沙盒游戲是不錯的選擇。在沙盒游戲中,游戲世界會基于一定的模板生成一個相對隨機的世界,來到這個游戲世界的玩家擁有最大自由度去選擇如何在這個虛擬的世界生活,并且可以隨時保存并結束游戲投身到現(xiàn)實生活中去。4游戲設計與實現(xiàn)4.1UI界面游戲的菜單界面以簡潔明了為主,基本上采用了黑白設計并添加動畫控制消失和出現(xiàn)以便于在觀感上變得平滑,如圖1左右兩邊的形狀分別對應著退出游戲和重新開始游戲,中間的齒輪可以觸發(fā)菜單的關閉動畫,下方的秒表圖案用來保存游戲,左下方音量標志控制游戲聲音的有無,另一邊的是游戲的操作說明。圖4-2是開始游玩時的界面,紅色的機器人圖標代表Player的生命值,藍色的代表能量,藍齒輪表示目前已有的資源數(shù)量。右下方的齒輪組會在建造模式下從下方移動到當前位置,每個齒輪代表可以制造的物體,齒輪的右下角代表當前可造數(shù)量。圖1菜單界面圖2游戲界面4.1.1UI介紹Unity3D的UI制作是非常方便的,在窗口Hierarchy空白處右鍵→UI→Panel即可在Hierarchy窗口自動創(chuàng)建Canvas和EventSystem并在Canvas里生成Panel,EventSystem在Hierarchy窗口里基本只能有一個,創(chuàng)建的UI基本都是Canvas的子節(jié)點。UI的基本類型有image、Text、Button、Panel、Solid等多種類型。4.1.2主界面UI制作主界面UI主的制作主要使用了Unity3D自帶的Button組件,Image組件和Animator組件來制作。完成圖1菜單畫面的基礎布置后,可以考慮加入Animator制作一些簡單的UI動畫。在Canvas里將相關的UI放到同一個父節(jié)點“Closing”下面,之后在父節(jié)點的組件里通過AddComponent添加Animator組件。之后再根據(jù)自己的創(chuàng)意制作動畫。全程除了Button的OnClick()事件要寫些相關代碼外都可以在編輯界面完成。Button按鈕相關代碼usingUnityEngine.SceneManagement;publicvoidRestScene1(){//當前場景重新加載SceneManager.LoadScene(SceneManager.GetActiveScene().name);}publicvoidGameQuit(){ //退出游戲Application.Quit();}publicvoidClosingEnd(){//關閉UIif(!Player_control.player_Control.isDie){anim.SetBool(ClosingStarid,false);anim.SetBool(ClosingEndid,true);}}主要是通過將初始的保存地圖的二維數(shù)組清空,遍歷每一個初始場景的物體創(chuàng)建時的信息再保存。publicvoidMainMapSave(){//保存初始地圖MainMapGrid=newint[mapsize,mapsize];if(gamemap[5].childCount!=0){for(inti=0;i<gamemap[5].childCount;i++){int_x=gamemap[5].GetChild(i).GetComponent<BlockMessage>().x;int_y=gamemap[5].GetChild(i).GetComponent<BlockMessage>().y;MainMapGrid[_x,_y]=1;}for(inti=0;i<gamemap[7].childCount;i++){int_x=gamemap[7].GetChild(i).GetComponent<BlockMessage>().x;int_y=gamemap[7].GetChild(i).GetComponent<BlockMessage>().y;MainMapGrid[_x,_y]=5;}}Debug.Log("主地圖保存");}4.1.3血條&藍條圖3中顯示的機器人圖像的紅藍UI分別是生命值和能量值主要是應用UI組件Image完成。組件Image中參數(shù)設置ImageType→Filled,F(xiàn)illMethod→Vertical之后就可以通過調(diào)節(jié)FillAmount的值實現(xiàn)血藍條的增減,如圖3。FillAmount的值最小為0最大為1,可以通過將當前的生命值除去最大的生命值來獲得FillAmount的值。比如FillAmount=角色當前的數(shù)值/角色最大生命值。圖34.1.4齒輪UI藍色齒輪表示游戲中玩家獲取的資源量,主要是通過擊碎水晶來增加。資源數(shù)量是通過Text組件里的Text來顯示,代碼上通過獲取Text組件“BaseCount”之后再將int類型的資源數(shù)量“Counter”轉(zhuǎn)換成類型string,代碼如下BaseCount.text=GM.gM.Counter.ToString("0");白色齒輪用來直觀表示當前選擇要建造的物體和能夠建造的數(shù)量。4.2地圖4.2.1地圖生成地圖采用二維數(shù)組來實現(xiàn),先通過Random.Range(intmin,intmax)隨機生成一個40*40的由0和1組成的二維數(shù)組int[,],之后再通過填補和刪除逐漸得到想要的效果,之后再根據(jù)二維數(shù)組的值生成物體,并將每個物體放進物體數(shù)組GameObject[,],這樣基本可以實現(xiàn)基本的物體刪除和創(chuàng)建,在地圖數(shù)組生成后經(jīng)過填補,刪除完成之后遍歷數(shù)組查找能夠添加水晶的位置接著按照二維數(shù)組創(chuàng)建游戲地圖。如初始地圖4。圖副本隨機地圖5。二維地圖生成代碼如下usingUnityEngine;publicclassCreateTerrain:MonoBehaviour{publicstaticCreateTerraincreateTerrain;publicGameObjectrock;//保存生成的兩種水晶類型publicGameObject[]crystalsv;//生成地圖位置publicTransform[]gamemap;//傳送通道publicGameObjectJumpTuunnel;//數(shù)組大小publicintmapsize=40;//副本地圖二維數(shù)組publicint[,]mapgrid;//主地圖數(shù)組publicint[,]MainMapGrid;//副本地圖生成的物體池publicGameObject[,]objgrid;//主地圖生成的物體池publicGameObject[,]Mainobjgrid;voidUpdate(){//判斷是否需要調(diào)用主地圖CreateMainMap();檢測隨機副本的數(shù)組是否被清空,如果被清空則會開始銷毀隨機副本,并生成新的隨機副本地圖,一般在玩家離開隨機地圖后調(diào)用。if(mapgrid==null){if(gamemap[0].childCount!=0){for(inti=0;i<gamemap[0].childCount;i++){Destroy(gamemap[0].GetChild(0));}}CreateMap(gamemap[0],gamemap[1]);}}//創(chuàng)建地圖CreateMap()主要用來生成隨機地圖,兩個參數(shù)分別代表生成的巖石和水晶的父節(jié)點。該函數(shù)調(diào)用的時候會檢測隨機副本地圖是否是空數(shù)組,不是則直接調(diào)用生成地圖函數(shù)CreateMap_execute(),是的情況下則會重新生成新的隨機副本地圖數(shù)組,經(jīng)過多次ResetMap_del()和ResetMap_fill()的刪補后ResetMap_delone()消除孤立的個體CreateCrystalsv()則會尋找數(shù)組地圖上滿足生成水晶條件的位置并概率生成,Createtunnel()負責在數(shù)組地圖基本成型的時候封邊之前找出傳送通道的位置,之后執(zhí)行生成函數(shù)CreateMap_execute()。二維數(shù)組地圖生成函數(shù)CreateMapGrid(int[,]mapgrid),該函數(shù)通過for循環(huán)和隨機數(shù)生成大致的二維數(shù)組模型,之后通過函數(shù)RestMap_del()刪除,函數(shù)RestMap_fill()填充,函數(shù)RestMap_delone刪除孤立點,完成基本框架,之后遍歷數(shù)組添加水晶敵人和傳送通道位置。voidCreateMapGrid(int[,]mapgrid){for(inti=0;i<mapsize;i++){for(intj=0;j<mapsize;j++){if(Random.Range(1,100)>=40){mapgrid[i,j]=1;}else{mapgrid[i,j]=0;}}}//優(yōu)化地圖ResetMap_del(mapgrid);ResetMap_fill(mapgrid);ResetMap_del(mapgrid);ResetMap_delone(mapgrid);//生成水晶CreateCrystalsv(mapgrid);//生成傳送門Createtunnel(mapgrid);//封邊f(xié)or(inti=0;i<mapsize;i++){if(mapgrid[0,i]==0){mapgrid[0,i]=1;}if(mapgrid[i,0]==0){mapgrid[i,0]=1;}if(mapgrid[i,mapsize-1]==0){mapgrid[i,mapsize-1]=1;}if(mapgrid[mapsize-1,i]==0){mapgrid[mapsize-1,i]=1;}}}傳送通道的位置生成是通過不斷隨機出地圖數(shù)組中一個當前位子沒有其它物體的坐標(x,y)符合條件后開始判斷在數(shù)組中(x-2,y)+(x+2,y)+(x,y-2)+(x,y+2)值的和為零的情況下生成傳送通道并將坐標(x,y)為中心的3*3的九宮格,除坐標外其他坐標的值變更為-1,變成不可使用區(qū)域,不等于零的情況下在開始下一輪的隨機,直到找到符合條件的位置循環(huán)結束。//挑選位置生成傳送門voidCreatetunnel(){int_x;int_y;for(inti=0;i<i+1;i++){_x=Random.Range(2,38);_y=Random.Range(2,38);if(mapgrid[_x,_y]==0){int_sum=mapgrid[_x-2,_y]+mapgrid[_x+2,_y]+mapgrid[_x,_y-2]+mapgrid[_x,_y+2];if(_sum==0){for(intk=_x-2;k<_x+3;k++){for(intl=_y-2;l<_y+3;l++){mapgrid[k,l]=-1;}}mapgrid[_x,_y]=4;break;}}}}//生成主地圖函數(shù)CreateMainMap()主要負責在場景里按照主地圖的二維數(shù)組創(chuàng)建對應的主地圖,由于主地圖和副本地圖同樣在同一個Scene里,在生成完物體后變動主地圖父節(jié)點位置以防和副本地圖位置重合。publicvoidCreateMainMap(){//如果未生成主地圖if(gamemap[5].childCount==0){//判斷主地圖數(shù)組是否為空if(MainMapGrid.Length!=0){//生成地圖CreateMap_execute(MainMapGrid,Mainobjgrid,gamemap[5],gamemap[6]);gamemap[5].position=newVector3(0,70,0);gamemap[6].position=newVector3(0,70,0);gamemap[7].position=newVector3(0,70,0);}}}//地形生成CreateMap_execute()負責通過數(shù)組遍歷數(shù)組里的值在場景里生成數(shù)組地形。這里是后期要重點改進的地方,如果游戲中的可生成物體越多這里編寫的代碼便會越越多越顯的臃腫,不利于后期的代碼維護。for(inti=0;i<mapsize;i++){for(intj=0;j<mapsize;j++){switch(_mapgrid[i,j]){//地形框架case1:_objgrid[i,j]=Instantiate(rock,newVector3(i,j,0),Quaternion.identity,_rocktr);_objgrid[i,j].GetComponent<BlockMessage>().x=i;_objgrid[i,j].GetComponent<BlockMessage>().y=j;break;//攻擊型水晶case2://向右if(_mapgrid[i+1,j]==1){_objgrid[i,j]=Instantiate(crystalsv[0],newVector3(i,j,0),Quaternion.Euler(0f,0f,90f),_crytr);_objgrid[i,j].GetComponent<CryNews>().cryX=i;_objgrid[i,j].GetComponent<CryNews>().cryY=j;continue;}//向左if(_mapgrid[i-1,j]==1){_objgrid[i,j]=Instantiate(crystalsv[0],newVector3(i,j,0),Quaternion.Euler(0f,0f,-90f),_crytr);_objgrid[i,j].GetComponent<CryNews>().cryX=i;_objgrid[i,j].GetComponent<CryNews>().cryY=j;continue;}//向上if(_mapgrid[i,j+1]==1){_objgrid[i,j]=Instantiate(crystalsv[0],newVector3(i,j,0),Quaternion.Euler(0f,0f,180f),_crytr);_objgrid[i,j].GetComponent<CryNews>().cryX=i;_objgrid[i,j].GetComponent<CryNews>().cryY=j;continue;}//向下if(_mapgrid[i,j-1]==1){_objgrid[i,j]=Instantiate(crystalsv[0],newVector3(i,j,0),Quaternion.Euler(0f,0f,0f),_crytr);_objgrid[i,j].GetComponent<CryNews>().cryX=i;_objgrid[i,j].GetComponent<CryNews>().cryY=j;continue;}break;………………default:break;}}}case2:這里的四個if語句是利用數(shù)組來判斷生成的水晶方向。數(shù)組的刪補操作基本都要遍歷數(shù)組,找到每個數(shù)組成員的(x,y)值獲得上下左右的值,判斷是否滿足條件。比如這里有一個5*5的二維數(shù)組Y+211010y+100010y11101y-100011y-200110y/xx-2x-1xx+1x+2以坐標為(x,y)的點來算,點(x,y)的周圍的8個點合計值為3,小于5之后(x,y)的值會從1變?yōu)?。水晶的生成則是判斷點(x,y)的值是否為1,之后遍歷上下左右,有值為0的情況下就有幾率將0替換成3或4。//填補privatevoidResetMap_fill(){for(inti=0;i<mapsize;i++){for(intj=0;j<mapsize;j++){//如果空物體位置周圍的方塊數(shù)大于5則填補,物塊周圍方塊數(shù)在4以內(nèi)則消去if(mapgrid[i,j]==0){//Debug.Log(sun_b);if(GetObjSideNumber(i,j)>=5){mapgrid[i,j]=1;}}}}}//在地圖數(shù)組生成水晶的位置2/3生成攻擊水晶,1/3生成能量水晶voidCreateCrystalsv(){for(inti=1;i<mapsize-1;i++){for(intj=1;j<mapsize-1;j++){if(mapgrid[i,j]==1){if(mapgrid[i+1,j]==0&&Random.Range(0,10)<=1){if(Random.Range(0,3)>0)mapgrid[i+1,j]=2;elsemapgrid[i+1,j]=3;}if(mapgrid[i-1,j]==0&&Random.Range(0,10)<=1){if(Random.Range(0,3)>0)mapgrid[i-1,j]=2;elsemapgrid[i-1,j]=3;}if(mapgrid[i,j+1]==0&&Random.Range(0,10)<=1){if(Random.Range(0,3)>0)mapgrid[i,j+1]=2;elsemapgrid[i,j+1]=3;}if(mapgrid[i,j-1]==0&&Random.Range(0,10)<=1){if(Random.Range(0,3)>0)mapgrid[i,j-1]=2;elsemapgrid[i,j-1]=3;}}elsecontinue;}}}}圖4初始地圖圖5隨機地圖4.3玩家4.3.1玩家設計玩家模型來源于AssetStore資源包RobotKyle里的機器人模型,模型可以通過綁定骨骼,如圖6。玩家模型綁好骨骼后導入項目前最好在Hierarchy里新建一個空物體Player,之后將玩家模型放到空物體里,調(diào)整參數(shù)后保存為預制體,方便后期調(diào)整。Mixamo同樣可以尋找并下載角色動畫。圖6玩家和骨骼4.3.2玩家物理效果玩家的物理效果的實現(xiàn)沒有使用碰撞器和剛體的組合,而用的是Unity3D自帶的玩家控制器組件CharacterController。本次課題曾嘗試用過膠囊、正方形的碰撞器,雖然原理上面差不多,但是在實際的場景里有些麻煩的問題,膠囊形剛體在場景里移動的時候會有細小的抖動,換成方塊形的物體則是會有被地面卡住的現(xiàn)象,如果追求更好的交互效果,比較適合用網(wǎng)格碰撞器GenerateColliders。網(wǎng)格碰撞器是一種復雜的、貼合于模型結構的碰撞器,能夠達到很好的交互效果,但是同時消耗大量的計算機資源,影響場景表現(xiàn)性能REF_Ref38104820\r\h[5]。組件CharacterController能夠解決移動的時候的卡頓問題,但是Unity3D自帶的物理下落效果有些不盡人意,而且CharacterController組件上默認啟用了剛體效果,雖然一般可以通過Edit→ProjectSettings→Physics里的Gravity調(diào)整剛體的重力參數(shù)來決定玩家的下落速度,但是當視野寬廣的時候,下落的效果沒達到預期效果。本課題解決辦法是在判斷玩家離開地面的時候添加一個不斷增長的垂直向下的速度velocity.y+=gravity*Time.deltaTime,在跳躍的時候用物理的跳躍公式,速度V=√(jumpHeight*-2f*grivaty)即velocity.y=Mathf.Sqrt(jumpHeight*-2f*gravity)。由于玩家在空中的時候,向下的速度就會不斷增大,所以在玩家接觸地面時強制讓向下的速度變?yōu)?.0f。publicCharacterControllerCC;velocity.y+=重力*Time.deltaTime;CC.Move(velocity*Time.deltaTime);4.3.3玩家動畫玩家動畫和UI動畫一樣是通過Unity3D組件Animator來實現(xiàn)的,但AssetStore導入的人物模型不附帶人物動畫,獲取人物動畫一個方法是自己在Unity3D中通過Animation窗口來自己制作,另一個方法是找其他帶動作的模型綁到玩家上使用,由于基本是人類動畫,可以選擇將人物模型放到網(wǎng)站Mixamo下載當前人物模型的其他動作。下載后的人物模型導入后將其中的一個模型的骨骼Avatar放到自己玩家模型的animator組件上,之后把在Mixamo下載的模型在Inspector窗口里找到Rig之后把AnimationType改為Humanoid,AvatarDefinition選為CopyFromOtherAvatar,之后就可以將其他的模型動畫共用一套骨骼了。玩家動畫齊全后可以在Project新建一個動畫控制器和C#腳本來控制玩家動畫的播放,動畫控制器如圖4-2-2-3-1。C#腳本主要通過檢查玩家當前處于的狀態(tài)來改變動畫控制器左側(cè)參數(shù)的變化。相關代碼如下圖7動畫控制器代碼中的Animator.StringToHash(String)是將動畫控制器里的參數(shù)轉(zhuǎn)換成數(shù)字序號,提前獲取參數(shù)的數(shù)字序號就不用輸入可能輸錯string類型的名稱,而且有些平臺是不支持SetBool(string,true),這里用SetBool(int,true)更保險。publicAnimatorAnim;//動畫參數(shù)序號int下落參數(shù)序號; ……voidStart(){ 下落參數(shù)序號=Animator.StringToHash("isFall");……}voidPlayerAnimation(){if(角色是否處于下落狀態(tài))Anim.SetBool(下落參數(shù)序號,true);elseAnim.SetBool(下落參數(shù)序號,false);……}PhysicsCheck()通過半球形檢測判斷玩家是否在地面上,是否正在跳躍。voidPhysicsCheck(){Physics.CheckSphere是球形物理檢測是否在地上=Physics.CheckSphere(玩家腳步的點,檢測半徑,檢測的圖層);……}4.3.4玩家移動玩家的移動利用的是CharacterController組件里的Move(Vector3motion),Move()可以提供一個方向的恒定推力,通過Horizontal的值來實現(xiàn)玩家的走動。給物體添加一個PhysicMaterial并將其的摩擦力調(diào)為零,這樣移動的時候當物體緊貼其他物體下落的時候就不會有摩擦力使玩家不能平滑的下落。玩家的主要移動是通過“Horizontal”的值來實現(xiàn)的,在編輯里的項目設置中可以找到。當玩家按下A鍵時“Horizontal”的值從0變?yōu)?1,按下D鍵時從0變?yōu)?,沒有按下時為0。通過按下A或D鍵時“Horizontal”的值來判斷玩家運動的方向,再給玩家一個推力就可以實現(xiàn)玩家的移動。相關代碼如下playerX=Input.GetAxis("Horizontal");Vector3移動方向=newVector3(playerX,0f,0f);//轉(zhuǎn)向if(按下A鍵)向左旋轉(zhuǎn)玩家if(按下D鍵)向右旋轉(zhuǎn)玩家CC.Move(移動方向*移動速度*Time.deltaTime);4.4助手助手的功能有四個,分別是攻擊、短距離傳送、建造物體和銷毀物體。通過Tap鍵來啟用助手,鍵盤上的1,2,3,4分別對應一個模式。按1時處于攻擊模式時,助手會從方塊變?yōu)楣裟J?,長按鼠標左鍵放出激光束,如圖8。按2時處于短距離傳送模式的時候會在10個單位內(nèi)生成小型傳送通道,單機左鍵瞬移。按3或4時是單擊左鍵時建造或銷毀物體。在玩家身上設置一個跟隨點通過Vector3.Lerp(助手位置,玩家位置,speed)來實現(xiàn),雖然速度不是恒定的但效果不錯。函數(shù)AssisterChange()負責對應的1,2,3,4的模式切換并在切換時隱藏其他模式時產(chǎn)生的物體。模式的切換是用鍵盤上的Alpha1、Alpha2、Alpha3和Alpha4來實現(xiàn)的if(按下對應的數(shù)字鍵){啟動對應的模式關閉其它模式if(有其它模式下對象在場景里){隱藏或銷毀對應的對象}}當切換到模式2下時通過射線判定傳送通道位置Ray_ray=newRay(射線原點,射線方向);RaycastHit_hit;bool_rayCheck=Physics.Raycast(_ray,out_hit,射線長度,檢測圖層);if(未生成傳送通道)生成傳送通道else{if(_rayCheck){Vector3_vp=接觸點的坐標+接觸點的法向量傳送通道位置=newVector3(_vp.x,_vp.y,0);}else傳送通道位置=射線的原點+射線的方向*射線長度}函數(shù)Shoot()負責啟動對應模式時的鼠標事件和助手旋轉(zhuǎn)voidShoot(){//炮塔旋轉(zhuǎn)if(isAttack||isLongTransmit){//獲取鼠標坐標Vector3mouse=Input.mousePosition;//獲取物體中心點坐標,并轉(zhuǎn)換成屏幕坐標Vector3obj=Camera.main.WorldToScreenPoint(transform.position);//向量相減Vector3direction=mouse-obj;//z軸為0direction.z=0f;//將目標向量長度變成單位向量,獲得方位向量direction=direction.normalized;//物體自身Y軸和目標向量保持一致transform.right=direction;}//按下鼠標左鍵時if(Input.GetButtonDown("Fire1")){if(攻擊模式){if(bullets.childCount<1){ //在對應位置生成激光子彈Instantiate(bullet,firePosition.position,firePosition.rotation,bullets);}}if(isLongTransmit&&isTransmit){ //記錄傳送點和玩家的位置,再交換Vector3tr_position=transmissionPosition.GetChild(0).position;player.position=tr_position;transform.position=tr_position+newVector3(0,1,0);}}//松開鼠標左鍵時if(Input.GetButtonUp("Fire1")){ //隱藏傳送通道transmissionOUT.SetActive(false);if(isAttack){if(bullets.childCount!=0){ //銷毀激光Destroy(bullets.GetChild(0).gameObject);}}}}圖8助手攻擊圖9短距離傳送物體的創(chuàng)造主要通過函數(shù)CreationItem()來實現(xiàn),原理在于在整個地圖后面加一個足夠覆蓋整個地圖大小的空物體并添加圖層background,之后從攝像機處發(fā)射出射線獲取鼠標在場景里對應圖層上的大概位置點,之后在鼠標位置生成帶有射線的物體,以物體為中心在上下左右生成的射線檢測碰到的物體信息判斷物體在場景里的位置和地圖數(shù)組里的對應位置,放置的時候更新地圖數(shù)組和對象數(shù)組。圖10創(chuàng)造圖11銷毀函數(shù)ItemDirectionCheck()負責檢測對應方向的物體,獲取對應場景坐標。_pos為射線原點,_direction為射線方向boolItemDirectionCheck(Vector3射線原點,Vector3射線方向){Ray_ray=newRay(射線原點,射線方向);RaycastHit_hit;boolisDirection=Physics.Raycast(_ray,out_hit,射線長度,檢測圖層);if(isDirection){Debug.DrawLine(射線原點,接觸點,射線顏色);int_x=_hit.transform.GetComponent<BlockMessage>().x;int_y=_hit.transform.GetComponent<BlockMessage>().y;Vector3_normal=接觸點法向量;物體位置=newVector3(_x,_y,0)+_hit.normal;}else{Debug.DrawLine(射線原點,射線原點+射線方向*射線長度,射線顏色);}returnisDirection;}函數(shù)CreationItem()負責建造時的相關判定,原理為啟動建造時獲取建造的信息在鼠標位置生成對應的物體,四個方向的ItemDirectionCheck()函數(shù)負責判斷物體周圍是否有其他方塊,周圍沒有其他方塊時無法進行放置。voidCreationItem(){if(PlayerAssister.playerAssister.isCreation){if(transform.childCount==0){creatObj=Instantiate(C_Item[0],transform);creatObj.GetComponent<BoxCollider>().isTrigger=true;creatObj.layer=default;}Ray_ray=Camera.main.ScreenPointToRay(Input.mousePosition);RaycastHit_hit;if(Physics.Raycast(_ray,out_hit,creationLayer)){creatObj.transform.position=newVector3Int((int)_hit.point.x,(int)_hit.point.y,0);}for循環(huán)判斷物體上下左右是否有其它物體,判斷為true則可以放置物體。for(inti=0;i<1;i++){if(ItemDirectionCheck(creatObj.transform.position,creatObj.transform.up)){isBuild=true;break;}if(ItemDirectionCheck(creatObj.transform.position,-creatObj.transform.up)){isBuild=true;break;}if(ItemDirectionCheck(creatObj.transform.position,creatObj.transform.right)){isBuild=true;break;}if(ItemDirectionCheck(creatObj.transform.position,-creatObj.transform.right)){isBuild=true;break;}isBuild=false;}if(Input.GetButtonDown("Fire1")&&isBuild){int_id=CreateTerrain.createTerrain.MainMapGrid[(int)buildpos.x,(int)buildpos.y];if(_id==0){creatObj.GetComponent<BoxCollider>().isTrigger=false;creatObj.layer=9;creatObj.transform.SetParent(CreateTerrain.createTerrain.gamemap[7]);creatObj.transform.localPosition=buildpos;creatObj.transform.GetComponent<BlockMessage>().x=(int)buildpos.x;creatObj.transform.GetComponent<BlockMessage>().y=(int)buildpos.y;CreateTerrain.createTerrain.Mainobjgrid[(int)buildpos.x,(int)buildpos.y]=creatObj;CreateTerrain.createTerrain.MainMapGrid[(int)buildpos.x,(int)buildpos.y]=5;buildpos=newVector3();}else{Debug.Log("不可建造");}}}else{isBuild=false;}在物體的銷毀上主要用函數(shù)DestoryItem()來實現(xiàn)。相比放置方塊,銷毀方塊只需要檢測物體是否存在決定是否銷毀方塊并更新地圖數(shù)組和對象數(shù)組即可。4.5敵人4.5.1敵人簡介目前制作了兩種敵人,分別是負責攻擊的藍水晶以及負責喚醒藍水晶的粉水晶,如圖4-2-4-1。當玩家接近粉水晶的時候,粉水晶會喚醒自己一定范圍藍水晶進行攻擊玩家。粉水晶的三顆旋轉(zhuǎn)的珠子消失時也是生命值歸零,和藍水晶一樣正中間的水晶會消失并播放水晶破碎的粒子特效,并關閉已喚醒的藍水晶。藍水晶的攻擊方向只能向左右各旋轉(zhuǎn)最大20度,并且激活時會根據(jù)玩家位置控制旋轉(zhuǎn)方向。藍水晶的攻擊是通過射線判斷玩家是否在攻擊路徑上,播放冰刺特效。4.5.2敵人功能的實現(xiàn)藍色水晶敵人的攻擊是利用粒子系統(tǒng)來實現(xiàn)的,要讓粒子特效擊中玩家有反饋的話,必須要在播放的粒子系統(tǒng)上勾選Collision→SendCollisionMessages之后就可以通過OnParticleCollision(GameObjectgameObject)進行接收信息,判斷是否擊中玩家。(x,y+2)玩家(x+1,y+2)(x,y+1)(x-2,y)(x-1,y)水晶(x,y)(x+1,y)(x+2,y)(x,y-1)(x,y-2)向上生成的藍色水晶敵人如何瞄準玩家,這里利用坐標點的x,y值的大小來判斷,假設水晶的位置是上面表格中的(x,y),如果玩家在水晶的上面,玩家的Y軸y+2就一定比水晶的Y軸y大,接下來再判斷水晶的X軸相對于玩家的X軸大小,就可以決定水晶的發(fā)射角度的偏轉(zhuǎn)方向。其他方向的瞄準同理。藍水晶的朝向只要在生成時向水晶的下方發(fā)射射線,之后通過檢測點的法向量即可獲得當前水晶的朝向。藍水晶的主要代碼如下藍水晶朝上時的部分代碼:publicfloatyRotation;if(朝上){if(水晶的X軸坐標>玩家的X軸坐標){if(藍水晶發(fā)射塔的Y軸角度>最小旋轉(zhuǎn)角度){yRotation--;if(yRotation<最小旋轉(zhuǎn)角度)yRotation=最小旋轉(zhuǎn)角度;藍水晶發(fā)射塔的旋轉(zhuǎn)角度=Quaternion.Euler(90f,yRotation,0f);}}else{if(藍水晶發(fā)射塔的Y軸角度<最大旋轉(zhuǎn)角度){yRotation++;if(yRotation>最大旋轉(zhuǎn)角度)yRotation=Maxangle;藍水晶發(fā)射塔的旋轉(zhuǎn)角度=Quaternion.Euler(90f,yRotation,0f);}}}藍水晶的位置判斷部分代碼:Ray_ray=newRay(Turret.position,-Turret.up);RaycastHit_hit;if(Physics.Raycast(_ray,out_hit,maxDistanceRock,layerMaskRock)){//Upif(_hit.normal==newVector3(0f,1f,0f)){isUp=true;}//downif(_hit.normal==newVector3(0f,-1f,0f)){isDown=true;}//leftif(_hit.normal==newVector3(-1f,0f,0f)){isLeft=true;}//rightif(_hit.normal==newVector3(1f,0f,0f)){isRight=true;}}粉色水晶的作用相當于哨兵,負責判斷玩家是否在附近,玩家靠近時激活附近的藍水晶攻擊玩家,相關代碼如下:float相對于玩家的距離=Vector3.Distance(水晶的位置,玩家的位置);if(相對于玩家的距離<=10f){if(attaceCry.Count==0){//通過地圖數(shù)組查找當前位置附近的藍水晶,并放進數(shù)組for(inti=cryNews.cryX-2;i<cryNews.cryX+3;i++){for(intj=cryNews.cryY-2;j<cryNews.cryY+3;j++){if(i>0&&i<createTerrain.mapsize&&j>0&&j<createTerrain.mapsize){if(createTerrain.mapgrid[i,j]==2){attaceCry.Add(createTerrain.objgrid[i,j]);}}}}}//遍歷數(shù)組里藍水晶啟動攻擊for(inti=0;i<attaceCry.Count;i++){attaceCry[i].GetComponent<CrystalsvControl>().isStart=true;}}圖12水晶敵人4.6傳送通道傳送通道是由三個不停旋轉(zhuǎn)的漏斗環(huán)組成,如圖13。當玩家按下F鍵時傳送到隨機的副本地圖,副本地圖固定隨機位置生成一個傳送通道,當玩家離開隨機地圖時,隨機地圖和傳送通道將一切刪除。傳送是用了簡單的位置交換,地圖消除則是直接清空數(shù)組后執(zhí)行函數(shù)CreateCopeMap()重新創(chuàng)建新的地圖并生成新的傳送通道。publicvoidCreateCopeMap(){if(gamemap[0].childCount!=0){objgrid=newGameObject[mapsize,mapsize];intGenv0=gamemap[0].childCount;intGenv1=gamemap[1].childCount;for(inti=0;i<Genv0;i++){DestroyImmediate(gamemap[0].GetChild(0).gameObject);}for(inti=0;i<Genv1;i++){DestroyImmediate(gamemap[1].GetChild(0).gameObject);}Destroy(gamemap[8].GetChild(1).gameObject);mapgrid=null;}CreateMap(gamemap[0],gamemap[1]);}要注意這里的銷毀物體用的是DestroyImmediate(GameObject),用Destroy(GameObject)的時候程序不能立即檢測GameObject是否被銷毀了。圖13傳送通道4.7相機由于是采用橫版的游戲方式,因此這里可以采用2D游戲常用的一種相機插件Cinemachine,插件可以通過Window→Packages進行下載。下載完成后可以通過菜單上的Cinemachine選擇創(chuàng)建一個Virtual相機,再建一個空物體添加組件PolygonCollider2D,編輯collider的尺寸,也就是相機的可活動范圍,之后再創(chuàng)建出來的虛擬相機上找到Follow放入要跟蹤的對象,并把在組件CinemachineConfiner的BoundingShape2D上放入編輯好的空物體。在使用虛擬相機的時候主相機的位置是鎖死的,調(diào)位移也只能調(diào)虛擬相機的。圖144.8保存機制4.8.1保存在保存機制上,采用的是序列化的方法,將保存的信息存儲在StreamingFileSave文件夾里的savebyjson.json里。在函數(shù)Save()里添加要存儲的數(shù)據(jù)類型,添加[System.Serializable]將數(shù)據(jù)序列化。[System.Serializable]publicclassSave{//地圖信息存儲publicList<int>MapdataSave=newList<int>();publicList<int>Ma

溫馨提示

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

評論

0/150

提交評論