最近看到有朋友問一個unity遊戲開發團隊,須要掌握哪些知識之類的問題。事實上Unity引擎是一個很靈活的引擎,根據團隊開發遊戲類型的不一樣,對人員的要求也有差別,因此不能一律而論。可是,一些在Unity項目開發過程當中經常會遇到的問題仍是能夠總結一下的。html
下面我就來聊聊實際工做中,一個項目組可能會遇到的問題吧。node
這裏指的不是策劃的需求或者遊戲玩法的計劃,而是做爲一個Unity項目咱們須要在一開始明確並制定好的規範和標準。做爲一個Unity項目或軟件項目,這部分是很重要的,由於項目早期的規劃隨着項目的開發時間越久,就越難以修改。git
對支持的最低機型不明確
做爲一個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?) 等等。github
通過了項目早期的規劃階段,來到項目的開發階段時項目組有可能會犯哪些錯誤呢?一些很差的實踐有可能會拖慢項目的開發進度以及讓項目組成員的焦躁感上升。
不重視版本管理
不少團隊對版本管理不重視,或者團隊內部對版本管理例如git的操做不熟練。
固然,關於git的最佳實踐的資料有不少,建議項目組在內部進行培訓和普及,讓你們(程序美術策劃etc)對版本管理的操做符合規範。
針對Unity項目,serialization 的格式建議設置爲text serialization。
設置commit hook:編程
https://github.com/3pjgames/unity-git-hooks緩存
靜態數據存儲在Json或XML文件保存
很多團隊喜歡或習慣於使用Json文件或XML文件來保存一些靜態數據,在遊戲運行的時候加載使用。可是使用Json或XML文件保存數據會有如下的問題:性能優化
因此數據最好使用二進制來保存,在Unity內部也提供了ScriptableObject來幫助保存數據。
項目中包含了沒有用到的資源、插件或冗餘的庫
這也是不少團隊中常見的一個問題。一些廢棄的資源沒有及時處理,仍然留在項目中甚至被構建進入了最後的發佈版本,從而形成沒必要要的開銷。
另外一個問題是冗餘或多份一樣功能的庫,好比項目中使用的插件中有多款插件都使用到了Json解析庫,那麼就會形成冗餘。工具
只在Editor中測試性能性能
這是一個很很差的開發習慣。由於在Editor中測試的是Editor的性能開銷,而不是在真正的目標平臺上的性能開銷。因此在作Profile的時候,必定要在目標平臺的設備上進行。不然只能獲得讓人誤會的數據,例如在Editor中,GetComponent這個API會產生堆內存的分配,可是在真機上並不會產生堆內存的開銷。測試
詳情能夠查看:
https://zhuanlan.zhihu.com/p/26763624
固然,更可怕的是真正的性能瓶頸被隱藏了,這樣只會讓Profile變成一件浪費時間而又沒有收益的事情。
開發者不瞭解Profiler工具
在開發Unity項目的過程當中,經常使用的Profiler工具主要包括如下幾種:
Unity提供的:
https://unity3d.com/cn/learn/tutorials/topics/performance-optimization
Unity-Technologies / MemoryProfiler - Bitbucket
移動平臺相關的:
在項目後期才進行性能分析和優化
在開發的過程當中就應該關注項目的性能問題,在平常的工做中就應該重視性能分析,而不是等到了項目後期甚至是deadline前才進行。
一方面是能作到對項目的性能問題心中有數,不會在後期手忙腳亂。
另外一方面可以及時發現問題,修正工做流程,不至於「開發債務」越積累越多。
開發者不瞭解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。
項目的Overdraw太多了
這一點主要是開發移動平臺項目的團隊須要注意的問題,Overdraw是致使圖形性能瓶頸的最多見的緣由之一。因此要避免渲染沒必要要的半透明物體,也可使用更復雜的mesh來勾出半透明的區域。
製做UI時遇到的種種問題
UI系統也是致使不少項目出現性能問題的緣由,下面Unity官方公衆號總結出的《Unity UI性能優化技巧》是十分有參考價值的。
不基於數據來優化
今年Unite Berlin上,Ian作的一個Presentation的圖片能夠很好的說明這一點。
除了數據,不要相信任何人,更不要迷信本身的經驗。經過以前提到過的各類性能測試工具來獲取目標平臺上的真正數據,根據數據分析真正的性能瓶頸。並進行調整、對比來確認問題真正的獲得了修改。
-EOF-
最後打個廣告,歡迎支持個人書