初探unity中的ECS

ECS是一种软件架构模式,就像MVC一样。ECS最早在游戏《守望先锋》中提及到的相关链接。ECS具体是指实体(entity)、 组件(component)和系统(system):

实体:实体是一个ID,它是一个唯一的标识符,用于标识一个对象,它本身不包含任何数据,只是一个ID,它的作用是用于标识一个对象,它的数据是由组件来提供的。

组件:组件是一个数据结构,它包含了一些数据,用于描述一个对象的属性,组件是没有任何行为的,它只是一个数据结构。

系统:主要用户逻辑处理,进行状态迁移。系统中不保留数据,且是无状态的。

三者之间的关系如下图所示:

ECS在unity中出现的原因

在使用unity开发的时候,monobehaviour是我们最常用的,然而monobehaviour中的update是基于gameobject去更新的且无序的,这样很容易造成memory cache miss。而ECS是基于数据的,它将具有相同Component组合的Entity放在一起,这样可以更好的利用cache,提高性能。

archetype

通过上面的图和介绍我们知道通过将不同的Component组合和Entity一起组成了GameOjbect,Component不同组合的唯一性在ECS中被称为archetype。在ECS中,archetype是一个很重要的概念,它是用来管理内存的,每个archetype都有一个chunk列表,chunk是一种内存管理方式。

上图中EntityA和EntityB具有相同的Component组合,所以它们属于同一个Archetype M,而EntityC具有不同的Component组合,所以它们属于不同的Archetype N。

下图是一个chunk的内存排布:

component在chunk中的排布.

Archetype ArchetypeChunkData Chunks; ComponentTypeInArchetype* Types; ArchetypeChunkData Chunk** p; Chunk

执行System

unity会自己实例化system,system里的方法默认都在主线程执行,可以通过一下几种方式来实现多线程

  • Entities.ForEach
  • Job.WithCode
  • IJobEntity
  • IJobEntityBatch
  • C# Job System

各部分的创建

下面是一个简单的例子,创建一个CustomSystem,它会在每一帧中更新CustomData的值。ComponentData不一定要和MonoBehaviour一起使用,它可以单独使用,像一些CPU密集性的计算可以使用ComponentData来实现。下面的示例重点是为了说明各部分的创建过程,从LaunchECS中可以发现仅仅使用了World中的EntityManager来创建了一个Entity,系统的创建被注视掉了。这是因为unity会自己实例化system,所以我们不需要手动创建system。

C# 复制代码
public class Custom : MonoBehaviour
{
    private void Awake()
    {
        LaunchECS();
    }

    private void LaunchECS()
    {
        var world = World.DefaultGameObjectInjectionWorld;
        world.EntityManager.CreateEntity(typeof(CustomData));
        // world.CreateSystem<CustomSystem>();
    }
}

public struct CustomData : IComponentData
{
    public int Value;
}

public partial class CustomSystem : SystemBase
{
    [BurstCompile]
    protected override void OnUpdate()
    {
        var timeElapsedTime = World.Time.ElapsedTime;
        Entities.ForEach((ref CustomData customData) =>
        {
            customData.Value = (int)(100 * math.sin(timeElapsedTime));
        }).ScheduleParallel();
    }
}

游戏制作

ECS的大致情况我们已经了解了,那如何在项目中应用呢。下面是一个简单的例子,我们创建一个Cube,然后通过ECS来控制它的移动。

  1. 将下面的代码放到名叫MoveMono的cs文件中,
  2. 然后在场景中添加一个sub scene
  3. 在sub scene中添加一个Cube,然后添加一个MoveMono组件,并设置Velocity的值。
    运行后,我们会发现Cube会按照我们设置的Velocity的值进行移动。
C# 复制代码
[GenerateAuthoringComponent]
public struct MoveData : IComponentData
{
    public float3 Velocity; 
}
    
public partial class MoveSystem : SystemBase
{
    [BurstCompile]
    protected override void OnUpdate()
    {
        var deltaTime = World.Time.DeltaTime;
        Entities.ForEach((ref Translation translation, in MoveData moveData) =>
        {
            translation.Value += moveData.Velocity * deltaTime;
        }).ScheduleParallel();
    }
}

上面代码中使用了GenerateAuthoringComponent,这个属性将会自动生成一个名为MoveMono的MonoBehaviour,所有虽然我们并没有显示的创建MoveMono,但是我们可以给GameObject添加组件是可以看到MoveMono.

除了GenerateAuthoringComponent属性以外还有其他方式去将ComponentData和MonoBehaviour关联起来,还可以有其他方式。我们将在后面的gameplay文章中介绍。

相关推荐
mxwin8 小时前
unity shader中 ddx ddy是什么
unity·游戏引擎·shader
郝学胜-神的一滴11 小时前
[简化版 GAMES 101] 计算机图形学 08:三角形光栅化上
c++·unity·游戏引擎·godot·图形渲染·opengl·unreal
nnsix11 小时前
Unity ILRuntime 笔记
unity·游戏引擎
nnsix13 小时前
Unity API 兼容的 .NET Standard 2.1 和 .NET Framework 区别
unity·游戏引擎·.net
mxwin13 小时前
Unity Shader 制作半透明物体 使用多Pass提前写入深度的方式 避免穿模
unity·游戏引擎
nnsix15 小时前
Unity HybridCLR 笔记
笔记·unity·游戏引擎
nnsix16 小时前
Unity Addressables 笔记
unity·游戏引擎
RReality16 小时前
【Unity Shader URP】视差贴图 实战教程
ui·平面·unity·游戏引擎·图形渲染·贴图
小清兔1 天前
Addressable的设置打包流程
笔记·游戏·unity·c#
3D霸霸1 天前
Sourcetree 拉取新工程
数据仓库·unity