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

下載本文檔

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

文檔簡介

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

評論

0/150

提交評論