用Unity3D的17個技巧:Unity3D最佳實踐_第1頁
用Unity3D的17個技巧:Unity3D最佳實踐_第2頁
用Unity3D的17個技巧:Unity3D最佳實踐_第3頁
用Unity3D的17個技巧:Unity3D最佳實踐_第4頁
用Unity3D的17個技巧:Unity3D最佳實踐_第5頁
已閱讀5頁,還剩6頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

用Unity3D的17個技巧:Unity3D最佳實踐擴展和MonoBehaviourBase21、 擴展一個自己的MonoBehaviour基類,然后自己的所有組件都從它派生這可以使你方便的實現(xiàn)一些通用函數(shù),例如類型安全的Invoke,或者是一些更復雜的調(diào)用(例如random等等)。22、 為Invoke,StartcoroutineandInstantiate定義安全調(diào)用方法定義一個委托任務(delegateTask),用它來定義需要調(diào)用的方法,而不要使用字符串屬性方法名稱,例如:資源來自于狗刨網(wǎng)publicvoidInvoke(Tasktask,floattime){Invoke(task.Method.Name,time);}23、 為共享接口的組件擴展有些時候把獲得組件、查找對象實現(xiàn)在一個組件的接口中會很方便。下面這種實現(xiàn)方案使用了typeof,而不是泛型版本的函數(shù)。泛型函數(shù)無法在接口上工作,而typeof可以。下面這種方法把泛型方法整潔的包裝起來。//DefinedinthecommonbaseclassforallmonobehaviourspublicIGetInterfaceComponentvI>()whereI:class{returnGetComponent(typeof(I))asI;}publicstaticListvI>FindObjectsOfInterfacevI>()whereI:class{MonoBehaviour[]monoBehaviours=FindObjectsOfTypevMonoBehaviour>();Listvl>list=newListvl>();foreach(MonoBehaviourbehaviourinmonoBehaviours){Icomponent=behaviour.GetComponent(typeof(I))asI;if(component!=null){list.Add(component);}}returnlist;}24、使用擴展來讓代碼書寫更便捷例如:publicstaticclassCSTransform{publicstaticvoidSetX(thisTransformtransform,floatx){Vector3newPosition=newVector3(x,transform.position.y,transform.position.z);transform.position=newPosition;}25、使用防御性的GetComponent()有些時候強制性組件依賴(通過RequiredComponent)會讓人蛋疼。例如,很難在Inspector中修改組件(即使他們有同樣的基類)。下面是一種替代方案,當一個必要的組件沒有找到時,輸出一條錯誤信息。publicstaticTGetSafeComponentvT>(thisGameObjectobj)whereT:MonoBehaviour{Tcomponent=obj.GetComponentvT>();if(component==null){Debug.LogError("Expectedtofindcomponentoftype"+typeof(T)+"butfoundnone",obj);}returncomponent;}風格26、避免對同一件事使用不同的處理風格在很多情況下,某件事并不只有一個慣用手法。在這種情況下,在項目中明確選擇其中的一個來使用。下面是原因:?一些做法并不能很好的一起協(xié)作。使用一個,能強制統(tǒng)一設計方向,并明確指出不是其他做法所指的方向;?團隊成員使用統(tǒng)一的風格,可能方便大家互相的理解。他使得整體結(jié)構(gòu)和代碼都更容易理解。這也可以減少錯誤;幾組風格的例子:協(xié)程與狀態(tài)機(Coroutinesvs.statemachines);嵌套的Prefab、互相鏈接的Prefab、超級Prefab(Nestedprefabsvs.linkedprefabsvs.Godprefabs);?數(shù)據(jù)分離的策略;?在2D游戲的使用Sprite的方法;Prefab的結(jié)構(gòu);?對象生成策略;?定位對象的方法:使用類型、名稱、層、引用關系;?對象分組的方法:使用類型、名稱、層、引用數(shù)組;?找到一組對象,還是讓它們自己來注冊;?控制執(zhí)行次序(使用Unity的執(zhí)行次序設置,還是使用Awake/Start/Update/LateUpdate,還是使用純手動的方法,或者是次序無關的架構(gòu));?在游戲中使用鼠標選擇對象/位置/目標:SelectionManager或者是對象自主管理;?在場景變換時保存數(shù)據(jù):通過PlayerPrefs,或者是在新場景加載時不要銷毀的對象;?組合動畫的方法:混合、疊加、分層;時間27、維護一個自己的Time類,可以使游戲暫停更容易實現(xiàn)做一個“Time.DeltaTime”和""Time.TimeSinceLevelLoad"的包裝,用來實現(xiàn)暫停和游戲速度縮放。這使用起來略顯麻煩,但是當對象運行在不同的時鐘速率下的時候就方便多了(例如界面動畫和游戲內(nèi)動畫)。生成對象28、不要讓游戲運行時生成的對象搞亂場景層次結(jié)構(gòu)在游戲運行時,為動態(tài)生成的對象設置好它們的父對象,可以讓你更方便的查找。你可以使用一個空的對象,或者一個沒有行為的單件來簡化代碼中的訪問??梢越o這個對象命名為“DynamicObjects"。類設計29、使用單件(Singleton)模式從下面這個類派生的所有類,將自動獲得單件功能:publicclassSingletonvT>:MonoBehaviourwhereT:MonoBehaviour{protectedstaticTinstanee;/**Returnstheinstaneeofthissingleton.*/publicstaticTInstanee{get{if(instanee==null){instanee=(T)FindObjectOfType(typeof(T));if(instance==null)Debug.LogError("Aninstanceof"+typeof(T)+"isneededintheseene,butthereisnone.");}returninstanee;}}}單件可以作為一些管理器,例如ParticleManager或者AudioManager亦或者GUIManager。?對于那些非唯一的prefab實例使用單件管理器(例如Player)。不要為了堅持這條原則把類的層次關系復雜化,寧愿在你的GameManager(或其他合適的管理器中)中持有一個它們的引用。?對于外部經(jīng)常使用的共有變量和方法定義為static,這樣你可以這樣簡便的書寫“GameManager.Player”,而不用寫成“GameManager.Instance.player”。30、 在組件中不要使用public成員變量,除非它需要在inspector中調(diào)節(jié)除非需要設計師(策劃or美術(shù))去調(diào)節(jié)的變量,特別是它不能明確表明自己是做什么的變量,不要聲明為public。如果在這些特殊情況下,無法避免,則可使用兩個甚至四個下劃線來表明不要從外部調(diào)節(jié)它,例如:publicfloat—aVariable;31、 把界面和游戲邏輯分開這一條本質(zhì)上就是指的MVC模式。所有的輸入控制器,只負責向相應的組件發(fā)送命令,讓它們知道控制器被調(diào)用了。舉一個控制器邏輯的例子,一個控制器根據(jù)玩家的狀態(tài)來決定發(fā)送哪個命令。但是這樣并不好(例如,如果你添加了多個控制器,那將會導致邏輯重復)。相反的,玩家對象應該根據(jù)當前狀態(tài)(例如減速、驚恐)來設置當前的速度,并根據(jù)當前的面朝向來計算如何向前移動。控制器只負責做他們自己狀態(tài)相關的事情,控制器不改變玩家的狀態(tài),因此控制前甚至可以根本不知道玩家的狀態(tài)。另外一個例子,切換武器。正確的方法是,玩家有一個函數(shù):“SwitchWeapon(WeaponnewWeapon)"供GUI調(diào)用。GUI不應該維護所有對象的Transform和他們之間的父子關系。所有界面相關的組件,只負責維護和處理他們自己狀態(tài)相關的數(shù)據(jù)。例如,顯示一個地圖,GUI可以根據(jù)玩家的位移計算地圖的顯示。但是,這是游戲狀態(tài)數(shù)據(jù),它不屬于GUI。GUI只是顯示游戲狀態(tài)數(shù)據(jù),這些數(shù)據(jù)應該在其他地方維護。地圖數(shù)據(jù)也應該在其他地方維護(例如GameManager)。游戲玩法對象不應該關心GUI。有一個例外是處理游戲暫停(可能是通過控制Time.timeScale,其實這并不是個好主意)。游戲玩法對象應該知道游戲是否暫停。但是,這就是全部了。另外,不要把GUI組件掛到游戲玩法對象上。這么說吧,如果你把所有的GUI類都刪了,游戲應該可以正確編譯。你還應該達到:在不需要重寫游戲邏輯的前提下,重寫GUI和輸入控制。32、分離狀態(tài)控制和簿記變量簿記變量只是為了使用起來方便或者提高查找速度,并且可以根據(jù)狀態(tài)控制來覆蓋。將兩者分離可以簡化:?保存游戲狀態(tài)?調(diào)試游戲狀態(tài)實現(xiàn)方法之一是為每個游戲邏輯定義一個”SaveData“類,例如:[Serializable]PlayerSaveData{publicfloathealth;//publicforserialisation,notexposedininspector}Player//...bookkeepingvariables//Don'texposestateininspector.Stateisnottweakable.privatePlayerSaveDataplayerSaveData;}33分離特殊的配置假設我們有兩個敵人,它們使用同一個Mesh,但是有不同的屬性設置(例如不同的力量、不同的速度等等)。有很多方法來分離數(shù)據(jù)。下面是我比較喜歡的一種,特別是對于對象生成或者游戲存檔時,會很好用。(屬性設置不是狀態(tài)數(shù)據(jù),而是配置數(shù)據(jù),所以我們不需要存檔他們。當對象加載或者生成是,屬性設置會自動加載。)?為每一個游戲邏輯類定義一個模板類。例如,對于敵人,我們來一個“EnemyTemplate”,所有的屬性設置變量都保存在這個類中。?在游戲邏輯的類中,定義一個上述模板類型的變量。?制作一個敵人的Prefab,以及兩個模板的Prefab:“WeakEnemyTemplate”禾『'StrongEnemyTemplate"。?在加載或者生成對象是,把模板變量正確的復制。這種方法可能有點復雜(在一些情況下,可能不需要這樣)。舉個例子,最好使用泛型,我們可以這樣定義我們的類:publicclassBaseTemplate{}publicclassActorTemplate:BaseTemplate{}publicclassEntity<EntityTemplateType>whereEntityTemplateType:BaseTemplateEntityTemplateTypetemplate;}publicclassActor:Entity<ActorTemplate>{}34、 除了顯示用的文本,不要使用字符串特別是不要用字符串作為對象或者prefab等等的ID標識。一個很遺憾的例外是動畫系統(tǒng),需要使用字符串來訪問相應的動畫。35、 避免使用public的數(shù)組舉例說明,不要定義一個武器的數(shù)組,一個子彈的數(shù)組,一個粒子的數(shù)組,這樣你的代碼看起來像這樣:publicvoidSelectWeapon(intindex){currentWeaponlndex=index;Player.SwitchWeapon(weapons[currentWeapon]);}publicvoidShoot(){Fire(bullets[currentWeapon]);FireParticles(particles[currentWeapon]);}這在代碼中還不是什么大問題,但是在Inspector中設置他們的值的時候,就很難不犯錯了。我們可以定義一個類,來封裝這三個變量,然后使用一個它的實例數(shù)組:[Serializable]publicclassWeapon{publicGameObjectprefab;publicParticleSystemparticles;publicBulletbullet;}這樣代碼看起來很整潔,但是更重要的是,在Inspector中設置時就不容易犯錯了。36在結(jié)構(gòu)中避免使用數(shù)組舉個例子,一個玩家可以有三種攻擊形式,每種使用當前的武器,并發(fā)射不同的子彈、產(chǎn)生不同的行為。你可以把三個子彈作為一個數(shù)組,并像下面這樣組織邏輯:publicvoidFireAttack(){///behaviourFire(bullets[O]);}publicvoidIceAttack(){///behaviourFire(bullets[1]);publicvoidWindAttack(){///behaviourFire(bullets[2]);}使用枚舉值可以讓代碼看起來更好一點:publicvoidWindAttack(){///behaviourFire(bullets[WeaponType.Wind]);}但是這對Inspector一點也不好。最好使用單獨的變量,并且起一個好的變量名,能夠代表他們的內(nèi)容的含義。使用下面這個類會更整潔。[Serializable]publicclassBullets{publicBulletFireBullet;publicBulletIceBullet;publicBulletWind

溫馨提示

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

最新文檔

評論

0/150

提交評論