Unity 開發人員最常犯的 10 個錯誤

已發表: 2022-03-11

Unity 是用於多平台開發的出色而直接的工具。 它的原理很容易理解,您可以直觀地開始創建您的產品。 但是,如果有些事情沒有考慮到,那麼當您將工作推進到下一個級別時,它們會減慢您的進度,因為您正從初始原型階段或接近最終版本。 本文將提供有關如何克服最常見問題以及如何避免新項目或現有項目中的基本錯誤的建議。 請注意,本文的觀點更側重於 3D 應用程序開發,但所提及的一切也適用於 2D 開發。

Unity 是用於多平台開發的出色而直接的工具。
鳴叫

常見的 Unity 錯誤 #1:低估項目規劃階段

對於每個項目,在項目的應用程序設計和編程部分開始之前確定幾件事情是至關重要的。 如今,當產品營銷成為整個過程的重要組成部分時,清楚了解所實施應用程序的業務模型將是什麼也很重要。 您必須確定您將為哪些平台發布產品,以及您的計劃中包含哪些平台。 還需要設置支持的最低設備規格(您會支持較舊的低端設備還是僅支持更新的型號?)以了解您可以承受的性能和視覺效果。 本文中的每個主題都受到這一事實的影響。

從更技術的角度來看,在將資產和模型提供給程序員的同時,應該提前設置創建資產和模型的整個工作流程,尤其是在模型需要進行更多更改和改進時的迭代過程。 您應該對所需的幀速率和頂點預算有一個清晰的概念,這樣 3D 藝術家才能知道模型必須達到的最大分辨率,以及他必須做多少 LOD 變化。 還應指定如何統一所有測量以具有一致的比例,並在整個應用程序中導入過程。

關卡的設計方式對未來的工作至關重要,因為關卡的劃分對性能有很大影響。 在設計新關卡時,您必須始終考慮性能問題。 不要帶著不切實際的願景去。 問問自己“可以合理實現嗎?”這個問題總是很重要的。 如果不是這樣,您不應該將寶貴的資源浪費在難以實現的事情上(當然,如果將其作為主要競爭優勢不是您業務戰略的一部分)。

常見的 Unity 錯誤 #2:使用未優化的模型

讓您的所有模型做好充分準備,以便能夠在您的場景中使用它們而無需進一步修改,這一點至關重要。 好的模型應該滿足幾件事。

正確設置比例很重要。 有時,由於這些應用程序使用的單位不同,因此無法從您的 3D 建模軟件中正確設置。 為了使一切正確,請在模型導入設置中設置比例因子(為 3dsMax 和 Modo 保留 0.01,為 Maya 設置 1.0),並註意有時您需要在更改比例設置後重新導入對象。 這些設置應確保您可以在場景中僅使用基本比例 1、1、1 來獲得一致的行為並且沒有物理問題。 動態批處理也更有可能正常工作。 此規則也應應用於模型中的每個子對象,而不僅僅是主對象。 當您需要調整對象尺寸時,請在 3D 建模應用程序中而不是在 Unity 中針對其他對象進行調整。 但是,您可以在 Unity 中嘗試縮放以找出合適的值,但對於最終應用程序和一致的工作流程,最好在導入 Unity 之前做好一切準備。

關於對象的功能及其動態部分 - 讓您的模型得到很好的劃分。 子對象越少越好。 將對象的各個部分分開,以備不時之需,例如,動態移動或旋轉、用於動畫目的或其他交互。 每個對象及其子對像都應使其樞軸相對於其主要功能正確對齊和旋轉。 主對象的 Z 軸應指向前方,並且樞軸應位於對象的底部,以便更好地放置在場景中。 在物體上使用盡可能少的材料(更多內容見下文)。

所有資產都應具有適當的名稱,以便輕鬆描述其類型和功能。 在所有項目中保持這種一致性。

常見的 Unity 錯誤 #3:構建相互依賴的代碼架構

Unity 中功能的原型設計和實現非常容易。 您可以輕鬆拖放對其他對象的任何引用,處理場景中的每個對象,並訪問它擁有的每個組件。 但是,這也可能存在潛在危險。 除了明顯的性能問題(在層次結構中查找對象和訪問組件有其開銷)之外,使部分代碼完全相互依賴也存在很大的危險。 或者依賴於您的應用程序特有的其他系統和腳本,甚至依賴於當前場景或當前場景。 嘗試採用更加模塊化的方法並創建可重用的部分,這些部分可用於應用程序的其他部分,甚至可以在整個應用程序組合中共享。 在 Unity API 之上構建您的框架和庫,就像您構建知識庫一樣。

有很多不同的方法可以確保這一點。 一個好的起點是 Unity 組件系統本身。 當特定組件需要與應用程序的其他系統通信時,可能會出現複雜情況。 為此,您可以使用接口使系統的某些部分更加抽象和可重用。 或者,您可以使用事件驅動的方法對來自外部範圍的特定事件做出反應,方法是創建消息傳遞系統或直接註冊到其他系統的部分作為偵聽器。 正確的方法是嘗試將游戲對象屬性與程序邏輯分開(至少類似於模型控制器原理),因為很難確定哪些對象正在修改其變換屬性,例如位置和旋轉。 這應該完全是其控制者的責任。

嘗試使所有內容都有據可查。 總是把它當作你應該在很長一段時間後返回你的代碼,並且你需要快速理解這部分代碼到底在做什麼。 因為實際上,您經常會在一段時間後到達應用程序的某些部分,這對於快速解決問題是不必要的障礙。 但不要過度。 有時,一個適當的類、方法或屬性名稱就足夠了。

常見的 Unity 錯誤 #4:浪費你的表現

最新的手機、遊戲機或台式電腦產品線永遠不會先進到無需關心性能。 性能優化總是需要的,它們為使您的遊戲或應用程序與市場上的其他產品相比看起來有所不同提供了基礎。 因為當您在一個部分中保存一些性能時,您可以使用它來完善應用程序的其他部分。

有很多地方需要優化。 需要整篇文章來了解這個主題的表面。 至少,我會嘗試將這個領域劃分為一些核心領域。

更新循環

不要在更新循環中使用性能密集型的東西,而是使用緩​​存。 一個典型的例子是訪問場景中的組件或其他對像或腳本中的密集計算。 如果可能,將所有內容緩存在Awake()方法中,或者將您的架構更改為更加事件驅動的方法,以便在需要時觸發事件。

實例化

對於經常實例化的對象(例如,FPS 遊戲中的子彈),為它們創建一個預先初始化的池,並在需要時選擇一個已經初始化並激活它。 然後,不要在不再需要它時將其銷毀,而是將其停用並將其返回到池中。

渲染

使用遮擋剔除或 LOD 技術來限制場景的渲染部分。 嘗試使用優化模型來控制場景中的頂點數。 請注意,頂點數不僅僅是模型本身的頂點數,它還會受到法線(硬邊)、UV 坐標(UV 接縫)和頂點顏色等其他因素的影響。 此外,場景中的一些動態燈光會極大地影響整體性能,因此請盡可能提前烘焙所有內容。

繪製調用

嘗試減少繪圖調用次數。 在 Unity 中,您可以通過對靜止對象使用靜態批處理和對移動對象使用動態批處理來減少繪製調用。 但是,您必須首先準備場景和模型(批處理對象必須共享相同的材質),並且動態對象的批處理僅適用於低分辨率模型。 或者,您可以通過腳本將網格組合成一個 ( Mesh.CombineMeshes ) 而不是使用批處理,但您必須注意不要創建太大的對象,因為在某些平台上無法利用視錐體剔除。 一般來說,關鍵是盡可能少地使用材料並在整個場景中共享它們。 您有時需要從紋理創建圖集,以便能夠在不同對象之間共享一種材質。 一個好的技巧是在較大的環境中烘焙光照時,使用更高分辨率的場景光照貼圖紋理(不是生成的分辨率,而是紋理輸出的分辨率)來降低它們的數量。

透支問題

不需要時不要使用透明紋理,因為它會導致填充率問題。 可以將它用於復雜且更遠的幾何圖形,例如樹木或灌木叢。 當您需要使用它時,更喜歡 alpha 混合著色器而不是帶有 alpha 測試的著色器或移動平台的剪切著色器。 通常,為了識別這些問題,請嘗試降低應用程序的分辨率。 如果有幫助,您可能會遇到這些填充率問題,或者您需要進一步優化著色器。 否則,可能是更多的內存問題。

著色器

優化著色器以獲得更好的性能。 減少通過次數,使用精度較低的變量,用預先生成的查找紋理替換複雜的數學計算。

始終使用分析器來確定瓶頸。 這是一個很棒的工具。 對於渲染,您還可以使用很棒的 Frame Debugger,它可以幫助您了解很多關於使用它分解渲染過程時一般情況下的工作原理。

常見的 Unity 錯誤 #5:忽略垃圾收集問題

有必要意識到,儘管垃圾收集器 (GC) 本身可以幫助我們提高效率並專注於編程中的重要事情,但我們應該明確了解一些事情。 GC 的使用不是免費的。 通常,我們應該避免不必要的內存分配,以防止 GC 過於頻繁地觸發自身,從而因幀率峰值而破壞性能。 理想情況下,每幀根本不應該有任何新的內存分配定期發生。 然而,我們怎樣才能實現這個目標呢? 這實際上是由應用程序架構決定的,但是您可以遵循一些有助於幫助的規則:

  • 避免在更新循環中進行不必要的分配。
  • 將結構用於簡單的屬性容器,因為它們不是在堆上分配的。
  • 嘗試預先分配數組或列表或其他對象集合,而不是在更新循環中創建它們。
  • 避免使用單聲道有問題的東西(例如 LINQ 表達式或 foreach 循環),因為 Unity 使用的是較舊的、未經過理想優化的 Mono 版本(在撰寫本文時,它是經過修改的 2.6 版,並在路線圖上進行了升級)。
  • Awake()方法或事件中緩存字符串。
  • 如果需要在更新循環中更新字符串屬性,請使用 StringBuilder 對象而不是字符串。
  • 使用分析器來識別潛在問題。

常見的 Unity 錯誤 #6:最後優化內存和空間使用

有必要從項目一開始就關注應用程序的最低內存和空間使用率,因為當您將優化留在預發布階段時,這樣做會更加複雜。 在移動設備上,這一點更為重要,因為我們那裡的資源非常短缺。 此外,如果安裝大小超過 100MB,我們可能會失去大量客戶。 這是因為蜂窩網絡下載有 100MB 的限制,也因為心理原因。 當您的應用程序不浪費客戶寶貴的電話資源時總是更好,並且當應用程序較小時,他們更有可能下​​載或購買您的應用程序。

要查找資源消耗者,您可以使用編輯器日誌,您可以在其中查看(在每次新構建之後)分為不同類別的資源大小,例如音頻、紋理和 DLL。 為了更好地定位,Unity Asset Store 上有編輯器擴展,它將為您提供文件系統中引用的資源和文件的詳細摘要。 實際內存消耗也可以在分析器中看到,但建議在連接到目標平台上構建時對其進行測試,因為在編輯器或目標平台以外的任何東西上進行測試時會出現很多不一致。

最大的內存消耗者通常是紋理。 最好使用壓縮紋理,因為它們佔用的空間和內存要少得多。 使所有紋理平方,理想情況下,使兩邊的長度為 2 的冪 (POT),但請記住,Unity 也可以自動將 NPOT 紋理縮放為 POT。 當處於 POT 形式時,可以壓縮紋理。 Atlas 紋理一起填充整個紋理。 有時您甚至可以使用紋理 Alpha 通道為著色器提供一些額外信息,以節省額外空間和性能。 當然,盡量為場景重複使用紋理,並在可能保持良好視覺外觀的情況下使用重複紋理。 對於低端設備,您可以在質量設置中降低紋理的分辨率。 對較長的音頻片段(如背景音樂)使用壓縮音頻格式。

當您處理不同的平台、分辨率或本地化時,您可以使用資產包為不同的設備或用戶使用不同的紋理集。 安裝應用程序後,可以從 Internet 動態加載這些資產包。 這樣,您可以在遊戲期間通過下載資源來超過 100MB 的限制。

常見的 Unity 錯誤 #7:常見的物理錯誤

有時,當在場景中移動物體時,我們沒有意識到物體上有一個碰撞器,改變它的位置會迫使引擎重新計算整個物理世界。 在這種情況下,您應該為其添加Rigidbody組件(如果您不希望涉及外力,可以將其設置為非運動學)。

要修改帶有Rigidbody的對象的位置,請始終在新位置不跟隨前一個位置時設置Rigidbody.position ,或在連續移動時設置Rigidbody.MovePosition ,這也考慮了插值。 修改它時,始終在FixedUpdate中應用操作,而不是在Update函數中。 它將確保一致的物理行為。

如果可能,請在遊戲對像上使用原始碰撞器,例如球體、長方體或圓柱體,而不是網格碰撞器。 您可以從多個對撞機中合成最終的對撞機。 物理可能是應用程序的性能瓶頸,因為它的 CPU 開銷和原始碰撞器之間的碰撞計算速度要快得多。 您還可以在時間管理器中調整固定時間步長設置,以在不需要物理交互的準確性時減少物理固定更新的頻率。

常見的 Unity 錯誤 #8:手動測試所有功能

有時可能會傾向於通過在播放模式下進行試驗來手動測試功能,因為它非常有趣,並且您可以直接控制一切。 但是這個很酷的因素會很快減少。 應用程序變得越複雜,程序員必須重複和考慮的任務就越繁瑣,以確保應用程序的行為符合最初的預期。 由於其重複性和被動性,它很容易成為整個開發過程中最糟糕的部分。 此外,由於手動重複測試場景並不那麼有趣,因此某些錯誤更有可能貫穿整個測試過程。

Unity 有很好的測試工具來自動執行此操作。 通過適當的架構和代碼設計,您可以使用單元測試來測試孤立的功能,甚至可以使用集成測試來測試更複雜的場景。 您可以顯著減少記錄實際數據並將其與所需狀態進行比較的嘗試檢查方法。

毫無疑問,手動測試是開發的關鍵部分。 但是它的數量可以減少,整個過程可以更加健壯和快速。 如果無法實現自動化,請準備好您的測試場景,以便能夠盡快解決您要解決的問題。 理想情況下,點擊播放按鈕後的幾幀。 實施快捷方式或作弊以設置所需的測試狀態。 此外,將測試情況隔離起來,以確定是什麼導致了問題。 遊戲模式中每一次不必要的測試都在累積,測試問題的初始偏差越大,你就越有可能根本不測試問題,你會希望一切正常。 但它可能不會。

常見的 Unity 錯誤 #9:認為 Unity Asset Store 插件將解決您的所有問題

相信我; 他們不會。 在與一些客戶合作時,我有時會面臨過去使用資產商店插件處理每一件小事的趨勢或遺留問題。 我並不是說 Unity Asset Store 上沒有有用的 Unity 擴展。 它們有很多,有時甚至很難決定選擇哪一個。 但是對於每個項目來說,保持一致性很重要,因為不明智地使用不能很好地組合在一起的不同部分可能會破壞一致性。

另一方面,對於需要很長時間才能實現的功能,使用 Unity Asset Store 中經過良好測試的產品總是很有用的,這可以為您節省大量的開發時間。 但是,請謹慎選擇,使用經過驗證的,不會給您的最終產品帶來很多無法控制和奇怪的錯誤。 五星級評論是一個很好的開始。

如果您想要的功能不難實現,只需將其添加到您不斷增長的個人(或公司)庫中,以後可以在您的所有項目中再次使用這些庫。 這樣,您就可以同時提高您的知識和工具集。

Unity 常見錯誤 #10:無需擴展 Unity 基本功能

有時 Unity Editor 環境對於基本的遊戲測試和關卡設計來說似乎已經足夠了,擴展它是浪費時間。 但相信我,事實並非如此。 Unity 的巨大擴展潛力來自於能夠使其適應各種項目中需要解決的特定問題。 這可以改善在 Unity 中工作時的用戶體驗,也可以顯著加快整個開發和關卡設計工作流程。 不幸的是不使用內置功能,例如內置或自定義的屬性抽屜、裝飾器抽屜、自定義組件檢查器設置,甚至不使用自己的編輯器窗口構建整個插件。

結論

我希望這些主題在您進一步推動 Unity 項目時對您有用。 有很多東西是項目特定的,所以它們不能被應用,但是在嘗試解決更困難和更具體的問題時,記住一些基本規則總是有用的。 對於如何在項目中解決這些問題,您可能有不同的意見或程序。 最重要的是在整個項目中保持慣用語的一致性,以便團隊中的任何人都可以清楚地了解應該如何正確解決特定領域。


進一步閱讀 Toptal 工程博客:

  • Unity AI 開發:有限狀態機教程