Home / Unity / ScriptableObjects 可使您的團隊和代碼受益的 6 種方式

ScriptableObjects 可使您的團隊和代碼受益的 6 種方式

https://blog.unity.com/engine-platform/6-ways-scriptableobjects-can-benefit-your-team-and-your-code

ScriptableObjects 使您的團隊和代碼受益的 6 種方式 |  英雄形象

我們很高興地宣布,我們推出了一本新的技術電子書,使用 ScriptableObjects 在 Unity 中創建模塊化遊戲架構,其中提供了專業開發人員在生產中部署 ScriptableObjects 的最佳實踐。

除了電子書,您還可以從GitHub下載一個受經典球拍街機遊戲機制啟發的演示項目。該演示展示了 ScriptableObjects 如何幫助您創建可測試和可擴展的組件,同時也對設計人員友好。雖然像這樣的遊戲可以用更少的代碼行來構建,但這個演示展示了 ScriptableObjects 的實際應用。

電子書隨附球拍演示。

電子書隨附了一個 Scriptable Object 演示項目,可在 Github 上找到。

這篇文章解釋了 ScriptableObjects 的好處,但沒有涵蓋 Unity 中的基礎知識或一般編碼。如果您不熟悉 Unity 編程,請前往 Unity Learn,它提供有用的介紹性教程。電子書的第一章還提供了紮實的入門知識。

讓我們看看您可以從在項目中使用 ScriptableObjects 中獲益的六種方式。想知道更多?在電子書和演示項目中將進一步探討所有這些示例。

 

1、高效的團隊協作(Efficient team collaboration)

儘管此處共享的許多技術也可以使用 C# 類實現,但 ScriptableObjects 的主要優勢之一是藝術家和設計師的可訪問性。他們可以使用 ScriptableObjects 在項目中配置和應用遊戲邏輯,而無需編輯代碼。

編輯器可以方便地查看和編輯 ScriptableObjects,使設計人員無需開發團隊的大量支持即可設置遊戲數據。這也適用於遊戲邏輯,例如通過添加 ScriptableObject 將行為應用於 NPC(在下面的模式中解釋)。

如果兩個人更改同一預製件或場景的不同部分,則在單個 MonoBehaviour 上存儲數據和邏輯可能會導致耗時的合併衝突。通過使用 ScriptableObjects 將共享數據分解為更小的文件和資產,設計人員可以與開發人員並行構建遊戲玩法,而不必等待後者在測試之前完成代碼中的遊戲設置。

當具有不同角色的同事同時訪問遊戲代碼和資產時,就會出現問題。使用 ScriptableObjects,程序員可以控制項目的哪一部分在編輯器中是可編輯的。此外,使用 ScriptableObjects 來組織您的代碼自然會導致代碼庫更加模塊化和更高效的測試。

了解遊戲設計師如何使用 ScriptableObjects

Christo Nobbs 是一名高級技術遊戲設計師,專門從事系統遊戲設計和 Unity (C#),他為Unity 遊戲設計師手冊做出了貢獻,並且是關於在 Unity 中設計遊戲系統的博客文章系列的主要作者。他的博文“創造生態系統的系統:​​緊急遊戲設計”和“意想不到的樂趣:遊戲設計中隨機化的價值”提供了設計師如何使用 ScriptableObjects 的有趣示例。

2. 數據容器(Data containers)

模塊化是一種通用的軟件原則,可以在不使用 ScriptableObjects 的情況下在 C# 中實現。但是,如上所述,ScriptableObjects 通過將數據與邏輯分離來幫助促進乾淨的編碼實踐,這是邁向模塊化遊戲代碼的第一步。這種分離意味著在不引起意外副作用的情況下更容易進行更改,並提高了可測試性。

ScriptableObjects 擅長存儲靜態數據,使它們可以方便地配置靜態遊戲值,如項目或 NPC 統計數據、角色對話等等。因為 ScriptableObjects 被保存為資產,它們在遊戲模式之外仍然存在,使得可以使用它們加載靜態配置,該靜態配置在運行時動態變化。

雖然對 ScriptableObject 數據的更改確實會保留在編輯器中,但請務必注意,它們不是為保存遊戲數據而設計的。在這種情況下,最好使用序列化系統,例如 JSON、XML 或二進制解決方案(如果性能至關重要)。

MonoBehaviours 帶來額外的開銷,因為它們需要一個 GameObject——默認情況下是一個 Transform——來充當宿主。這意味著您需要在存儲單個值之前創建大量未使用的數據。ScriptableObject 減少了內存佔用並刪除了 GameObject 和 Transform。它還在項目級別存儲數據,如果您需要從多個場景訪問相同的數據,這將很有幫助。

許多遊戲對象依賴於不需要在運行時更改的重複數據是很常見的。您可以將其匯集到一個 ScriptableObject 中,而不是在每個 GameObject 上都有這種重複的本地數據。每個對像都存儲對共享數據資產的引用,而不是複制數據本身。這可以在具有數千個對象的項目中提供顯著的性能改進。

許多具有重複本地數據的對象會導致性能低下。

許多具有重複本地數據的對象會導致性能低下

許多對象通過 ScriptableObject 共享數據(而不是複制數據)

許多對象通過 ScriptableObject 共享數據(而不是複制數據)

在軟件設計中,這是一種稱為享元模式的優化。使用 ScriptableObjects 以這種方式重構代碼可避免複製值並減少內存佔用。查看我們的電子書,使用遊戲編程模式升級您的代碼,了解有關在 Unity 中使用設計模式的更多信息。

3.枚舉(Enums)

ScriptableObjects 如何簡化代碼的一個很好的例子是將它們用作比較操作的枚舉。ScriptableObject 可以代表一個類別或項目類型,例如特殊的傷害效果——冷、熱、電、魔法等。

如果您的應用程序需要庫存系統來裝備遊戲項目,ScriptableObjects 可以表示項目類型或武器槽。Inspector 中的字段然後用作用於設置它們的拖放界面。

拖放基於 ScriptableObject 的類別

拖放基於 ScriptableObject 的類別

當您想要擴展它們並添加更多數據時,使用 ScriptableObjects 作為枚舉會變得更加有趣。與普通枚舉不同,ScriptableObjects 可以有額外的字段和方法。無需單獨的查找表或關聯新的數據數組。

傳統枚舉具有一組固定的值,而 ScriptableObject 枚舉可以在運行時創建和修改,允許您根據需要添加或刪除值。

如果您有一長串沒有顯式編號的枚舉值,則插入或刪除枚舉可以更改它們的順序。這種重新排序可能會引入細微的錯誤或意外行為。基於 ScriptableObject 的枚舉沒有這些問題。您可以刪除或添加到您的項目中,而不必每次都更改代碼。

假設您想在角色扮演遊戲中製作一個可裝備的物品。您可以將額外的布爾字段附加到 ScriptableObject 來執行此操作。某些角色是否不允許持有某些物品?有些物品是神奇的還是具有特殊能力?基於 ScriptableObject 的枚舉可以做到這一點。

4.委託物件(Delegate objects)

因為您可以在 ScriptableObject 上創建方法,所以它們對於包含邏輯或操作和保存數據一樣有用。將邏輯從您的 MonoBehaviour 移動到 ScriptableObject 使您能夠將後者用作委託物件,從而使行為更加模塊化。

如果你需要執行特定的任務,你可以將他們的算法封裝到他們自己的物件中。最初的四人幫將這種通用設計稱為策略模式。下面的示例展示瞭如何通過使用抽像類來實現 EnemyAI 來使策略模式更有用。結果是幾個具有不同行為的派生 ScriptableObjects,然後成為可插入行為,因為每個資產都是可互換的。您只需將選擇的 ScriptableObject 拖放到 MonoBehaviour 中。

可插入行為可以在運行時或在編輯器中更改。

可插入行為可以在運行時或在編輯器中更改

有關顯示如何使用 ScriptableObjects 驅動行為的詳細示例,請觀看視頻系列Pluggable AI with ScriptableObjects。這些會議演示了一個基於有限狀態機的 AI 系統,可以使用 ScriptableObjects 配置狀態、動作和這些狀態之間的轉換。

5.事件通道(Event channels)

大型項目中的一個常見挑戰是,當多個遊戲對象需要通過避免這些對象之間的直接引用來共享數據或狀態時。大規模管理這些依賴關係可能需要付出巨大的努力,而且通常是錯誤的來源。許多開發人員使用單例——一個在場景加載後仍然存在的類的全局實例。然而,單例引入了全局狀態並使單元測試變得困難。如果您正在使用引用單例的預製件,您將最終導入其所有依賴項只是為了測試一個獨立的功能。這會降低您的代碼的模塊化程度和調試效率。

一種解決方案是使用基於 ScriptableObject 的事件來幫助您的遊戲對象進行通信。在這種情況下,您使用 ScriptableObjects 來實現觀察者設計模式的一種形式,其中主題向一個或多個鬆散解耦的觀察者廣播消息。每個觀察對像都可以獨立於主體做出反應,但不會意識到其他觀察者。主體也可以稱為“發布者”或“廣播者”,而觀察者則稱為“訂閱者”或“聽眾”。

您可以使用 MonoBehaviours 或C# 對象來實現觀察者模式。雖然這已經是 Unity 開發中的常見做法,但僅使用腳本的方法意味著您的設計師將依賴編程團隊來處理遊戲過程中所需的每個事件。

基於 ScriptableObject 的事件通道

基於 ScriptableObject 的事件通

乍一看,您似乎為觀察者模式添加了一層開銷,但這種結構提供了一些優勢。由於 ScriptableObjects 是資產,因此層次結構中的所有對像都可以訪問它們,並且不會在場景加載時消失。

對某些資源的輕鬆、持久的訪問是許多開發人員使用單例的原因。ScriptableObjects 通常可以提供相同的好處,而無需引入那麼多不必要的依賴項。

在基於 ScriptableObject 的事件中,任何對像都可以充當發布者(廣播事件),任何對像都可以充當訂閱者(偵聽事件)。ScriptableObject 位於中間並幫助中繼信號,充當兩者之間的中央中介。

一種思考方式是將其視為“事件通道”。將 ScriptableObject 想像成一個無線電塔,有任意數量的對象監聽它的信號。感興趣的 MonoBehaviour 可以訂閱事件通道並在發生某些事情時做出響應。

該演示展示了觀察者模式如何幫助您為 UI、聲音和計分設置遊戲事件。

6.運行時集(Runtime Sets)

在運行時,您通常需要跟踪場景中的遊戲對像或組件列表。例如,敵人列表是您需要經常訪問的內容,但它也是一個動態列表,會隨著生成或擊敗更多敵人而變化。單例提供了簡單的全局訪問,但它有幾個缺點。考慮將數據存儲在 ScriptableObject 上作為“運行時集”,而不是使用單例。ScriptableObject 實例出現在項目級別,這意味著它可以存儲任何場景中任何對象可用的數據,提供類似的全局訪問。由於數據位於資產上,因此可以隨時訪問其公共項目列表。

在此用例中,您將獲得一個專門的數據容器,它維護元素的公共集合,但也提供向集合添加和從集合中刪除的基本方法。這可以減少對單例的需求並提高可測試性和模塊化。

運行時集提供對數據集合的全局訪問。

運行時集提供對數據集合的全局訪問

直接從 ScriptableObject 讀取數據也比使用Object.FindObjectOfTypeGameObject.FindWithTag等查找操作搜索場景層次結構更優化。根據您的用例和層次結構的大小,這些是相對昂貴的方法,對於每幀更新可能效率低下。

有幾個 ScriptableObjects 框架提供了比這六個場景更多的用例。一些團隊決定廣泛使用 ScriptableObjects,而其他團隊則將其使用限制在加載靜態數據和將邏輯與數據分離。最終,您的項目需求將決定您如何使用它們。

Unity程序員進階系列

使用 ScriptableObjects 在 Unity 中創建模塊化遊戲架構是我們系列中針對中高級 Unity 程序員的第三篇指南。每份指南均由經驗豐富的程序員編寫,針對對開發團隊很重要的主題提供最佳實踐。

創建 C# 風格指南:編寫可縮放的更清晰的代碼,幫助您開發風格指南,以幫助統一您創建更具凝聚力的代碼庫的方法。

使用遊戲編程模式升級您的代碼 重點介紹了使用 SOLID 原則和通用編程模式在您的 Unity 項目中創建可擴展遊戲代碼架構的最佳實踐。

我們創建這個系列的目的是為我們經驗豐富的創作者提供可行的技巧和靈感,但它們不是規則手冊。構建 Unity 項目的方法有很多種,看起來很適合一個應用程序的方法可能並不適合另一個應用程序。在部署之前,與您的同事一起評估每個建議、提示和模式的優點和缺點。

在Unity 最佳實踐中心找到更多高級指南和文章。

“使用 ScriptableObjects 在 Unity 中創建模塊化遊戲架構”的電子書封面

Check Also

UREAL虛幻引擎助力開放世界動作遊戲《幻塔》登上行動、PC與PS平台

UREAL虛幻引擎助力開放世界動作遊戲《幻塔》登上行動、PC與PS平台

麥克威廉斯 | 2023年9月 …

快樂豐收演示:了解最新的 2D 技術

快樂豐收演示:了解最新的 2D 技術

https://blog.un …

激勵視頻廣告展示位置的基礎知識

激勵視頻廣告展示位置的基礎知識

https://blog.un …

發佈留言