日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【转载】关于对方法实例化的相关感悟以及unity的50个技巧

發布時間:2025/6/16 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转载】关于对方法实例化的相关感悟以及unity的50个技巧 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

關于實例化問題的感悟(筆者自悟,大神勿噴)

在之前的程序編寫過程中,雖然對相關的方法進行了實例化,但是在運行的時候總是會出現“未將對象引用設置到對象的實例”,出現該種問題的原因是由于在實例化后,沒有對實例化進行引用賦值,所以導致相關變量無法在其他方法中進行讀取,以后需對此謹記。

?

同時之前瀏覽過一片大神寫過的關于unity相關技巧的文章,筆者覺得受益匪淺,現將鏈接與原文轉載于下,希望可以幫助大家。

?

使用Unity3D的50個技巧:Unity3D最佳實踐

作者:房燕良

?

關于這些技巧

這些技巧不可能適用于每個項目。
  • 這些是基于我的一些項目經驗,項目團隊的規模從3人到20人不等;
  • 框架結構的可重用性、清晰程度是有代價的——團隊的規模和項目的規模決定你要在這個上面付出多少;
  • 很多技巧是品味的問題(這里所列的所有技巧,可能有同樣好的技術替代方案);
  • 一些技巧可能是對傳統的Unity開發的一個沖擊。例如,使用prefab替代對象實例并不是一個傳統的Unity風格,并且這樣做的代價還挺高的(需要很多的preffab)。也許這些看起來有些瘋狂,但是在我看來是值得的。

流程

1、避免Assets分支

?

所有的Asset都應該只有一個唯一的版本。如果你真的需要一個分支版本的Prefab、Scene或是Mesh,那你要制定一個非常清晰的流程,來確定哪個是正確的版本。錯誤的分支應該起一個特別的名字,例如雙下劃線前綴:__MainScene_Backup。Prefab版本分支需要一個特別的流程來保證安全(詳見Prefabs一節)。

2、如果你在使用版本控制的話,每個團隊成員都應該保有一個項目的Second Copy用來測試

修改之后,Second Copy和Clean Copy都應該被更新和測試。大家都不要修改自己的Clean Copy。這對于測試Asset丟失特別有用。

3、考慮使用外部的關卡編輯工具

Unity不是一個完美的關卡編輯器。例如,我們使用TuDee來創建3D Tile-Based的游戲,這使我們可以獲得對Tile友好的工具的益處(網格約束,90度倍數的旋轉,2D視圖,快速Tile選擇等)。從一個XML文件來實例化Prefab也很簡單。詳見Guerrilla Tool Development。

4、考慮把關卡保存為XML,而非scene

這是一種很奇妙的技術:
  • 它可以讓你不必每個場景都設置一遍;
  • 他可以加載的更快(如果大多數對象都是在場景之間共享的)。
  • 它讓場景的版本合并變的簡單(就算是Unity的新的文本格式的Scene,也由于數據太多,而讓版本合并變的不切實際)。
  • 它可以使得在關卡之間保持數據更簡便。
你仍就可以使用Unity作為關卡編輯器(盡管你用不著了)。你需要寫一些你的數據的序列化和反序列化的代碼,并實現在編輯器和游戲運行時加載關卡、在編輯器中保存關卡。你可能需要模仿Unity的ID系統來維護對象之間的引用關系。

5、考慮編寫通用的自定義Inspector代碼

實現自定義的Inspector是很直截了當的,但是Unity的系統有很多的缺點:
  • 它不支持從繼承中獲益;
  • 它不允許定義字段級別的Inspector組件,而只能是class類型級別。舉個例子,如果沒有游戲對象都有一個ScomeCoolType字段,而你想在Inspector中使用不同的渲染,那么你必須為你的所有class寫Inspector代碼。
你可以通過從根本上重新實現Inspector系統來處理這些問題。通過一些反射機制的小技巧,他并不像看上去那么看,文章底部(日后另作翻譯)將提供更多的實現細節。 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

場景組織

6、使用命名的空Game Object來做場景目錄

仔細的組織場景,就可以方便的找到任何對象。

7、把控制對象和場景目錄(空Game Objec)放在原點(0,0,0)

如果位置對于這個對象不重要,那么就把他放到原點。這樣你就不會遇到處理Local Space和World Space的麻煩,代碼也會更簡潔。

8、盡量減少使用GUI組件的offset

通常應該由控件的Layout父對象來控制Offset;它們不應該依賴它們的爺爺節點的位置。位移不應該互相抵消來達到正確顯示的目的。做基本上要防止了下列情況的發生: 父容器被放到了(100,-50),而字節點應該在(10,10),所以把他放到(90,60)[父節點的相對位置]。 這種錯誤通常放生在容器不可見時。

9、把世界的地面放在Y=0

這樣可以更方便的把對象放到地面上,并且在游戲邏輯中,可以把世界作為2D空間來處理(如果合適的話),例如AI和物理模擬。

10、使游戲可以從每個Scene啟動

這將大大的降低測試的時間。為了達到所有場景可運行,你需要做兩件事: 首先,如果需要前面場景運行產生的一些數據,那么要模擬出它們。 其次,生成在場景切換時必要保存的對象,可以是這樣: [csharp]?view plain?copy ?
  • myObject?=?FindMyObjectInScene();??
  • ???
  • if?(myObjet?==?null)??
  • {??
  • ???myObject?=?SpawnMyObject();??
  • }??
  • ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

    美術

    11、把角色和地面物體的中心點(Pivot)放在底部,不要放在中間

    這可以使你方便的把角色或者其他對象精確的放到地板上。如果合適的話,它也可能使得游戲邏輯、AI、甚至是物理使用2D邏輯來表現3D。

    12、統一所有的模型的面朝向(Z軸正向或者反向)

    對于所有具有面朝向的對象(例如角色)都應該遵守這一條。在統一面朝向的前提下,很多算法可以簡化。

    13、在開始就把Scale搞正確

    請美術把所有導入的縮放系數設置為1,并且把他們的Transform的Scale設置為1,1,1。可以使用一個參考對象(一個Unity的Cube)來做縮放比較。為你的游戲選擇一個世界的單位系數,然后堅持使用它。

    14、為GUI組件或者手動創建的粒子制作一個兩個面的平面模型

    設置這個平面面朝向Z軸正向,可能簡化Billboard和GUI創建。

    15、制作并使用測試資源

    • 為SkyBox創建帶文字的方形貼圖;
    • 一個網格(Grid);
    • 為Shader測試使用各種顏色的平面:白色,黑色,50%灰度,紅,綠,藍,紫,黃,青;
    • 為Shader測試使用漸進色:黑到白,紅到綠,紅到藍,綠到藍;
    • 黑白格子;
    • 平滑的或者粗糙的法線貼圖;
    • 一套用來快速搭建場景的燈光(使用Prefa);
    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

    Prefabs

    16、所有東西都使用Prefab

    只有場景中的“目錄”對象不使用Prefab。甚至是那些只使用一次的唯一對象也應該使用Prefab。這樣可以在不動用場景的情況下,輕松修改他們。(一個額外的好處是,當你使用EZGUI時,這可以用來創建穩定的Sprite Atlases)

    17、對于特例使用單獨的Prefab,而不要使用特殊的實例對象

    如果你有兩種敵人的類型,并且只是屬性有區別,那么為不同的屬性分別創建Prefab,然后鏈接他們。這可以:
    • 在同一個地方修改所有類型
    • 在不動用場景的情況下進行修改
    如果你有很多敵人的類型,那么也不要在編輯器中使用特殊的實例。一種可選的方案是程序化處理它們,或者為所有敵人使用一個核心的文件/Prefab。使用一個下拉列表來創建不同的敵人,或者根據敵人的位置、玩家的進度來計算。

    18、在Prefab之間鏈接,而不要鏈接實例對象

    當Prefab放置到場景中時,它們的鏈接關系是被維護的,而實例的鏈接關系不被維護。盡可能的使用Prefab之間的鏈接可以減少場景創建的操作,并且減少場景的修改。

    19、如果可能,自動在實例對象之間產生鏈接關系

    如果你確實需要在實例之間鏈接,那么應該在程序代碼中去創建。例如,Player對象在Start時需要把自己注冊到GameManager,或者GameManager可以在Start時去查找Player對象。 對于需要添加腳本的Prefab,不要用Mesh作為根節點。當你需要從Mesh創建一個Prefab時,首先創建一個空的GameObject作為父對象,并用來做根節點。把腳本放到根節點上,而不要放到Mesh節點上。使用這種方法,當你替換Mesh時,就不會丟失所有你在Inspector中設置的值了。 使用互相鏈接的Prefab來實現Prefab嵌套。Unity并不支持Prefab的嵌套,在團隊合作中第三方的實現方案可能是危險的,因為嵌套的Prefab之間的關系是不明確的。

    20、使用安全的流程來處理Prefab分支

    我們用一個名為Player的Prefab來講解這個過程。 用下面這個流程來修改Player:
  • 復制Player Prefab;
  • 把復制出來的Prefab重命名為__Player_Backup;
  • 修改Player Prefab;
  • 測試一切工作正常,刪除__Player_Backup;
  • 不要把新復制的命名為Player_New,然后修改它。 有些情況可能更復雜一些。例如,有些修改可能涉及到兩個人,上述過程有可能使得場景無法工作,而所有人必須停下來等他們修改完畢。如果修改能夠很快完成,那么還用上面這個流程就可以。如果修改需要花很長時間,則可以使用下面的流程:
    • 第一個人:
    • 復制Player Prefab;
    • 把它重命名為__Player_WithNewFeature或者__Player_ForPerson2;
    • 在復制的對象上做修改,然后提交給第二個人;
    • 第二個人:
    • 在新的Prefab上做修改;
    • 復制Player Prefab,并命名為__Player_Backup;
    • 把__Player_WithNewFeature拖放到場景中,創建它的實例;
    • 把這個實例拖放到原始的Player Prefab中;
    • 如果一切工作正常,則可使刪除__Player_Backup和__Player_WithNewFeature;
    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

    擴展和MonoBehaviourBase

    21、擴展一個自己的Mono Behaviour基類,然后自己的所有組件都從它派生

    這可以使你方便的實現一些通用函數,例如類型安全的Invoke,或者是一些更復雜的調用(例如random等等)。

    22、為Invoke, StartCoroutine and Instantiate?定義安全調用方法

    定義一個委托任務(delegate Task),用它來定義需要調用的方法,而不要使用字符串屬性方法名稱,例如: [csharp]?view plain?copy ?
  • public?void?Invoke(Task?task,?float?time)??
  • {??
  • ???Invoke(task.Method.Name,?time);??
  • }??
  • 23、為共享接口的組件擴展

    有些時候把獲得組件、查找對象實現在一個組件的接口中會很方便。 下面這種實現方案使用了typeof,而不是泛型版本的函數。泛型函數無法在接口上工作,而typeof可以。下面這種方法把泛型方法整潔的包裝起來。 [csharp]?view plain?copy ?
  • //Defined?in?the?common?base?class?for?all?mono?behaviours??
  • public?I?GetInterfaceComponent<I>()?where?I?:?class??
  • {??
  • ???return?GetComponent(typeof(I))?as?I;??
  • }??
  • ???
  • public?static?List<I>?FindObjectsOfInterface<I>()?where?I?:?class??
  • {??
  • ???MonoBehaviour[]?monoBehaviours?=?FindObjectsOfType<MonoBehaviour>();??
  • ???List<I>?list?=?new?List<I>();??
  • ???
  • ???foreach(MonoBehaviour?behaviour?in?monoBehaviours)??
  • ???{??
  • ??????I?component?=?behaviour.GetComponent(typeof(I))?as?I;??
  • ???
  • ??????if(component?!=?null)??
  • ??????{??
  • ?????????list.Add(component);??
  • ??????}??
  • ???}??
  • ???
  • ???return?list;??
  • }??
  • 24、使用擴展來讓代碼書寫更便捷

    例如: [csharp]?view plain?copy ?
  • public?static?class?CSTransform???
  • {??
  • ???public?static?void?SetX(this?Transform?transform,?float?x)??
  • ???{??
  • ??????Vector3?newPosition?=???
  • ?????????new?Vector3(x,?transform.position.y,?transform.position.z);??
  • ???
  • ??????transform.position?=?newPosition;??
  • ???}??
  • ???...??
  • }???
  • 25、使用防御性的GetComponent()

    有些時候強制性組件依賴(通過RequiredComponent)會讓人蛋疼。例如,很難在Inspector中修改組件(即使他們有同樣的基類)。下面是一種替代方案,當一個必要的組件沒有找到時,輸出一條錯誤信息。 [csharp]?view plain?copy ?
  • public?static?T?GetSafeComponent<T>(this?GameObject?obj)?where?T?:?MonoBehaviour??
  • {??
  • ???T?component?=?obj.GetComponent<T>();??
  • ???
  • ???if(component?==?null)??
  • ???{??
  • ??????Debug.LogError("Expected?to?find?component?of?type?"???
  • ?????????+?typeof(T)?+?"?but?found?none",?obj);??
  • ???}??
  • ???
  • ???return?component;??
  • }??
  • ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

    風格

    26、避免對同一件事使用不同的處理風格

    在很多情況下,某件事并不只有一個慣用手法。在這種情況下,在項目中明確選擇其中的一個來使用。下面是原因:
    • 一些做法并不能很好的一起協作。使用一個,能強制統一設計方向,并明確指出不是其他做法所指的方向;
    • 團隊成員使用統一的風格,可能方便大家互相的理解。他使得整體結構和代碼都更容易理解。這也可以減少錯誤;
    幾組風格的例子:
    • 協程與狀態機(Coroutines vs. state machines);
    • 嵌套的Prefab、互相鏈接的Prefab、超級Prefab(Nested prefabs vs. linked prefabs vs. God prefabs);
    • 數據分離的策略;
    • 在2D游戲的使用Sprite的方法;
    • Prefab的結構;
    • 對象生成策略;
    • 定位對象的方法:使用類型、名稱、層、引用關系;
    • 對象分組的方法:使用類型、名稱、層、引用數組;
    • 找到一組對象,還是讓它們自己來注冊;
    • 控制執行次序(使用Unity的執行次序設置,還是使用Awake/Start/Update/LateUpdate,還是使用純手動的方法,或者是次序無關的架構);
    • 在游戲中使用鼠標選擇對象/位置/目標:SelectionManager或者是對象自主管理;
    • 在場景變換時保存數據:通過PlayerPrefs,或者是在新場景加載時不要銷毀的對象;
    • 組合動畫的方法:混合、疊加、分層;
    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

    時間

    27、維護一個自己的Time類,可以使游戲暫停更容易實現

    做一個“Time.DeltaTime”和""Time.TimeSinceLevelLoad"的包裝,用來實現暫停和游戲速度縮放。這使用起來略顯麻煩,但是當對象運行在不同的時鐘速率下的時候就方便多了(例如界面動畫和游戲內動畫)。 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

    生成對象

    28、不要讓游戲運行時生成的對象搞亂場景層次結構

    在游戲運行時,為動態生成的對象設置好它們的父對象,可以讓你更方便的查找。你可以使用一個空的對象,或者一個沒有行為的單件來簡化代碼中的訪問。可以給這個對象命名為“DynamicObjects”。 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

    類設計

    29、使用單件(Singleton)模式

    從下面這個類派生的所有類,將自動獲得單件功能: [csharp]?view plain?copy ?
  • public?class?Singleton<T>?:?MonoBehaviour?where?T?:?MonoBehaviour??
  • {??
  • ???protected?static?T?instance;??
  • ???
  • ???/**?
  • ??????Returns?the?instance?of?this?singleton.?
  • ???*/??
  • ???public?static?T?Instance??
  • ???{??
  • ??????get??
  • ??????{??
  • ?????????if(instance?==?null)??
  • ?????????{??
  • ????????????instance?=?(T)?FindObjectOfType(typeof(T));??
  • ???
  • ????????????if?(instance?==?null)??
  • ????????????{??
  • ???????????????Debug.LogError("An?instance?of?"?+?typeof(T)?+???
  • ??????????????????"?is?needed?in?the?scene,?but?there?is?none.");??
  • ????????????}??
  • ?????????}??
  • ???
  • ?????????return?instance;??
  • ??????}??
  • ???}??
  • }??
  • 單件可以作為一些管理器,例如ParticleManager或者AudioManager亦或者GUIManager。
    • 對于那些非唯一的prefab實例使用單件管理器(例如Player)。不要為了堅持這條原則把類的層次關系復雜化,寧愿在你的GameManager(或其他合適的管理器中)中持有一個它們的引用。
    • 對于外部經常使用的共有變量和方法定義為static,這樣你可以這樣簡便的書寫“GameManager.Player”,而不用寫成“GameManager.Instance.player”。

    30、在組件中不要使用public成員變量,除非它需要在inspector中調節

    除非需要設計師(策劃or美術)去調節的變量,特別是它不能明確表明自己是做什么的變量,不要聲明為public。如果在這些特殊情況下,無法避免,則可使用兩個甚至四個下劃線來表明不要從外部調節它,例如: [csharp]?view plain?copy ?
  • public?float?__aVariable;???
  • 31、把界面和游戲邏輯分開

    這一條本質上就是指的MVC模式。 所有的輸入控制器,只負責向相應的組件發送命令,讓它們知道控制器被調用了。舉一個控制器邏輯的例子,一個控制器根據玩家的狀態來決定發送哪個命令。但是這樣并不好(例如,如果你添加了多個控制器,那將會導致邏輯重復)。相反的,玩家對象應該根據當前狀態(例如減速、驚恐)來設置當前的速度,并根據當前的面朝向來計算如何向前移動。控制器只負責做他們自己狀態相關的事情,控制器不改變玩家的狀態,因此控制前甚至可以根本不知道玩家的狀態。另外一個例子,切換武器。正確的方法是,玩家有一個函數:“SwitchWeapon(Weapon newWeapon)”供GUI調用。GUI不應該維護所有對象的Transform和他們之間的父子關系。 所有界面相關的組件,只負責維護和處理他們自己狀態相關的數據。例如,顯示一個地圖,GUI可以根據玩家的位移計算地圖的顯示。但是,這是游戲狀態數據,它不屬于GUI。GUI只是顯示游戲狀態數據,這些數據應該在其他地方維護。地圖數據也應該在其他地方維護(例如GameManager)。 游戲玩法對象不應該關心GUI。有一個例外是處理游戲暫停(可能是通過控制Time.timeScale,其實這并不是個好主意)。游戲玩法對象應該知道游戲是否暫停。但是,這就是全部了。另外,不要把GUI組件掛到游戲玩法對象上。 這么說吧,如果你把所有的GUI類都刪了,游戲應該可以正確編譯。 你還應該達到:在不需要重寫游戲邏輯的前提下,重寫GUI和輸入控制。

    32、分離狀態控制和簿記變量

    簿記變量只是為了使用起來方便或者提高查找速度,并且可以根據狀態控制來覆蓋。將兩者分離可以簡化:
    • 保存游戲狀態
    • 調試游戲狀態
    實現方法之一是為每個游戲邏輯定義一個”SaveData“類,例如: [csharp]?view plain?copy ?
  • [Serializable]??
  • PlayerSaveData??
  • {??
  • ???public?float?health;?//public?for?serialisation,?not?exposed?in?inspector??
  • }???
  • ???
  • Player??
  • {??
  • ???//...?bookkeeping?variables??
  • ???
  • ???//Don’t?expose?state?in?inspector.?State?is?not?tweakable.??
  • ???private?PlayerSaveData?playerSaveData;???
  • }??
  • 33、分離特殊的配置

    假設我們有兩個敵人,它們使用同一個Mesh,但是有不同的屬性設置(例如不同的力量、不同的速度等等)。有很多方法來分離數據。下面是我比較喜歡的一種,特別是對于對象生成或者游戲存檔時,會很好用。(屬性設置不是狀態數據,而是配置數據,所以我們不需要存檔他們。當對象加載或者生成是,屬性設置會自動加載。)
    • 為每一個游戲邏輯類定義一個模板類。例如,對于敵人,我們來一個“EnemyTemplate”,所有的屬性設置變量都保存在這個類中。
    • 在游戲邏輯的類中,定義一個上述模板類型的變量。
    • 制作一個敵人的Prefab,以及兩個模板的Prefab:“WeakEnemyTemplate”和"StrongEnemyTemplate"。
    • 在加載或者生成對象是,把模板變量正確的復制。
    這種方法可能有點復雜(在一些情況下,可能不需要這樣)。 舉個例子,最好使用泛型,我們可以這樣定義我們的類: [csharp]?view plain?copy ?
  • public?class?BaseTemplate??
  • {??
  • ???...??
  • }??
  • ???
  • public?class?ActorTemplate?:?BaseTemplate??
  • {??
  • ???...??
  • }??
  • ???
  • public?class?Entity<EntityTemplateType>?where?EntityTemplateType?:?BaseTemplate??
  • {??
  • ???EntityTemplateType?template;??
  • ???...??
  • }??
  • ???
  • public?class?Actor?:?Entity?<ActorTemplate>??
  • {??
  • ???...??
  • }??
  • 34、除了顯示用的文本,不要使用字符串

    特別是不要用字符串作為對象或者prefab等等的ID標識。一個很遺憾的例外是動畫系統,需要使用字符串來訪問相應的動畫。

    35、避免使用public的數組

    舉例說明,不要定義一個武器的數組,一個子彈的數組,一個粒子的數組,這樣你的代碼看起來像這樣: [csharp]?view plain?copy ?
  • public?void?SelectWeapon(int?index)??
  • {???
  • ???currentWeaponIndex?=?index;??
  • ???Player.SwitchWeapon(weapons[currentWeapon]);??
  • }??
  • ???
  • public?void?Shoot()??
  • {??
  • ???Fire(bullets[currentWeapon]);??
  • ???FireParticles(particles[currentWeapon]);?????
  • }??
  • 這在代碼中還不是什么大問題,但是在Inspector中設置他們的值的時候,就很難不犯錯了。 我們可以定義一個類,來封裝這三個變量,然后使用一個它的實例數組: [csharp]?view plain?copy ?
  • [Serializable]??
  • public?class?Weapon??
  • {??
  • ???public?GameObject?prefab;??
  • ???public?ParticleSystem?particles;??
  • ???public?Bullet?bullet;??
  • }???
  • 這樣代碼看起來很整潔,但是更重要的是,在Inspector中設置時就不容易犯錯了。

    36、在結構中避免使用數組

    舉個例子,一個玩家可以有三種攻擊形式,每種使用當前的武器,并發射不同的子彈、產生不同的行為。 你可以把三個子彈作為一個數組,并像下面這樣組織邏輯: [csharp]?view plain?copy ?
  • public?void?FireAttack()??
  • {??
  • ???///?behaviour??
  • ???Fire(bullets[0]);??
  • }??
  • ???
  • public?void?IceAttack()??
  • {??
  • ???///?behaviour??
  • ???Fire(bullets[1]);??
  • }??
  • ???
  • public?void?WindAttack()??
  • {??
  • ???///?behaviour??
  • ???Fire(bullets[2]);??
  • }???
  • 使用枚舉值可以讓代碼看起來更好一點: [csharp]?view plain?copy ?
  • public?void?WindAttack()??
  • {??
  • ???///?behaviour??
  • ???Fire(bullets[WeaponType.Wind]);??
  • }???
  • 但是這對Inspector一點也不好。 最好使用單獨的變量,并且起一個好的變量名,能夠代表他們的內容的含義。使用下面這個類會更整潔。 [csharp]?view plain?copy ?
  • [Serializable]??
  • public?class?Bullets??
  • {??
  • ???public?Bullet?FireBullet;??
  • ???public?Bullet?IceBullet;??
  • ???public?Bullet?WindBullet;??
  • }??
  • 這里假設沒有其他的Fire、Ice、Wind的數據。

    37、把數據組織到可序列化的類中,可以讓inspector更整潔

    有些對象有一大堆可調節的變量,這種情況下在Inspector中找到某個變量簡直就成了噩夢。為了簡化這種情況,可以使用一下的步驟:
    • 把這些變量分組定義到不同的類中,并讓它們聲明為public和serializable;
    • 在一個主要的類中,把上述類的實例定義為public成員變量;
    • 不用在Awake或者Start中初始化這些變量,因為Unity會處理好它們;
    • 你可以定義它們的默認值;
    這可以把變量分組到Inspector的分組頁簽中,方便管理。 [csharp]?view plain?copy ?
  • [Serializable]??
  • public?class?MovementProperties?//Not?a?MonoBehaviour!??
  • {??
  • ???public?float?movementSpeed;??
  • ???public?float?turnSpeed?=?1;?//default?provided??
  • }??
  • ???
  • public?class?HealthProperties?//Not?a?MonoBehaviour!??
  • {??
  • ???public?float?maxHealth;??
  • ???public?float?regenerationRate;??
  • }??
  • ???
  • public?class?Player?:?MonoBehaviour??
  • {??
  • ???public?MovementProperties?movementProeprties;??
  • ???public?HealthPorperties?healthProeprties;??
  • }??
  • ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

    文本

    38、如果你有很多的劇情文本,那么把他們放到一個文件里面。

    不要把他們放到Inspector的字段中去編輯。這些需要做到不打開Unity,也不用保存Scene就可以方便的修改。

    39、如果你計劃實現本地化,那么把你的字符串分離到一個統一的位置。

    有很多種方法來實現這點。例如,定義一個文本Class,為每個字符串定義一個public的字符串字段,并把他們的默認值設為英文。其他的語言定義為子類,然后重新初始化這些字段為相應的語言的值。 另外一種更好的技術(適用于文本很大或者支持的語言數量眾多),可以讀取幾個單獨的表單,然后提供一些邏輯,根據所選擇的語言來選取正確的字符串。 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

    測試與調試

    40、實現一個圖形化的Log用來調試物理、動畫和AI。

    這可以顯著的加速調試工作。詳見這里。

    41、實現一個HTML的Log。

    在很多情況下,日志是非常有用的。擁有一個便于分析的Log(顏色編碼、有多個視圖、記錄屏幕截圖等)可以使基于Log的調試變動愉悅。詳見這里。

    42、實現一個你自己的幀速率計算器。

    沒有人知道Unity的FPS計算器在做什么,但是肯定不是計算幀速率。實現一個你自己的,讓數字符合直覺并可視化。

    43、實現一個截屏的快捷鍵。

    很多BUG是圖形化的,如果你有一個截圖,就很容易報告它。一個理想的系統,應該在PlayerPrefes中保存一個計數,并根據這個計數,使得所有成功保存的截屏文件都不被覆蓋掉。截屏文件應該保存在工程文件夾之外,這可以防止人們不小心把它提交到版本庫中。

    44、實現一個打印玩家坐標的快捷鍵。

    這可以在匯報位置相關的BUG時明確它發生在世界中的什么位置,這可以讓Debug容易一些。

    45、實現一些Debug選項,用來方便測試。

    一些例子:
    • 解鎖所有道具;
    • 關閉所有敵人;
    • 關閉GUI;
    • 讓玩家無敵;
    • 關閉所有游戲邏輯;

    46、為每一個足夠小的團隊,創建一個適合他們的Debug選項的Prefab。

    設置一個用戶標識文件,單不要提交到版本庫,在游戲運行時讀取它。下面是原因:
    • 團隊的成員不會因為意外的提交了自己的Debug設置而影響到其他人。
    • 修改Debug設置不需要修改場景。

    47、維護一個包含所有游戲元素的場景。

    例如,一個場景,包括所有的敵人,所有可以交互的對象等等。這樣可以不用玩很久,而進行全面的功能測試。

    48、定義一些Debug快捷鍵常量,并把他們保存在統一的地方。

    Debug鍵通常(方便起見)在一個地方來處理,就像其他的游戲輸入一樣。為了避免快捷鍵沖突,在一個中心位置定義所有常量。一種替代方案是,在一個地方處理所有按鍵輸入,不管他是否是Debug鍵。(負面作用是,這個類可能需要引用更多的其他對象)

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

    文檔

    49、為你的設置建立文檔。 代碼應該擁有最多的文檔,但是一些代碼之外的東西也必須建立文檔。讓設計師們通過代碼去看如果進行設置是浪費時間。把設置寫入文檔,可以提高效率(如果文檔的版本能夠及時更新的話)。 用文檔記錄下面這些:
    • Layer的使用(碰撞、檢測、射線檢測——本質上說,什么東西應該在哪個Layer里);
    • Tag的使用;
    • GUI的depth層級(說什么應該顯示在什么之上);
    • 慣用的處理方式;
    • Prefab結構;
    • 動畫Layer。
    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

    命名規則和目錄結構

    50、遵從一個命名規范和目錄結構,并建立文檔

    命名和目錄結構的一致性,可以方便查找,并明確指出什么東西在哪里。 你很有可能需要創建自己的命名規則和目錄結構,下面的例子僅供參考。

    普遍的命名規則

  • 名字應該代表它是什么,例如鳥就應該叫做Bird。
  • 選擇可以發音、方便記憶的名字。如果你在制作一個瑪雅文化相關的游戲,不要把關卡命名為QuetzalcoatisReturn。
  • 保持唯一性。如果你選擇了一個名字,就堅持用它。
  • 使用Pascal風格的大小寫,例如ComplicatedVerySpecificObject。 不要使用空格,下劃線,或者連字符,除了一個例外(詳見為同一事物的不同方面命名一節)。
  • 不要使用版本數字,或者標示他們進度的名詞(WIP、final)。
  • 不要使用縮寫:DVamp@W應該寫成DarkVampire@Walk。
  • 使用設計文檔中的術語:如果文檔中稱呼一個動畫為Die,那么使用DarkVampire@Die,而不要用DarkVampire@Death。
  • 保持細節修飾詞在左側:DarkVampire,而不是VampireDark;PauseButton,而不是ButtonPaused。舉例說明,在Inspector中查找PauseButton,比所有按鈕都以Button開頭方便。(很多人傾向于相反的次序,認為那樣名字可以自然的分組。然而,名字不是用來分組的,目錄才是。名字是用來在同一類對象中可以快速辨識的。)
  • 為一個序列使用同一個名字,并在這些名字中使用數字。例如PathNode0, PathNode1。永遠從0開始,而不是1。
  • 對于不是序列的情況,不要使用數字。例如?Bird0, Bird1, Bird2,本應該是Flamingo, Eagle, Swallow。
  • 為臨時對象添加雙下劃線前綴,例如__Player_Backup。
  • 為同一事物的不同方面命名

    在核心名稱后面添加下劃線,后面的部分代表哪個方面。例如
    • GUI中的按鈕狀態:EnterButton_Active、EnterButton_Inactive
    • 貼圖:?DarkVampire_Diffuse, DarkVampire_Normalmap
    • 天空盒:JungleSky_Top, JungleSky_North
    • LOD分組:DarkVampire_LOD0, DarkVampire_LOD1

    結構

    場景組織、工程目錄、腳本目錄應該使用相似的模式。

    目錄結構

    [plain]?view plain?copy ?
  • Materials??
  • GUI??
  • Effects??
  • Meshes??
  • ???Actors??
  • ??????DarkVampire??
  • ??????LightVampire??
  • ??????...??
  • ???Structures??
  • ??????Buildings??
  • ??????...??
  • ???Props??
  • ??????Plants??
  • ??????...??
  • ???...??
  • Plugins??
  • Prefabs??
  • ???Actors??
  • ???Items??
  • ???...??
  • Resources??
  • ???Actors??
  • ???Items??
  • ???...??
  • Scenes??
  • ???GUI??
  • ???Levels??
  • ???TestScenes??
  • Scripts??
  • Textures??
  • GUI??
  • Effects??
  • ...??
  • 場景結構

    [plain]?view plain?copy ?
  • Cameras??
  • Dynamic?Objects??
  • Gameplay??
  • ???Actors??
  • ???Items??
  • ???...??
  • GUI??
  • ???HUD??
  • ???PauseMenu??
  • ???...??
  • Management??
  • Lights??
  • World??
  • ???Ground??
  • ???Props??
  • ???Structure??
  • ???...??
  • 腳本目錄結構

    [plain]?view plain?copy ?
  • ThirdParty??
  • ???...??
  • MyGenericScripts??
  • ???Debug??
  • ???Extensions??
  • ???Framework??
  • ???Graphics??
  • ???IO??
  • ???Math??
  • ???...??
  • MyGameScripts??
  • ???Debug??
  • ???Gameplay??
  • ??????Actors??
  • ??????Items??
  • ??????...??
  • ???Framework??
  • ???Graphics??
  • ???GUI??
  • ???...??
  • ?

    ?


    轉載于:https://www.cnblogs.com/cokefenta/p/7910912.html

    總結

    以上是生活随笔為你收集整理的【转载】关于对方法实例化的相关感悟以及unity的50个技巧的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。