【Unity 插件推薦】DOTS 效能咒術師,展開資料導向的性能領域,秒殺卡頓咒靈!

目錄
【Unity 插件推薦】Enhanced On-Screen Stick 搖桿操控大師,流暢移動體驗一鍵搞定!

 

前言

 

今天要推薦的是 Unity DOTS(Data-Oriented Technology Stack),一套資料驅動的開發工具組,為 Unity 遊戲帶來前所未有的高效能突破!

不同於傳統以 GameObject 為基礎的開發方式,DOTS 透過【ECS】、【Jobs】與【Burst Compiler】打造出極致的運行效率,特別適合需要處理【大量實體】、【複雜運算】或【大規模場景】的遊戲。

 

不論你正在開發【百萬物件的模擬遊戲】、【即時戰略 AI 控制系統】或【開放世界動態生態系統】,DOTS 都能【解放 CPU 能力】、【減少 GC 開銷】,甚至改變你對 Unity 效能的想像!

本篇文章將從 DOTS 的核心結構講起,介紹如何【安裝】與【啟用】 ECS 模組,並透過簡單案例逐步實作旋轉效果,讓你快速掌握 DOTS 的基礎用法!

今天要推薦的是 Unity DOTS(Data-Oriented Technology Stack),一套資料驅動的開發工具組,為 Unity 遊戲帶來前所未有的高效能突破!  不同於傳統以 GameObject 為基礎的開發方式,DOTS 透過【ECS】、【Jobs】與【Burst Compiler】打造出極致的運行效率,特別適合需要處理【大量實體】、【複雜運算】或【大規模場景】的遊戲。    不論你正在開發【百萬物件的模擬遊戲】、【即時戰略 AI 控制系統】或【開放世界動態生態系統】,DOTS 都能【解放 CPU 能力】、【減少 GC 開銷】,甚至改變你對 Unity 效能的想像!  本篇文章將從 DOTS 的核心結構講起,介紹如何【安裝】與【啟用】 ECS 模組,並透過簡單案例逐步實作旋轉效果,讓你快速掌握 DOTS 的基礎用法!

 

 

Unity DOTS 插件介紹

 

DOTS(Data-Oriented Technology Stack)是 Unity 官方推出的高效能開發工具組,專為【解決大型場景】、【高頻運算】與【效能瓶頸問題】而設計。

Unity 2022 起,DOTS 中的 Entities 模組已進入穩定階段,在 Unity 6 中更可直接透過 Package Manager 安裝使用。

 

DOTS 適用於【URP】或【HDRP】渲染管線,可與現代化圖形流程無縫整合,支援【大量實體處理】與【高效能資料驅動邏輯】。

搭配 Entities Graphics 套件,可實現高效能的 ECS 實體渲染,讓你在場景中輕鬆操作數千甚至數萬個物件而不卡頓。

DOTS 插件示意圖

 

功能特色

  1. 高效資料導向架構
    DOTS 採用 ECS 模型,讓【資料】與【邏輯】完全分離。實體(Entity)儲存資料,系統(System)負責運算,能精準控制【記憶體配置】與【資料存取順序】,大幅提升 CPU 【快取命中率】與【執行效率】,特別適合需要大量實體處理的遊戲開發。
  2. 全自動多執行緒排程
    透過 Jobs System,開發者能輕鬆撰寫可平行執行的邏輯,Unity 會自動處理【執行緒安全】與【排程分配】,無需手動管理【鎖定】與【同步】。搭配 Burst Compiler 使用時,能進一步壓榨多核心 CPU 效能,讓大量邏輯同時執行不卡頓。
  3. 易於擴展與效能偵錯
    DOTS 支援【SubScene 編輯】、【實體屬性檢視】與【System 運作追蹤】,可與 Unity Profiler 深度整合進行分析。開發者能快速定位效能瓶頸,針對【單一組件】或【系統】進行微調,也能彈性設計可重用的 ECS 模組,利於大型專案擴展。

 

適用場景

  1. 大規模實體模擬
    適用於需要同時管理數千甚至數萬個物件的場景,例如【即時戰略遊戲中的士兵單位】、【開放世界遊戲中的動態生態系統】或【城市建造模擬遊戲中的市民與交通行為】。
  2. 高頻率邏輯運算系統
    在遊戲中需要持續進行大量【數學】或【物理】計算的場景,如【物理模擬】、【粒子系統】、【路徑規劃】或【AI 行為演算】等。
  3. 資源受限的平台開發
    特別適合開發【行動裝置】或【VR 裝置】等效能有限的平台,透過【Burst Compiler】與【ECS】的記憶體最佳化特性,是針對效能敏感應用的最佳選擇。

 

【Unity 插件推薦】DOTS 效能咒術師,展開資料導向的性能領域,秒殺卡頓咒靈!

 

 

Unity DOTS 核心組成

 

  • ECS(Entity Component System):以資料為中心,使用實體(Entities)、元件(Components)和系統(Systems)來組織和管理數據,旨在提升記憶體存取效率。
  • Jobs System:透過多執行緒並行化任務,能將大量的運算工作分配給多個處理器核心,進而提升效能。
  • Burst Compiler:透過靜態分析程式碼並優化產生的機器碼,可大幅提升 CPU 運算效能。

 

 

Unity DOTS 解決傳統問題的痛點

 

1.優化內存佈局:

DOTS 中的 ECS 透過將資料按組件組織,並優化內存佈局,能夠讓數據按照連續區塊儲存在內存中,從而大幅提高 CPU 緩存命中率,減少緩存未命中的問題。

這種資料佈局優化使得大量實體的處理能更有效率,尤其涉及大規模遊戲世界或複雜場景時。

 

2.減少垃圾回收及內存管理開銷:

DOTS 避免了傳統物件實例化和銷毀的開銷,透過使用物件池(或「內存分配池」)來重複使用實體,減少 GC(垃圾回收)的頻繁調用,從而降低效能損耗。

 

3.提高並行運算能力:

DOTS 通過 Jobs System 將任務分割並並行化,能夠充分利用多核心 CPU 的運算能力。開發者可以輕鬆編寫多執行緒代碼,而無需擔心執行緒安全性問題,系統會自動管理並行化。

Burst Compiler 進一步優化了程式碼的執行效率,確保多執行緒任務能夠最大化地提高效能。

 

4、高效率的系統和組件設計:

DOTS 的 ECS 模式簡化了邏輯和資料的分離,讓每個系統(System)只處理資料(Components)中的某一部分。

透過這種設計,開發者可以更方便地對資料進行分區、篩選和批次處理,提高程式的執行效率。

這種「數據驅動」模型使得開發者可以更直觀地分析和優化效能瓶頸。

 

5、易於擴展和優化:

DOTS 提供了一個高效的調試和分析工具鏈(如 Profiler),可幫助開發者即時監控和調整效能瓶頸。

同時,ECS 和 Jobs 使得開發者能夠在程式碼層級進行細粒度的優化。

 

 

Unity DOTS 安裝

 

我這裡使用的是最新的 Unity6,Unity6 Entities 已經從預覽版放出來了(貌似 2022 版本就不是預覽版了),直接搜尋安裝即可。

如果你用的是其他,可能方法各有不同,需要自行去查找如何進行安裝
(注意:推薦在 URP 或者 hdrp 中使用 DOTS

我這裡使用的是最新的 Unity6,Unity6 Entities 已經從預覽版放出來了(貌似 2022 版本就不是預覽版了),直接搜尋安裝即可。  如果你用的是其他,可能方法各有不同,需要自行去查找如何進行安裝 (注意:推薦在 URP 或者 hdrp 中使用 DOTS)

 

安裝 Entities Graphics,實體的 DOTS 顯示包。

安裝 Entities Graphics,實體的 DOTS 顯示包。

 

 

Unity DOTS 在編輯器下建置 ECS World

 

之前的流程是在GameObject 掛上一個 Convert To Entity 的元件,就能轉換成 Entity。

不過新的流程修改了,這個元件被移除了,新的流程如下:

在 Hierarchy 視窗下右鍵,選擇 New Subscene > Empty Scene,建立一個新的 SubScene。

之前的流程是在GameObject 掛上一個 Convert To Entity 的元件,就能轉換成 Entity。  不過新的流程修改了,這個元件被移除了,新的流程如下:  在 Hierarchy 視窗下右鍵,選擇 New Subscene > Empty Scene,建立一個新的 SubScene。

 

現在只要在這個 SubScene 裡面的東西,就會自動轉換成實體(Entity)。

現在只要在這個 SubScene 裡面的東西,就會自動轉換成實體(Entity)。

 

 

Unity DOTS 看 Entity 的屬性

 

之前這塊是在 EntityDebugger 裡面的,相信大家已經發現了,在 Entities 1.0 中,已經沒有這個 EntityDebugger 了。

查看Entity 的方法如下:

直接 Play,然後在 Hierarchy 中選擇對應的 Cube(已經轉成實體)。

你可以透過右上角查看實體情況。

之前這塊是在 EntityDebugger 裡面的,相信大家已經發現了,在 Entities 1.0 中,已經沒有這個 EntityDebugger 了。  查看Entity 的方法如下:  直接 Play,然後在 Hierarchy 中選擇對應的 Cube(已經轉成實體)。  你可以透過右上角查看實體情況。

 

裡面你就能看到 Entity 的屬性了。

裡面你就能看到 Entity 的屬性了。

 

可以看到這裡加了很多 Data,除了 LTW 相關的就是渲染相關的,東西還是非常多的。

不過這裡我們都完全不需要管它,只要知道這裡能看各 Data 的資料就 OK 了。

 

 

Unity DOTS 最簡單的 ecs 程序

 

這裡我我帶大家來實現一個簡單的印刷效果。

 

傳統方式

傳統方式應該不用我介紹太多了,相信大家用的已經很多了。

public class test : MonoBehaviour

{

   void Update()

   {

       Debug.Log("傳統方式打印");

   }

}
 

ecs 方式

要使用 Unity DOTS 實作類似傳統方式的 Update() 列印功能,首先需要了解如何在 DOTS 中使用 ECS(Entity Component System)。

DOTS 的核心思想是將資料(組件)與行為(系統)分離,使用不同的方式來處理每個畫面更新的邏輯。

 

1. 建立一個元件(Component)

定義一個結構體,表示一個組件,用於儲存印刷訊息。

using Unity.Collections;

using Unity.Entities;

public struct PrintMessageComponent : IComponentData {

    // 固定長度字符串,用於存儲打印的消息

   public FixedString128Bytes printData;

}
 

2. 建立一個系統(System)

定義一個系統,處理所有包含 PrintMessageComponent 的實體。

using Unity.Entities;

using Unity.Transforms;

using UnityEngine;

partial class PrintMessageSystem : SystemBase {

    // 系統每幀更新時會調用此方法

   protected override void OnUpdate()

   {

       // 查詢所有包含 LocalTransform 和 PrintMessageComponent 的實體       foreach ((RefRW<LocalTransform> localTransform, RefRO<PrintMessageComponent> printMessageComponent)

           in SystemAPI.Query<RefRW<LocalTransform>, RefRO<PrintMessageComponent>>())

       {

           // 打印每個實體中的 printMessageComponent 內容

           Debug.Log(printMessageComponent.ValueRO.printData);

       }

   }

}
 

3. 觸發打印

定義一個 MonoBehaviour 腳本,用於在場景中產生實體。

using Unity.Entities;

using UnityEngine;

public class EntitySpawner : MonoBehaviour

{

    //用於在 Inspector 面板中輸入的字符串值

   public string value;

    

    // 內部類 Baker,用於將 MonoBehaviour 轉換為實體

   private class Baker : Baker<EntitySpawner>{

       // Bake 方法會在編輯器模式下調用,將 MonoBehaviour 組件數據轉為實體組件數據

       public override void Bake(EntitySpawner authoring){

           // 創建一個動態使用的實體

           Entity entity = GetEntity(TransformUsageFlags.Dynamic);

           // 給實體添加 PrintMessageComponent 組件,並設置其 printData 為 authoring 中的值

           AddComponent(entity, new PrintMessageComponent{

               printData = authoring.value,

           });

       }

   }

}
 

4. 新建空物件掛載腳本

4. 新建空物件掛載腳本

 

效果。

效果。

 

 

Unity DOTS 旋轉組件

 

定義一個旋轉速度組件,用於儲存每個實體的旋轉速度。

using Unity.Entities;

// 定義一個實現 IComponentData 接口的結構體,用於表示旋轉速度

public struct RotateSpeed : IComponentData {

   // 旋轉速度的數值

   public float value;

}
 

定義一個旋轉速度的 Authoring 類,用於在 Unity 編輯器中設定旋轉速度的值。

public class RotateSpeedAuthoring : MonoBehaviour {

   // 用於設置旋轉速度的公共字段

   public float value;

   // Baker 類用於將 MonoBehaviour 組件轉換為 ECS 的組件數據

   private class Baker : Baker<RotateSpeedAuthoring>{

       // 該方法在實體生成時被調用,負責將 MonoBehaviour 上的屬性數據化為 ECS 組件

       public override void Bake(RotateSpeedAuthoring authoring){

           // 獲取當前的實體,並設置為動態使用(TransformUsageFlags.Dynamic)

           Entity entity = GetEntity(TransformUsageFlags.Dynamic);

           // 為實體添加 RotateSpeed 組件,並將作者的旋轉速度值傳遞給它

           AddComponent(entity, new RotateSpeed{

               value = authoring.value, // 設置旋轉速度

           });

       }

   }

}
 

定義一個旋轉立方體系統,負責處理與旋轉速度相關的邏輯。

public partial struct RotatingCubeSystem : ISystem

{

   // 系統創建時調用的方法

   public void OnCreate(ref SystemState state){

       // 在系統創建時要求必須有 RotateSpeed 組件才能進行更新

       state.RequireForUpdate<PrintMessageComponent>();

   }

   // 系統更新時調用的方法

   void OnUpdate(ref SystemState state)

   {

       // 查詢所有包含 LocalTransform 和 RotateSpeed 組件的實體

       foreach ((RefRW<LocalTransform> localTransform, RefRO<RotateSpeed> rotateSpeed)

           in SystemAPI.Query<RefRW<LocalTransform>, RefRO<RotateSpeed>>())

       {

           // 通過當前的旋轉速度(rotateSpeed)來更新實體的旋轉

           // 使用 RotateY 方法按照 Y 軸旋轉,旋轉角度由旋轉速度與 DeltaTime 計算得出

           localTransform.ValueRW =localTransform.ValueRO.RotateY(rotateSpeed.ValueRO.value * SystemAPI.Time.DeltaTime);

       }

   }

}
 

掛載腳本。

掛載腳本。

 

效果。

效果。

 

 

Unity DOTS 最佳化

 

新增 OnCreate,當系統第一次被建立時,OnCreate 方法會被呼叫。

在此方法中,呼叫 state.RequireForUpdate<RotateSpeed>() 來確保系統只會在實體中包含 RotateSpeed 元件時進行更新。

這保證了只有需要旋轉的實體會觸發系統的更新。

using Unity.Transforms;

using Unity.Entities;

// 定義一個旋轉立方體系統,負責處理與旋轉速度相關的邏輯

public partial struct RotatingCubeSystem : ISystem

{

   // 系統創建時調用的方法

   public void OnCreate(ref SystemState state){

       // 在系統創建時要求必須有 RotateSpeed 組件才能進行更新

       state.RequireForUpdate<RotateSpeed>();

   }

   // 系統更新時調用的方法

   void OnUpdate(ref SystemState state)

   {

       // 查詢所有包含 LocalTransform 和 RotateSpeed 組件的實體

       foreach ((RefRW<LocalTransform> localTransform, RefRO<RotateSpeed> rotateSpeed)

           in SystemAPI.Query<RefRW<LocalTransform>, RefRO<RotateSpeed>>())

       {

           // 通過當前的旋轉速度(rotateSpeed)來更新實體的旋轉

           // 使用 RotateY 方法按照 Y 軸旋轉,旋轉角度由旋轉速度與 DeltaTime 計算得出

           localTransform.ValueRW = localTransform.ValueRO.RotateY(rotateSpeed.ValueRO.value * SystemAPI.Time.DeltaTime);

       }

   }

}

 

 

Unity DOTS 多執行緒並行執行

 

系統仍在主執行緒執行。

系統仍在主執行緒執行。

 

修改代碼,使用 rotatingCubeJob.ScheduleParallel(); 系統在多執行緒並行執行。

public partial struct RotatingCubeSystem : ISystem

{

   // 系統創建時調用的方法

   public void OnCreate(ref SystemState state)

   {

       // 在系統創建時要求必須有 RotateSpeed 組件才能進行更新

       state.RequireForUpdate<RotateSpeed>();

   }

   // 系統更新時調用的方法

   void OnUpdate(ref SystemState state)

   {

       // 創建旋轉立方體的工作作業,並傳遞時間增量信息

       RotatingCubeJob rotatingCubeJob = new RotatingCubeJob

       {

           deltaTime = SystemAPI.Time.DeltaTime // 獲取每幀的時間增量

       };

       // 調度工作作業

       // rotatingCubeJob.Schedule();

       // state.Dependency = rotatingCubeJob.Schedule(state.Dependency);

       //在多個線程上並行

       rotatingCubeJob.ScheduleParallel();

   }

   // 定義旋轉立方體的作業,IJobEntity 用於操作實體

   {

       public float deltaTime; // 存儲時間增量,用於旋轉計算

       // 執行作業時的具體操作:旋轉實體

       public void Execute(ref LocalTransform localTransform, in RotateSpeed rotateSpeed)

       {

           // 旋轉的倍率系數

           float power = 1f;

           // 根據旋轉速度和時間增量來旋轉實體

           localTransform = localTransform.RotateY(rotateSpeed.value * deltaTime * power);

       }

   }

}
 

區別總結

 

 

Unity DOTS 使用 Burst 編譯器優化效能

 

加入關鍵字 [BurstCompile] 即可,使用 Burst 編譯器優化效能。

加入關鍵字 [BurstCompile] 即可,使用 Burst 編譯器優化效能。

 

記得查看 Burst 編譯器是否勾選使用。

記得查看 Burst 編譯器是否勾選使用。

 

 

Unity DOTS 屏蔽系統間的干擾

 

前面我們實現了一個打印和旋轉系統,雖然我們的打印功能已經被隱藏了。

前面我們實現了一個打印和旋轉系統,雖然我們的打印功能已經被隱藏了。

 

但是如果通過在打印系統 OnUpdate 裡打印日誌。

但是如果通過在打印系統 OnUpdate 裡打印日誌。

 

你會發現系統其實仍然在執行。

你會發現系統其實仍然在執行。   你會發現系統其實仍然在執行。

 

我們可以加上 [DisableAutoCreation] 特性,屏蔽該系統的干擾,這樣這個系統就不會再運行了。

我們可以加上 [DisableAutoCreation] 特性,屏蔽該系統的干擾,這樣這個系統就不會再運行了。

 

 

Unity DOTS 偵錯視窗

 

Unity DOTS 偵錯視窗

 

  • Hierarchy : 顯示目前場景中的實體訊息
  • Components :顯示所有 ComponentData 的結構體資訊。
  • Systems:顯示目前執行的所有System 訊息,能看到其使用了哪些實體。
  • Archetypes:顯示原型資訊。
  • Journaling:日誌記錄,可以顯示用了哪些方法,有哪些實體、ComponentData 之類,應該是可以用來分析效能,但我還沒有仔細研究。

 

 

Unity DOTS 後續

 

DOTS 基礎篇就先寫到這裡了,如果你有興趣也可以用傳統方式進行效能比較,這裡我就不寫了。

後續我看有時間再考慮寫一些進階知識或是 DOTS 項目實戰內容,可以敬請期待一下。
 

 

Unity DOTS 相關介紹 & 教學影片

 

Connecting the DOTS: Let’s make a game with Entities | Unite 2024

 

Learn Unity DOTS! (FREE Tutorial Course)

 

UNITY DOTS (ECS) - Beginners Guide

 

 

Unity DOTS 效能咒術師相關網站 & 插件下載點

 

【DOTS】

官方文檔:DOTS

GitHub 下載連結:DOTS

————————————————

以上內容改編節錄自:CSDN 作者:向宇it

 

更多好用插件:【Unity 好用插件推薦】持續更新,一起讓遊戲開發事半功倍!

 

 

 

本文原創(或整理)於亞洲電玩通,未經作者與本站同意不得隨意引用、轉載、改編或截錄。

特約作家簡介

X
A
Y
B
JamXu的頭像
JamXu
十年遊戲研發
二十年遊戲台主
三十年遊戲玩家

經中華網龍遊戲企劃進入遊戲圈,然後被雷打到去學程式前後端又學了點設計帶帶幾個研發團隊,見證了 3D 渲染技術及遊戲引擎互相進步,也見證了研發代理的更迭與博弈遊戲的興起,再毅然研究起 SEO 網路行銷社群廣告投放,深信自研自賣才是最大贏家,期望能為台灣研發重回輝煌時光貢獻一點力量。如果你也有遊戲夢,歡迎交流認識。


支持贊助 / DONATE

 

亞洲電玩通只是很小的力量,但仍希望為復甦台灣遊戲研發貢獻一點動能,如果您喜歡亞洲電玩通的文章,或是覺得它們對您有幫助,歡迎給予一些支持鼓勵,不論是按讚追蹤或是贊助,讓亞洲電玩通持續產出,感謝。

亞洲電玩通AsiaGameMaster - Steam 遊戲鑑賞家
亞洲電玩通AsiaGameMaster - FB 粉絲專頁
亞洲電玩通AsiaGameMaster - IG 粉絲專頁
亞洲電玩通AsiaGameMaster - Twitter
亞洲電玩通AsiaGameMaster - Yoytube 粉絲專頁
亞洲電玩通AsiaGameMaster - Tiktok

BTC

亞洲電玩通AsiaGameMaster - BTC 鏈贊助地址

352Bw8r46rfXv6jno8qt9Bc3xx6ptTcPze

 

ETH

亞洲電玩通AsiaGameMaster - ETH 鏈贊助地址

0x795442E321a953363a442C76d39f3fbf9b6bC666

 

TRON

亞洲電玩通AsiaGameMaster - TRON 鏈贊助地址

TCNcVmin18LbnXfdWZsY5pzcFvYe1MoD6f

延伸閱讀