Unity ECS DOTS技術實現50000個cube隨機循環移動流程

前言

? ? ? ? 之前使用過ECS面向組件開發,一直想試一下Unity的ECS DOTS技術,但是苦于入門門檻太高,下載官方的Demo,發現代碼哪哪兒都看不懂,一大堆API聞所未聞,而且沒有一個入門的流程,導致無法進行下去。也嘗試過幾次讓AI引導,創建一個小的Demo,但是由于Entities和Graphics各個版本API差距很大,單純使用AI,也難以實現。今天突然奇想,結合官方Demo和AI,再次嘗試了,成功的實現了一個小Demo。

? ? ? ? 本文不做原理講解,因為還沒琢磨透每行代碼,只是做一個流程示范,可以讓每個入門的讀者按照流程體驗一下萬人同屏的情況下,FPS穩定在60+的“爽感”,Demo實現之后,再仔細閱讀代碼,慢慢拓展功能。

? ? ? ? 本文以下內容,均是個人理解+AI解釋,并不能保證完全正確,如有問題,歡迎指出

版本

? ? ? ? Unity版本6000.0.40(可改,但是一定要是6000,官方Demo用的例子是6000.0.23),Entities版本1.3.5(不要改,避免API失效,如果Unity版本太低導致不支持,建議升級Unity版本),Entities Graphics版本1.4.2(不要改,原因同上)。URP版本17.0.4(這個理論上無所謂)。

步驟

1.創建工程

????????選擇URP項目(必須,只支持URP,如果會在項目中切換渲染管線則隨意)

2.PackageManager導入插件

? ? ? ? 分別導入以上插件Entities1.3.5,Entities Graphics1.4.2,PackageManager里面版本太高的話,在Version History里面切換

3.新建cube生成器

using Unity.Entities;
using UnityEngine;public class RandomMoveAuthoring : MonoBehaviour
{public GameObject prefab;public int count = 50000;public float radius = 100f;class Baker : Baker<RandomMoveAuthoring>{public override void Bake(RandomMoveAuthoring authoring){var entity = GetEntity(TransformUsageFlags.None);AddComponent(entity, new RandomMoveSpawner{Prefab = GetEntity(authoring.prefab, TransformUsageFlags.Renderable),Count = authoring.count,Radius = authoring.radius});}}
}public struct RandomMoveSpawner : IComponentData
{public Entity Prefab;public int Count;public float Radius;
}

? ? ? ? 這個腳本的作用主要是把Mono的GameObject(prefab)對象,烘焙成ECS系統里面的Entity實例,把Mono腳本上面的值(count,radius)烘焙到ECS里的IComponentData上。這個Bake函數是在編輯器模式下執行的,不是在運行時執行的。

4.新建cube移動組件數據

using Unity.Entities;
using Unity.Mathematics;public struct RandomMoveComponent : IComponentData
{public float3 StartPosition;public float3 Direction;public float Speed;public float Radius;
}

? ? ? ? 記錄cube的各個屬性,起始位置,方向,速度,移動半徑

5.新建cube生成系統

using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;[BurstCompile]
[UpdateInGroup(typeof(InitializationSystemGroup))]
public partial struct RandomMoveSpawnerSystem : ISystem
{public void OnCreate(ref SystemState state){}public void OnUpdate(ref SystemState state){var ecb = new EntityCommandBuffer(Allocator.Temp);foreach (var (spawner, entity) in SystemAPI.Query<RefRO<RandomMoveSpawner>>().WithEntityAccess()){var random = new Unity.Mathematics.Random((uint)UnityEngine.Random.Range(1, int.MaxValue));// 創建 NativeArray 存儲實例var instances = new NativeArray<Entity>(spawner.ValueRO.Count, Allocator.Temp);// 實例化 prefab ,這里先用 EntityManager,因為 ECB 不能實例化實體,之后可以改成別的方案state.EntityManager.Instantiate(spawner.ValueRO.Prefab, instances);for (int i = 0; i < instances.Length; i++){float3 start = new float3(random.NextFloat(-spawner.ValueRO.Radius, spawner.ValueRO.Radius),0,random.NextFloat(-spawner.ValueRO.Radius, spawner.ValueRO.Radius));float3 dir = math.normalize(random.NextFloat3Direction());dir.y = 0;// 通過ECB設置組件數據(延遲生效)ecb.SetComponent(instances[i], LocalTransform.FromPosition(start));ecb.AddComponent(instances[i], new RandomMoveComponent{StartPosition = start,Direction = dir,Speed = UnityEngine.Random.Range(1f, 3f),Radius = 10f});}instances.Dispose();// 延遲刪除 spawner 實體ecb.DestroyEntity(entity);}ecb.Playback(state.EntityManager);ecb.Dispose();}
}

? ? ? ? 根據RandomMoveSpawner的Count數量,生成對應的實例。可以看到,很多新的API,還沒理清,就不解釋誤導人了。

6.新建cube移動系統

原版代碼

using Unity.Burst;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;[BurstCompile]
public partial struct RandomMoveSystem : ISystem
{public void OnUpdate(ref SystemState state){float time = (float)SystemAPI.Time.ElapsedTime;foreach (var (move, transform) in SystemAPI.Query<RefRO<RandomMoveComponent>, RefRW<LocalTransform>>()){float3 pos = move.ValueRO.StartPosition +move.ValueRO.Direction *math.sin(time * move.ValueRO.Speed) *move.ValueRO.Radius;transform.ValueRW.Position = pos;}}
}

? ? ? ? 這個代碼運行之后,fps只有30,明顯不正常,讓AI又重新生成了一版

新版代碼

using Unity.Burst;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;[BurstCompile]
public partial struct RandomMoveSystem : ISystem
{[BurstCompile]public partial struct RandomMoveJob : IJobEntity{public float time;public void Execute(in RandomMoveComponent move, ref LocalTransform transform){float3 pos = move.StartPosition +move.Direction *math.sin(time * move.Speed) *move.Radius;transform.Position = pos;}}public void OnUpdate(ref SystemState state){var job = new RandomMoveJob{time = (float)SystemAPI.Time.ElapsedTime};job.ScheduleParallel(); // 并行調度}
}

????????使用 IJobEntity + Burst 多線程并行,FPS達到了90左右,完美!

7.代碼結束,接下來是編輯器的操作

8.新建cube預制體

? ? ? ? 新建一個cube,拖成預制體。新建一個材質,shader選擇URP默認的Lit即可。勾選材質上的Enable GPU Instancing(這個之前沒勾選的時候,渲染不出來,但是后面又測試的時候,發現不勾選也可以正常渲染,而且可以正常合批,沒搞清楚什么情況)

9.烘焙!!!重要

? ? ? ? 場景內新建對象,命名Spawner(隨意命名)

????????Spawner掛載腳本RandomMoveAuthoring

????????把剛才新建的cube預制體拖到RandomMoveAuthoring的Prefab欄

? ? ? ? 選中Spawner,右鍵,點擊New Sub Scene->From Selection,選擇路徑保存場景,此時會自動觸發RandomMoveAuthoring腳本內的Bake函數,烘焙Mono的數據到ECS系統內,不進行烘焙,ECS是無法獲取到Mono內定義的數據的

10.運行

? ? ? ? 查看效果

問題記錄

1.運行時看不到物體

a.檢查渲染管線是否使用的是URP

b.烘焙是否正常,可以在Bake函數加日志,在點擊子場景Inspector視圖的Open按鈕時,會觸發Bake函數

c.確定編譯過程中,沒有報錯,有些報錯,不影響程序啟動,但是會影響程序邏輯

2.FPS比預期的低

查看下Profiler,耗時主要在哪里,如果是EditorLoop,則關閉Scene視圖

3.Scene視圖不顯示物體

關閉Sub Scene,取消圖中的 復選框

4.Hierarchy視圖,勿刪了Sub Scene怎么辦

在Hierarchy視圖,新建空對象,添加腳本Sub Scene,把之前創建的場景,拖到Sub Scene腳本的Scene Asset欄即可,重置下對象的Transform數據清除警告

總結

? ? ? ? ECS DOTS的入門還是太難了,充斥著大量的新的API,寫邏輯還要脫離Mono,跟之前的開發習慣差距巨大,需要慢慢深入,本文內容可能有錯的地方,后續如果有理解,再做更新

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/87303.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/87303.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/87303.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

設計模式精講 Day 3:抽象工廠模式(Abstract Factory Pattern)

【設計模式精講 Day 3】抽象工廠模式&#xff08;Abstract Factory Pattern&#xff09; 文章簡述 在軟件開發中&#xff0c;隨著業務復雜度的提升&#xff0c;系統需要支持多種產品族的創建。抽象工廠模式正是為了解決這一問題而誕生的設計模式之一。本文作為“設計模式精講”…

Kafka消息零丟失架構設計:從原理到實戰的全方位保障

引言 在構建高可靠分布式系統時&#xff0c;Kafka作為核心消息中間件被廣泛應用于數據管道、實時流處理等關鍵場景。然而&#xff0c;分布式環境下的網絡波動、節點故障等因素可能導致消息丟失&#xff0c;如何確保Kafka實現端到端的消息零丟失成為架構設計的關鍵挑戰。本文將…

Python學習筆記:錯誤和異常處理

1. 什么是錯誤和異常 在Python中&#xff0c;錯誤可以分為兩類&#xff1a; 語法錯誤(Syntax Errors)&#xff1a;代碼不符合Python語法規則異常(Exceptions)&#xff1a;語法正確的代碼在運行時發生的錯誤 # 語法錯誤示例 print("Hello World" # 缺少右括號# 異…

為什么要進行行為驗證,行為驗證方式有哪些?

進行行為驗證的主要目的是提高賬戶安全性、防范自動化攻擊、增強用戶身份確認精準度、優化用戶體驗。其中&#xff0c;提高賬戶安全性最為關鍵。行為驗證能通過分析用戶的行為模式&#xff0c;如操作習慣、設備使用特點等&#xff0c;識別出非正常或惡意活動&#xff0c;迅速采…

主流Java Redis客戶端(Jedis、Lettuce、Redisson)差異對比

主流Java客戶端對比&#xff1a;Jedis采用阻塞I/O&#xff0c;需連接池支持&#xff1b;Lettuce/Redisson基于Netty非阻塞I/O。Jedis輕量但并發能力弱&#xff0c;Lettuce支持10K并發且為SpringBoot默認&#xff0c;Redisson提供分布式功能但性能稍遜。 Redisson Lettuce 在 …

使用Hexo搭建博客網站(二)

設置主題 我們在官方主題中選擇一個自己喜歡的主題 來到GitHub&#xff0c;將它git clone到當前項目的themes文件夾中 設置_config.yml 找到 # Extensions ## Plugins: https://hexo.io/plugins/ ## Themes: https://hexo.io/themes/ theme: landscape 只需將這個landscape名字…

springAI 大模型應用開發

一 筆記總結 1.1 spring AI 實戰 1.1.1 spring aideepseek整合 通過使用spring ai 調用大模型deepseek&#xff0c;實現對話聊天&#xff0c;文字轉圖片&#xff0c;文字轉音頻。 1.1.2 OLLAMA Ollama 專為本地部署和運行大型語言模型&#xff08;LLM&#xff09;而設計的…

Java + Spring Boot 后端防抖應用實例

防抖工具&#xff08;適用單機部署&#xff09; DebounceUtil.java package com.weiyu.utils;import jakarta.annotation.PostConstruct; import jakarta.annotation.PreDestroy; import org.springframework.stereotype.Component;import java.util.Map; import java.util.c…

PostgreSQL 快速入門

PostgreSQL介紹 PostgreSQL 是一個功能強大的開源關系型數據庫系統&#xff0c;它使用并擴展了 SQL 語言&#xff0c;并結合了許多功能&#xff0c;可以安全地存儲和擴展復雜的數據工作 PostgreSQL 因其經過驗證的架構、可靠性、數據完整性、強大的功能集、可擴展性以及軟件背…

CppCon 2016 學習:Out of memory? Business as usual.

當程序因為內存耗盡而拋出 std::bad_alloc 異常時&#xff0c;這并不意味著程序必須崩潰或停止運行。我們應該考慮“內存不足”作為一種可能正常出現的情況&#xff08;“Out of memory? Business as usual.”&#xff09;&#xff0c;并設計應用程序能優雅地處理這種異常。 具…

廟算兵棋推演AI開發初探(8-神經網絡模型接智能體進行游戲)

前言の碎碎念 由于我做的模仿學習&#xff0c;可能由于沒有完全模仿&#xff0c;可以說效果很爛……后來用強化學習優化&#xff0c;這個倒是不用自己做數據集了&#xff0c;為方便大家只搞代碼&#xff0c;這里只說這部分的經歷和方法。 實踐基礎介紹 1-動作 先介紹一個強化…

Uart_Prj02 Windows 窗口版串口_Step1

完成上位機控制臺串口后&#xff0c;接下來想用C#做一個Windows 窗口版的串口。上位機編程不是很熟練&#xff0c;每天學一點做一點。 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.…

自動駕駛系統研發—從工程視角看純視覺自動駕駛的安全挑戰與應對策略

???? 歡迎來到我的技術小筑,一個專為技術探索者打造的交流空間。在這里,我們不僅分享代碼的智慧,還探討技術的深度與廣度。無論您是資深開發者還是技術新手,這里都有一片屬于您的天空。讓我們在知識的海洋中一起航行,共同成長,探索技術的無限可能。 ?? 探索專欄:學…

PostgreSQL認證怎么選?PGCP中級認證、PGCM高級認證

上圖是2025年6月份最新的db-engines上的數據庫排名情況&#xff0c;可以看出PostgreSQL數據庫仍然呈上升趨勢&#xff0c;跟排名第三的"Microsoft SQL Server"起來越接近&#xff0c;國內亦是如此&#xff0c;PostgreSQL的熱潮依在&#xff0c;可見學習PostgreSQL數據…

Hive 3.x數據靜態脫敏與加密

引言 在大數據時代&#xff0c;數據已成為企業和組織的核心資產。作為數據處理的重要平臺&#xff0c;Hive 3.x存儲著大量敏感信息&#xff0c;如用戶個人身份、財務數據、商業機密等。如何確保這些數據在存儲和處理過程中的安全性&#xff0c;成為數據從業者關注的焦點。數據…

CppCon 2016 學習:Lightweight Object Persistence With Modern C++

你給出的這段文字是某個演講、論文或者技術文檔的概要&#xff08;Overview&#xff09;部分&#xff0c;內容主要是關于內存分配器&#xff08;allocator&#xff09;設計以及**對象持久化&#xff08;object persistence&#xff09;**的一些思路。讓我幫你逐條解析和理解&am…

IPv6中的ARP“NDP協議詳解“

一、概述 在IPv4網絡環境當中,我們想要與對端進行網絡通信時,首先需要去解析對方的MAC地址這樣我們才能封裝二層數據幀,就算訪問不同網絡時也需要解析網關的MAC,這些都是需要我們的ARP協議來進行操作完成的,但是在我們的IPv6網絡環境當中并沒有ARP協議,而是通過NDP協議來完成類…

TortoiseSVN遷移到本地git

將項目從Subversion&#xff08;SVN&#xff09;遷移到Git是許多開發團隊的需求&#xff0c;因為Git提供了更多的功能和靈活性。本文將詳細介紹如何使用TortoiseSVN將項目遷移到本地Git倉庫。 一、準備工作 安裝Git&#xff1a;確保在本地機器上安裝了Git。可以通過以下命令檢…

高性能 Web 服務器之Tengine

一、概述 Tengine 是一個由淘寶網發起的 Web 服務器項目。它基于 Nginx 然后針對大訪問量網站的需求&#xff0c;添加了很多高級功能和特性&#xff0c;從 2011 年 12 月開始&#xff0c;Tengine 正式開源。Tengine 的性能和穩定性已經100多家大型網站如淘寶網&#xff0c;天貓…

簡單實現HTML在線編輯器

我們繼續來看一下如何開發一個簡單的html在線編輯器&#xff0c;要求很簡單 能夠同時編輯html&#xff0c;css&#xff0c;js代碼&#xff0c;并且運行之后可以同時預覽效果 一&#xff1a;前置知識 在H5中設置了一個新的標簽&#xff0c;<iframe>&#xff0c; 用于在當前…