最近看到有朋友問一個unity游戲開發團隊,需要掌握哪些知識之類的問題。事實上Unity引擎是一個很靈活的引擎,根據團隊開發游戲類型的不同,對人員的要求也有差異,所以不能一概而論。但是,一些在Unity項目開發過程中常常會遇到的問題還是可以總結一下的。
下面我就來聊聊實際工作中,一個項目組可能會遇到的問題吧。
0x01.項目前期規划時的問題
這里指的不是策划的需求或者游戲玩法的計划,而是作為一個Unity項目我們需要在一開始明確並制定好的規范和標准。作為一個Unity項目或軟件項目,這部分是很重要的,因為項目早期的規划隨着項目的開發時間越久,就越難以修改。
對支持的最低機型不明確
作為一個Unity項目,我們首先要明確我們所需要支持的最低設備標准。並且項目組要有這樣的設備,以供開發和QA團隊使用。
否則,對項目的優化將無從談起。
資源標准不明確
開發過Unity項目的同學可能都有過類似的經歷,即開發過程中的資源標准不明確。這常常也是早期在項目規划時沒有重視資源標准導致的。
所以在項目的早期階段,最好能夠明確資源標准比如模型的vertex數量、紋理資源的尺寸格式等等。
也要對每幀開銷中,腳本和渲染所花費的時間有一個目標和預期。
沒有合理的Asset流水線
這里指的是資源應該按照一定的流程和標准從美術那里導入到Unity項目中。
很多項目最終出現性能問題,都是由於沒有一個合理的Asset流水線。從而導致項目內的資源標准無法管理,很多冗余或不符合目標設備水平的資源構建進了最終的安裝包里。
所以,作為項目組,大家一定要指定一套自動化的Asset流水線。為Asset的規格和標准制定明確的規范,在自動化腳本中進行設置。
例如texture是否開啟read/write?texture的壓縮格式?尺寸?非人形的model在導入時是否關閉了rigs?動畫模型是否開啟了Optimize Game Object選項?等等。
沒有合理的構建和QA流程
也有很多項目的構建並非一番風順,構建的版本也難以管理。策划或者QA常常是找負責某個功能的開發兵荒馬亂的打一個包出來。
所以項目組可以思考一下下面的幾個問題:
是否有專門的打包機?
一個新的功能是如何發布到最終的發布版本的?
是否有自動化的可持續集成設施(CI)?
QA要如何反饋Bug,Bug如何有效的管理?
正式項目直接在Demo原型上進行開發
這個也是一個常見的情況,有些項目組早期會有少數幾個人開發一些玩法演示Demo,Demo被認可之后開始開發正式的項目。
此時會有一個問題,即在Demo的基礎上直接開發正式項目。由於很多Demo只是為了演示玩法,所以代碼中有很多為了盡快實現需求的特定Hack。
如果正式項目以此為基礎,到后期維護會比較麻煩。
除了上面所提到的問題之外,還有一些別的需要重視的內容,例如制定統一的編碼規范、確定采用的光照模式(RealTime?Mixed?Baked?) 等等。
0x02.項目開發過程中的問題
經過了項目早期的規划階段,來到項目的開發階段時項目組有可能會犯哪些錯誤呢?一些不好的實踐有可能會拖慢項目的開發進度以及讓項目組成員的焦躁感上升。
不重視版本管理
很多團隊對版本管理不重視,或者團隊內部對版本管理例如git的操作不熟練。
當然,關於git的最佳實踐的資料有很多,建議項目組在內部進行培訓和普及,讓大家(程序美術策划etc)對版本管理的操作符合規范。
針對Unity項目,serialization 的格式建議設置為text serialization。
設置commit hook:
https://github.com/3pjgames/unity-git-hooks
靜態數據存儲在Json或XML文件保存
不少團隊喜歡或習慣於使用Json文件或XML文件來保存一些靜態數據,在游戲運行的時候加載使用。但是使用Json或XML文件保存數據會有以下的問題:
- 加載速度慢。
- Parse的時候會產生內存開銷。
所以數據最好使用二進制來保存,在Unity內部也提供了ScriptableObject來幫助保存數據。
項目中包含了沒有用到的資源、插件或冗余的庫
這也是很多團隊中常見的一個問題。一些廢棄的資源沒有及時處理,仍然留在項目中甚至被構建進入了最后的發布版本,從而造成不必要的開銷。
另一個問題是冗余或多份同樣功能的庫,比如項目中使用的插件中有多款插件都使用到了Json解析庫,那么就會造成冗余。
只在Editor中測試性能
這是一個很不好的開發習慣。因為在Editor中測試的是Editor的性能開銷,而不是在真正的目標平台上的性能開銷。所以在做Profile的時候,一定要在目標平台的設備上進行。否則只能得到讓人誤會的數據,例如在Editor中,GetComponent這個API會產生堆內存的分配,但是在真機上並不會產生堆內存的開銷。
詳情可以查看:
https://zhuanlan.zhihu.com/p/26763624
當然,更可怕的是真正的性能瓶頸被隱藏了,這樣只會讓Profile變成一件浪費時間而又沒有收益的事情。
開發者不了解Profiler工具
在開發Unity項目的過程中,常用的Profiler工具主要包括以下幾種:
Unity提供的:
- Unity自帶的Profiler:
https://unity3d.com/cn/learn/tutorials/topics/performance-optimization
- Unity內置的Frame Debugger
- Memory Profiler:
Unity-Technologies / MemoryProfiler - Bitbucket
移動平台相關的:
- Xcode Instruments
- Android Studio
- Mali Graphics Debugger
- Snapdragon Profiler
- Renderdoc
在項目后期才進行性能分析和優化
在開發的過程中就應該關注項目的性能問題,在日常的工作中就應該重視性能分析,而不是等到了項目后期甚至是deadline前才進行。
一方面是能做到對項目的性能問題心中有數,不會在后期手忙腳亂。
另一方面能夠及時發現問題,修正工作流程,不至於“開發債務”越積累越多。
0x03.寫代碼時的問題
開發者不了解Unity腳本的生命周期
有一些開發者由於不了解Unity腳本的生命周期,而出現一些程序上的錯誤和問題。
例如引擎什么時候會調用Awake、OnEnable、Update等等API?協程在什么時候會被更新?FixedUpdate又是怎么執行的?
可以參考Unity的文檔:
https://docs.unity3d.com/Manual/ExecutionOrder.html
FixedUpdate的執行可以查看:
https://zhuanlan.zhihu.com/p/30335370
過於重度的使用MonoBehavior以及Update
有些開發者喜歡在制作Demo甚至時正式開發項目的時候大量的依賴MonoBehavior以及Update方法。在Unity中MonoBehavior腳本的Update方法會被引擎記錄在一個List中,在運行時引擎會遍歷這個List,並調用其中的Update方法以實現腳本邏輯的更新。但是,原生代碼到托管代碼的調用總是會有性能上的開銷的,因此場景中的MonoBehavior以及Update過多會影響游戲的性能。
相關文檔可以參考:
https://blogs.unity3d.com/cn/2015/12/23/1k-update-calls/
沒有對需要頻繁訪問的數據進行緩存
這也是一個初學Unity的開發者有可能會犯的錯誤。要對需要頻繁訪問的數據進行緩存,以避免不必要的性能開銷。
例如訪問Camera.main,其背后的實現是FindObjectWithTag,因此如果沒有對這個值進行緩存,那么每次都會調用
FindObjectWithTag,這是一個開銷很大的操作。
另一個常見的情況就是GetComponent,對它的返回值也要進行緩存,以避免不必要的開銷。
頻繁實例化時不使用緩存池
這一點其實並不是什么新的觀點,或者是什么高階的知識。但是仍然有很多開發者可能忙於業務功能的實現,而沒有對此給予相應的重視,造成了性能上的瓶頸。
實例化操作是一個比較耗時的操作,所以切記當需要頻繁實例化時,創建一個池,並對其中的對象進行復用。
不了解會造成堆內存分配的API
C#的GC操作是造成游戲卡頓的一個常見原因。因此,對腳本堆內存分配的優化是很重要的。這里可以使用Unity的Profiler來檢測堆內存分配,除了重視堆內存分配很多的幀之外,對數量不起眼但是每幀都會有堆內存分配的方法也要重視。
Unity開發中,常見的會帶來堆內存分配的API主要有LINQ、String相關的操作以及返回Array的Unity的API。
例如Physics.RaycastAll,這個API每次調用都會返回一個Array的拷貝,因此更好的選擇是使用RaycastNonAlloc來代替。
還例如很多開發者喜歡在檢測用戶輸入時使用Input.touches,對這種property的訪問也會帶來一次Array的拷貝,所以更好的選擇是Input.GetTouch。
0x04.圖形以及UI開發中遇到的問題
項目的Overdraw太多了
這一點主要是開發移動平台項目的團隊需要注意的問題,Overdraw是導致圖形性能瓶頸的最常見的原因之一。所以要避免渲染不必要的半透明物體,也可以使用更復雜的mesh來勾出半透明的區域。
制作UI時遇到的種種問題
UI系統也是導致很多項目出現性能問題的原因,下面Unity官方公眾號總結出的《Unity UI性能優化技巧》是十分有參考價值的。
0x05.提醒
不基於數據來優化
今年Unite Berlin上,Ian做的一個Presentation的圖片可以很好的說明這一點。

除了數據,不要相信任何人,更不要迷信自己的經驗。通過之前提到過的各種性能測試工具來獲取目標平台上的真正數據,根據數據分析真正的性能瓶頸。並進行調整、對比來確認問題真正的得到了修改。
-EOF-
最后打個廣告,歡迎支持我的書
