Unity ECS 案例学习笔记

本文围绕Unity ECS展开,介绍了多种开发方法。如ForEach可将GameObject实例转换成Entity实例;FluentQuery能在MonoBehaviour中生成并初始化Entity实例;还提及IJobForEach、IJobChunk的多核处理方式,以及SubScene的场景管理和SpawnFromMonobehaviour生成Entity实例的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


资源地址:https://github.com/Unity-Technologies/EntityComponentSystemSamples

1.ForEach

在Hierarchy中创建GameObject实例,由插件中的ConvertToEntity在运行时把实例转换成Entity实例,RotationSpeedAuthoring_ForEach负责具体转换工作(添加组件数据等…)
在这里插入图片描述

脚本说明

RotationSpeedAuthoring_ForEach:把设置的参数DegreesPerSecond(角度速率)转成ComponentData(弧度速率)并绑定到entity上。
RotationSpeed_ForEach:这是个ComponentData,Entity实例的数据,注意它是结构体(Struct)不是类(Class)
RotationSpeedSystem_ForEach:组件系统,负责把ComponentData应用到Entity上,它在OnUpdate中对所有的Entity进行设置,Entities.ForEach会经常用到。

ReadMe

This sample demonstrates a simple ECS System that rotates a pair of cubes.

## What does it show?

This sample demonstrates the separation of data and functionality in ECS. Data is stored in components, while functionality is written into systems.

The **RotationSpeedSystem_ForEach** *updates* the object's rotation using the *data* stored in the **RotationSpeed_ForEach** Component.

## ComponentSystems and Entities.ForEach

RotationSpeedSystem_ForEach is a ComponentSystem and uses an Entities.ForEach delegate to iterate through the Entities. This example only creates a single Entity, but if you added more Entities to the scene, the RotationSpeedSystem_ForEach updates them all — as long as they have a RotationSpeed_ForEach Component (and the Rotation Component added when converting the GameObject's Transform to ECS Components).

Note that ComponentSystems using Entities.ForEach run on the main thread. To take advantage of multiple cores, you can use a JobComponentSystem (as shown in the next HelloCube example).

## Converting from GameObject to Entity

The **ConvertToEntity** MonoBehaviour converts a GameObject and its children into Entities and ECS Components upon Awake. Currently the set of built-in Unity MonoBehaviours that ConvertToEntity can convert includes the Transform and MeshRenderer. You can use the **Entity Debugger** (menu: **Window** > **Analysis** > **Entity Debugger**) to inspect the ECS Entities and Components created by the conversion.

You can implement the IConvertGameObjectEntity interface on your own MonoBehaviours to supply a conversion function that ConvertToEntity will use to convert the data  stored in the MonoBehaviour to an ECS Component.

In this example, the **RotationSpeedAuthoring_ForEach** MonoBehaviour uses IConvertGameObjectEntity to add the RotationSpeed_ForEach Component to the Entity on conversion.

1b.FluentQuery

在MonoBehaviour中可以生成一堆的Entity实例,并对它们初始化
在这里插入图片描述

脚本说明

HelloSpawnMonoBehaviour:把GameObject预制体转成EntityPrefab,再由World.Active.EntityManager实例化。初始化的时候给实例添加自定义的:ComponentData(MoveUp&MovingCube),它们两个不存数据只做Tag用。
MovementSystem:分两个部分第一部分:在OnUpdate中筛选出带有MoveUp&MovingCube组件的Entity实例,对它们进行位置偏移操作,当到达条件时删除(PostUpdateCommands.RemoveComponent<MoveUp>)掉MoveUp组件取消对它的偏移操作,第二部分:筛选出不带MoveUp的所有带MovingCube组件的Entity实例重置它的位置并重新添加(PostUpdateCommands.AddComponent)MoveUp组件。这两个部分就起到了循环Entity实例位置运动的功能。

ReadMe

This sample demonstrates a simple ECS System that uses fluent queries to select the correct set of entities to update.

The example defines two tag component, named MovingCube and MoveUp. One fluent query in the system selects all entities that have both a MoveUp component and a Translation component. The ForEach lambda function associated with this query moves each selected entity upwards until it reaches a certain height. At that point, the function removes the MoveUp component so the next time the system updates, the entity will not be selected and thus it will not be moved upwards any farther.

A second fluid query selects all entities that have a Translation component, but do not have a MoveUp component. The ForEach function associated with the second query moves the entity down to its starting location and adds a new MoveUp component. Since the entity has a MoveUp component once again, the next time the system updates, the entity is moved upward by the first ForEach function and skipped by the second query.

The MovingCube is another tag component that ensures that the system only works on components marked for this sample.

## What does it show?

This sample demonstrates a simple ECS System that uses fluent queries to select a set of entities to move upwards.  When they reach a certain height, the system removes a component and uses another query to respawn them at a lower height.  It also demonstrates the use of "tag" components to provide a means of selecting specific sets of entites with marker components to be processed.

## Component Systems and Entities.ForEach

MovementSystem is a ComponentSystem and uses an Entities.ForEach delegate to iterate through the Entities. This example uses the WithAll and WithNone constraints to select specific sets of entities to work on.

Note: Component Systems using Entities.ForEach run on the main thread. To take advantage of multiple cores, you can use a JobComponentSystem (as shown in other HelloCube examples).

2.IJobForEach

由于Component System 使用的Entities.ForEach是运行在主线程中的,如果需要多核方式就可以使用JobComponentSystem
只需要修改System部分即可。如下:

using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;

// This system updates all entities in the scene with both a RotationSpeed_IJobForEach and Rotation component.

// ReSharper disable once InconsistentNaming
public class RotationSpeedSystem_IJobForEach : JobComponentSystem
{
    // Use the [BurstCompile] attribute to compile a job with Burst. You may see significant speed ups, so try it!
    [BurstCompile]
    struct RotationSpeedJob : IJobForEach<Rotation, RotationSpeed_IJobForEach>
    {
        public float DeltaTime;

        // The [ReadOnly] attribute tells the job scheduler that this job will not write to rotSpeedIJobForEach
        public void Execute(ref Rotation rotation, [ReadOnly] ref RotationSpeed_IJobForEach rotSpeedIJobForEach)
        {
            // Rotate something about its up vector at the speed given by RotationSpeed_IJobForEach.
            rotation.Value = math.mul(math.normalize(rotation.Value), quaternion.AxisAngle(math.up(), rotSpeedIJobForEach.RadiansPerSecond * DeltaTime));
        }
    }

    // OnUpdate runs on the main thread.
    protected override JobHandle OnUpdate(JobHandle inputDependencies)
    {
        var job = new RotationSpeedJob
        {
            DeltaTime = Time.deltaTime
        };

        return job.Schedule(this, inputDependencies);
    }
}

3.IJobChunk

IJobChunk与IJobForEach类似,但是:Systems using IJobChunk can handle more complex situations than those supported by IJobForEach, while maintaining maximum efficiency.即IJobChunk更好点。

4.SubScene

如果场景中有大量的物体,可以把它们分成一系列的SubScene,然后放到主场景中。
如下图所示SubScene是当前的主场景,Game View中的物体其实是RotatingCube子场景中的物体,通过SubScene脚本实现。

在这里插入图片描述

5.SpawnFromMonobehaviour

如何在Monobehaviour中生成一个Entity实例呢?
首先通过GameObjectConversionUtility.ConvertGameObjectHierarchy(Prefab, World.Active);把一般普通的预制体转成EntityPrefab,然后用
World.Active.EntityManager.Instantiate(prefab)进行实例化。
未完待续

Unity ECS(Entity Component System)是Unity引擎的一种编程范式,它是一种数据驱动的编程模型,它将游戏对象(Entity)分解为数据和行为两个部分,其中数据由组件(Component)来表示,行为则由系统(System)来实现。相对于传统的面向对象编程模型,ECS提供了更高效、更灵活的编程方式,可以有效地提高游戏的性能和扩展性。 下面是我学习Unity ECS时的笔记: ## Entity Entity是ECS中最基本的概念,它表示游戏对象。每个Entity由一个唯一的ID来标识,可以通过EntityManager来创建、销毁、查询和管理Entity。 ## Component Component是Entity的数据部分,用来描述Entity的属性和状态。每个Component包含一些数据成员和一些方法,用来操作这些数据成员。Component是以结构体(struct)的形式定义的,通常只包含数据成员,不包含方法。 ## System System是Entity的行为部分,用来实现游戏逻辑和操作Component。System可以访问和操作EntityManager和Component,但不能直接访问Entity。每个System包含一个或多个Component,表示它所处理的数据类型。System是以类(class)的形式定义的,通常包含一个Update方法,用来实现游戏逻辑。 ## Job Job是一种轻量级的线程,用于并行执行System中的任务。Job可以访问和操作Component,但不能直接访问Entity和EntityManager。Job通常是以结构体(struct)的形式定义的,不包含方法。 ## Archetype Archetype是Entity的集合,包含一组具有相同Component类型的Entity。Archetype可以用来优化数据的访问和处理,可以在不同的System之间共享。 ## Chunk Chunk是Archetype中的数据块,包含一组连续的Entity和它们的Component数据。Chunk可以用来优化内存的分配和访问,可以在Job中进行并行处理。 ## Buffer Buffer是一种Component类型,用来存储可变长度的数据,例如数组或列表。Buffer可以在System和Job中进行修改和访问。 以上是我学习Unity ECS时的笔记,希望对你有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牙膏上的小苏打2333

哟,哟,切克闹,煎饼果子来一套

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值