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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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; 用于在当前…