UnityDots学习(四)

官方案例HelloCube和Tank学习研究:

HelloCube:

通用部分:

使用Authoring根据Inspector的勾选添加为Entity添加不同Component。然后每个System会根据实体添加的Component运行不同的System逻辑。

1. MainThread

简单构造System

先看System接口定义:

cs 复制代码
[RequireImplementors]
    public interface ISystem
    {
        /// <summary>
        /// Called when this system is created.
        /// </summary>
        /// <remarks>
        /// Implement an `OnCreate` function to set up system resources when it is created.
        ///
        /// `OnCreate` is invoked before the the first time <see cref="ISystemStartStop.OnStartRunning(ref SystemState)"/>
        /// and <see cref="OnUpdate"/> are invoked.
        /// </remarks>
        /// <param name="state">The <see cref="SystemState"/> backing this system instance</param>
        [RequiredMember]
        void OnCreate(ref SystemState state) { }

        /// <summary>
        /// Called when this system is destroyed.
        /// </summary>
        /// <remarks>
        /// Systems are destroyed when the application shuts down, the World is destroyed, or you
        /// call <see cref="World.DestroySystem"/>. In the Unity Editor, system destruction occurs when you exit
        /// Play Mode and when scripts are reloaded.
        /// </remarks>
        /// <param name="state">The <see cref="SystemState"/> backing this system instance</param>
        [RequiredMember]
        void OnDestroy(ref SystemState state) { }

        /// <summary>
        /// Implement `OnUpdate` to perform the major work of this system.
        /// </summary>
        /// <remarks>
        /// <p>
        /// By default, the system invokes `OnUpdate` once every frame on the main thread.
        /// To skip OnUpdate if all of the system's [EntityQueries] are empty, use the
        /// [RequireMatchingQueriesForUpdateAttribute]. To limit when OnUpdate is invoked, you can
        /// specify components that must exist, or queries that match specific Entities. To do
        /// this, call <see cref="SystemState.RequireForUpdate{T}"/> or
        /// <see cref="SystemState.RequireForUpdate(EntityQuery)"/>
        /// in the system's OnCreate method. For more information, see <see cref="SystemState.ShouldRunSystem"/>.
        /// </p>
        /// <p>
        /// You can instantiate and schedule an <see cref="IJobChunk"/> instance; you can use the
        /// [C# Job System] or you can perform work on the main thread. If you call <see cref="EntityManager"/> methods
        /// that perform structural changes on the main thread, be sure to arrange the system order to minimize the
        /// performance impact of the resulting [sync points].
        /// </p>
        ///
        /// [sync points]: xref:concepts-structural-changes
        /// [C# Job System]: https://docs.unity3d.com/Manual/JobSystem.html
        /// [EntityQueries]: xref:Unity.Entities.EntityQuery
        /// [RequireMatchingQueriesForUpdateAttribute]: xref:Unity.Entities.RequireMatchingQueriesForUpdateAttribute
        /// </remarks>
        /// <param name="state">The <see cref="SystemState"/> backing this system instance</param>
        [RequiredMember]
        void OnUpdate(ref SystemState state) { }
    }

有3处接口

OnCreate里可以添加是否让System在OnUpdate里运行

类似:

当至少有一个Entity包含ExecuteIJobEntity组件。会激活Update

OnDestory就是在System被销毁时运行

OnUpdate里实现了简单的旋转。

这里Query是查询当前符合要求Component的实体。

RW是即可读又可写,RO是只可读,在system里不可改变其属性

2. IJobEntity

该案例是把System里执行的逻辑换成Job,这样程序的运行可以利用多核在不用非在主线程里运行。这样会提升CPU的使用率

这个Job实现的Schedule可以实现在代码里顺序执行。

比如增加下列代码测试,就可以发现物体上下移动了

3. Aspects

上述的读取数据还得根据情况写RW,RO。

Unity提供了一个接口如图:

不需要去传入值,且函数名可以自定义

在使用时直接查询就可以正确去找到对应拥有Component组件的实体进行遍历。这个比较方便

需要注意是必须用

复制代码
readonly partial进行修饰。

可以看到Unity自己扩展定义后的内容

4. Prefabs

cs 复制代码
public partial struct SpawnSystem : ISystem
    {
        uint updateCounter;

        [BurstCompile]
        public void OnCreate(ref SystemState state)
        {
            // This call makes the system not update unless at least one entity in the world exists that has the Spawner component.
            state.RequireForUpdate<Spawner>();

            state.RequireForUpdate<ExecutePrefabs>();
        }

        [BurstCompile]
        public void OnUpdate(ref SystemState state)
        {
            // Create a query that matches all entities having a RotationSpeed component.
            // (The query is cached in source generation, so this does not incur a cost of recreating it every update.)
            var spinningCubesQuery = SystemAPI.QueryBuilder().WithAll<RotationSpeed>().Build();

            // Only spawn cubes when no cubes currently exist.
            if (spinningCubesQuery.IsEmpty)
            {
                var prefab = SystemAPI.GetSingleton<Spawner>().Prefab;

                // Instantiating an entity creates copy entities with the same component types and values.
                var instances = state.EntityManager.Instantiate(prefab, 500, Allocator.Temp);

                // Unlike new Random(), CreateFromIndex() hashes the random seed
                // so that similar seeds don't produce similar results.
                var random = Random.CreateFromIndex(updateCounter++);

                foreach (var entity in instances)
                {
                    // Update the entity's LocalTransform component with the new position.
                    var transform = SystemAPI.GetComponentRW<LocalTransform>(entity);
                    transform.ValueRW.Position = (random.NextFloat3() - new float3(0.5f, 0, 0.5f)) * 20;
                }
            }
        }
    }
复制代码
拿到对象实例,这里是Dots需要用结构体,所以跟Unity之前的GameObject生成有所区别
var prefab = SystemAPI.GetSingleton<Spawner>().Prefab;

这里是生成实例的DOTS版本

复制代码
var instances = state.EntityManager.Instantiate(prefab, 500, Allocator.Temp);
cs 复制代码
public partial struct FallAndDestroySystem : ISystem
    {
        [BurstCompile]
        public void OnCreate(ref SystemState state)
        {
            state.RequireForUpdate<ExecutePrefabs>();
        }

        [BurstCompile]
        public void OnUpdate(ref SystemState state)
        {
            // rotation
            float deltaTime = SystemAPI.Time.DeltaTime;
            foreach (var (transform, speed) in
                     SystemAPI.Query<RefRW<LocalTransform>, RefRO<RotationSpeed>>())
            {
                // ValueRW and ValueRO both return a ref to the actual component value.
                // The difference is that ValueRW does a safety check for read-write access while
                // ValueRO does a safety check for read-only access.
                transform.ValueRW = transform.ValueRO.RotateY(
                    speed.ValueRO.RadiansPerSecond * deltaTime);
            }

            // An EntityCommandBuffer created from EntityCommandBufferSystem.Singleton will be
            // played back and disposed by the EntityCommandBufferSystem when it next updates.
            var ecbSingleton = SystemAPI.GetSingleton<BeginSimulationEntityCommandBufferSystem.Singleton>();
            var ecb = ecbSingleton.CreateCommandBuffer(state.WorldUnmanaged);

            // Downward vector
            var movement = new float3(0, -SystemAPI.Time.DeltaTime * 5f, 0);

            // WithAll() includes RotationSpeed in the query, but
            // the RotationSpeed component values will not be accessed.
            // WithEntityAccess() includes the Entity ID as the last element of the tuple.
            foreach (var (transform, entity) in
                     SystemAPI.Query<RefRW<LocalTransform>>()
                         .WithAll<RotationSpeed>()
                         .WithEntityAccess())
            {
                transform.ValueRW.Position += movement;
                if (transform.ValueRO.Position.y < 0)
                {
                    // Making a structural change would invalidate the query we are iterating through,
                    // so instead we record a command to destroy the entity later.
                    ecb.DestroyEntity(entity);
                }
            }
        }
    }

Dots版本的删除实体:

复制代码
var ecbSingleton = SystemAPI.GetSingleton<BeginSimulationEntityCommandBufferSystem.Singleton>();
复制代码
var ecb = ecbSingleton.CreateCommandBuffer(state.WorldUnmanaged);
复制代码
ecb.DestroyEntity(entity);
复制代码
BeginSimulationEntityCommandBufferSystem.Singleton:我的理解就是全部关闭实例Manager
复制代码
EntityCommandBuffer:是每个实体管理的控制器,类似GameObjectManager。所有的创建销毁实体都是通过他来控制。
相关推荐
丰锋ff17 分钟前
操作系统学习笔记
笔记·学习
superior tigre1 小时前
C++学习:六个月从基础到就业——C++学习之旅:STL迭代器系统
c++·学习
世事如云有卷舒3 小时前
《C++ Primer》学习笔记(四)
c++·笔记·学习
李匠20243 小时前
C++学习之游戏服务器开发十四QT登录器实现
c++·学习·游戏
viperrrrrrrrrr74 小时前
大数据学习(112)-Analytic函数集
学习
nenchoumi31194 小时前
LLM 论文精读(二)Training Compute-Optimal Large Language Models
论文阅读·人工智能·笔记·学习·语言模型·自然语言处理
小王努力学编程4 小时前
美团2024年春招第一场笔试 C++
开发语言·数据结构·c++·学习·算法
卡皮巴拉爱吃小蛋糕4 小时前
MySQL的事务(Transaction)【学习笔记】
数据库·笔记·学习·mysql
superior tigre4 小时前
C++学习:六个月从基础到就业——STL算法(一) 基础与查找算法
c++·学习·算法