Unity 革命性技术DOST入门二 ECS简单使用介绍

上一篇:Unity 革命性技术DOST入门一 使用介绍

ECS介绍

ECS是一种软件架构模式,由三个元素组成:实体(Entity),组件(Component)和系统(System)(看起来和MVC很相似)。游戏程序分为这三个主要元素,并且通过定义每个系统的责任和关系来管理游戏。
实体代表游戏世界中的事物。实体本身没有特定功能,它们将会被组件填充来成为一个实体。

组件是附加到事物的数据。重点不是对象,而是数据,没有办法操纵它。比如操作游戏的角色时,位置,速度和体力等每个状态都将成为一个组成部分,并与称为“角色”实体相关联。另外,实体中的字段信息也被表示为组件部分。

系统是游戏世界的法则。给定与实体关联的某些组件作为数据输入源,或者更新某些组件的值(可能与输入的组件相同)。随着整个系统更新每一帧,游戏世界也在不断进行。我认为最容易想象的是物理定律。例如,想象一个刚体实体。它的运动基于利用位置和速度两个分量的系统来更新坐标。
粗略地说,系统负责处理,组件负责数据,而实体是一组组的组件,用于过滤系统正在处理的内容。由于系统和数据是完全分开的,因此它与面向对象不兼容。

下面为官方介绍:

实体组件系统(ECS)是Unity面向数据的技术堆栈的核心。顾名思义,ECS包含三个主要部分:

  • Entities:填充您的游戏或程序的实体或事物。
  • Components:与您的实体相关联的数据,但是应该有数据本身而不是实体来组织。(这种组织上的差异正是面向对象和面向数据的设计之间的关键差异之一)
  • Systems:主要逻辑所在,是把Components的数据从当前状态转换为下一个状态的逻辑,例如,一个system可能会通过他们的速度乘以从前一帧到这一帧的时间间隔来更新所有的移动中的entities的位置。

ECS使用介绍

这里就以一个实际案例来介绍下ECS的基本使用

1.Components数据组件

纯数据,不含有其他逻辑行为。 例如:旋转速度,缩放大小之类的。

using Unity.Entities;

public struct MoveSpeedComponent : IComponentData
{
    public float mMoveSpeed;//移动速度
}

2. System

主要逻辑所在,根据组件的集合(Enitites)和纯数据(Components)编写对应的逻辑,例如旋转,移动等一些逻辑。

这里我们通过ForEach()方法去遍历所有Entity上的数据组件,并且修改他们的数值!

下面的移动代码种用到了quaternion旋转函数,它是依赖于Unity.Mathematics命名空间的,quaternion为我们提供了极多的关于处理旋转和角度的函数,给我们带来了很大的便利,他为我们提供的欧拉角修改的方式以及四元数修改的方式,对于用不惯四元数修改的旋转的,这无疑是个最好的方式,具体的这里就不一一介绍了。

using Unity.Entities;
using Unity.Transforms;
using Unity.Mathematics;
public class MoveSystem : ComponentSystem
{
    protected override void OnUpdate()
    {
        Entities.ForEach((ref MoveSpeedComponent moveCmpt ,ref Translation translation,ref Rotation rotation) =>
        {
            translation.Value.x += moveCmpt.mMoveSpeed * Time.DeltaTime;

            if (translation.Value.x>30)
            {
                //反转移动速度和旋转
                rotation.Value=quaternion.Euler(new float3(0,130,0));
                moveCmpt.mMoveSpeed = -math.abs(moveCmpt.mMoveSpeed);
            }
            else if (translation.Value.x < -30)
            {
                //反转移动速度和旋转
                rotation.Value = quaternion.Euler(new float3(0, -130, 0));
                moveCmpt.mMoveSpeed =math.abs(moveCmpt.mMoveSpeed);
            }
        });
    }
}

3.Entity

最后是Entity启动类,他为我们初始化出了我们的Entity,以及Entity原型的创建和数据设置,这个类我把他挂载到在了相机上,方便我们进行初始化。

可以看到我们通过SetComponentData()方法初始化了我们的旋转、移动速度、和出生位置。


using UnityEngine;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Collections;
using Unity.Transforms;
using Unity.Rendering;
public class EntityMain : MonoBehaviour
{
    EntityManager mEentityManager;
   [SerializeField]
    private Mesh[] mFishMeshArray;//模型Mesh数组
    [SerializeField]
    private Material[] mFishMaterialArray;//模型材质数组
    void Start()
    {

         mEentityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
        //创建原型
        EntityArchetype entityArchetype = mEentityManager.CreateArchetype(
            typeof(MoveSpeedComponent),
            typeof(Translation),
            //下面三个实体一定要加不然是看不到实例化的物体的
            typeof(RenderBounds),
            typeof(RenderMesh),
            typeof(LocalToWorld),
            //添加旋转数据
            typeof(Rotation)
            );
        //创建实体数组 5000代表就生成5000个
        NativeArray<Entity> entityArray = new NativeArray<Entity>(5000, Allocator.Temp);
        //创建实体
        mEentityManager.CreateEntity(entityArchetype, entityArray);
        for (int i = 0; i < entityArray.Length; i++)
        {
            Entity entity = entityArray[i];
            //设置数据
            mEentityManager.SetComponentData(entity, new Rotation { Value = quaternion.Euler(0, -130, 0) });
            mEentityManager.SetComponentData(entity, new MoveSpeedComponent { mMoveSpeed = UnityEngine.Random.Range(3, 10) });
            mEentityManager.SetComponentData(entity, new Translation { Value = new float3(UnityEngine.Random.Range(-20, 20), UnityEngine.Random.Range(-15, 15), UnityEngine.Random.Range(5, 100)) });
            int index = UnityEngine.Random.Range(0, 3);
            //设置材质和渲染网格
            mEentityManager.SetSharedComponentData(entity, new RenderMesh { mesh = mFishMeshArray[index], material = mFishMaterialArray[index] });
        }
        //一定要记得释放
        entityArray.Dispose();
    }
}

mEentityManager.CreateEntity() 方法可以为我们创建一个Entity实体,相当于New GameObjcet

mEentityManager.CreateArchetype() 方法可以我们的Entity的原型,相当于AddComponent

mEentityManager.SetComponentData()方法则是可以设置Entity数据组件的初始值

在Entity的Inspector面板我们可以看到我们的数据组件:

我们添加的数据组件都在上面,并且我们修改的数值,也有所变化

在这里插入图片描述

一共有三种鱼,每种材质都不同。

在这里插入图片描述

最后是我们的实际运行效果,性能并不是最优,因为我们只使用了ECS和Burst

并且我们的主要目的是去了解如何使用ECS。

下面是同屏1000条鱼的截图

在这里插入图片描述

下面是 标准性能 下实际运行视屏演示

注意:视屏种的不流畅是录屏软件帧率不够导致的不流畅,并不是因为游戏的帧率不够。

5000只鱼:

<iframe allowfullscreen="true" data-mediaembed="bilibili" id="28QbhAKK-1611593944482" src="https://player.bilibili.com/player.html?aid=713854451"></iframe>

DOTS 5000只鱼演示(注意:录屏帧率低导致不流畅)

一万只鱼:

<iframe allowfullscreen="true" data-mediaembed="bilibili" id="vOot7jBt-1611594057137" src="https://player.bilibili.com/player.html?aid=756362967"></iframe>

DOTS 10000只鱼演示(注意:录屏帧率低导致不流畅)

15000只鱼:

<iframe allowfullscreen="true" data-mediaembed="bilibili" id="O1CwcBc4-1611594207274" src="https://player.bilibili.com/player.html?aid=416284281"></iframe>

DOTS 15000千只鱼性能的展示

可以看到当使用三种模型材质的鱼数量一共达到15000只时,并且在位移逻辑和游动动画都在的情况下,我们还能稳定在30多帧,可以说很不错了。

并且我们只是简单写了点代码 开了Burst进行的测试。

意味着我们还有很大的提升空间。

关于ECS的简单使用就到这里了

下一篇:Unity 革命性技术DOST 入门三JobSystem系统

原文地址:https://blog.csdn.net/qq_42461824/article/details/113141736

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


这篇文章主要介绍了Unity游戏开发中外观模式是什么意思,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家...
这篇文章主要介绍Unity中地面检测方案的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!1.普通射线在角色坐标(一般是脚底)...
这篇文章主要介绍了Unity游戏开发中如何消除不想要的黄色警告,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带...
这篇文章主要介绍了Unity中有多少种渲染队列,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解
这篇文章主要介绍Unity中如何实现Texture,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!了解Texture2D 如上图,Texture2D是一张
小编给大家分享一下Unity中DOTS要实现的特点有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让...
这篇文章给大家分享的是有关unity中如何实现UGUI遮罩流光特效的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。下面是核心shader:Sh...
这篇文章主要为大家展示了“Unity中如何实现3D坐标转换UGUI坐标”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下...
这篇文章主要介绍了Unity游戏开发中设计模式的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家...
这篇文章主要介绍了Unity中如何实现仿真丝袜渲染,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了...
这篇文章给大家分享的是有关Unity插件OVRLipSync有什么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。项目需要接入对话口型动...
这篇文章主要介绍了Unity性能优化之DrawCall的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家...
这篇文章给大家分享的是有关Unity给力插件之Final IK怎么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。这插件有什么用:一般游...
这篇文章给大家分享的是有关Unity中如何内嵌网页插件UniWebView的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、常见Unity中内...
小编给大家分享一下Unity如何做流体物理的几个轮子,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让...
小编给大家分享一下Unity中Lod和Occlusion Culling的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收...
这篇文章将为大家详细讲解有关Unity中LineRenderer与TrailRenderer有什么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获...
这篇文章主要介绍了Unity中coroutine问题的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起...
这篇文章将为大家详细讲解有关unity中spine怎么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。骨骼动画首先我们来看到...
这篇文章主要为大家展示了“Unity Shader后处理中如何实现简单均值模糊”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学...