DOTS 1.0 预览版,更新了什么?
近期,DOTS 1.0 的预览版已经发布,开发者社区大佬雨松 MOMO 以及社区牛人达哥纷纷第一时间进行了学习,并输出文章和视频,帮助大家掌握本次重大更新。
本文摘自雨松 MOMO 的文章,欢迎学习。
调试部分
Dots 从 2018 年问世到现在已经4年时间了,阻碍 Dots 发展的大家普遍的共识是:“开发方式对机器友好,对人不友好”。传统 GameObject 的开发流程中是对人友好的,但对机器不友好。Dots 是则对机器友好,对人不友好!这样的开发模式人就不容易理解和看懂了。显然需要在人和机器中找一个平衡点,Dots 1.0 这次是带着诚意来的。
调试面板
Entities Hierarchy (实体层次面板视图)
在实体层次面板视图中可看到最终运行时实体的排布信息。
如下图所示,在实体检测面板中可看到所有的实体组件信息,还可以单独展开查看,具体的组件中的数值。
在 Relationships 中还可以看到当前实体被那些系统所关注,展开后还可以看到具体 Query 的组件,以及读写状态。
新版 Dots 提出了创作模式与运行模式的概念,之前的方式在关闭运行游戏以后所有的改动就会自动还原。当处于创作模式下,无论游戏运行中都是可以修改并且保存的。这就能解决有些编辑工作需要依赖游戏运行后,以前由于引擎限制了无法解决此类问题,所有修改都必须在非运行模式下。
创作模式(点击橘黄色的小圆圈切换)
组件中属性前面如果有橘黄色竖杠 “|”表示属于运行模式数据,关闭游戏数据会还原。没有则表示它是创作模式下的数据,运行时不会进行修改它。
组件
这里包含了所有组件,可以搜索反向找到它与那些实体之间的有关联。
系统
这里列出了当前所有的系统,可以随时的关闭与启动某个系统,方便快速定位问题。
Archetypes
具体每个 Archetypes 所使用的组件分部以及精准的内存占用。
代码部分
这次代码部分的更新在使用侧这边并不是特别大,API的设计也围绕着使用者更加方便而展开,下面让我们来盘一盘有哪些改变。
Baker 全新烘焙管道
Conversion 的替代者,用于将创作端的 GameObject 对象转换成实体对象。主要原因是 Dots1.0 支持了创作模式与运行模式,随时都可以对数据进行修改。看文档的意思以前都是运行时进行 GameObject 到 Entity 的转换,这导致编辑模式下需要额外维护创作的数据。通过新的 Baker API 可以得到更快的速度以及更稳健的性能。
从使用的角度来说就是换个 API 名字,主要还是把 Monobehaviour 上的数据转成实体组件。
public class SpawnerAuthoring : MonoBehaviour
{
public GameObject Prefab;
class Baker : Baker<SpawnerAuthoring>
{
public override void Bake(SpawnerAuthoring authoring)
{
AddComponent(new Spawner { Prefab = GetEntity(authoring.Prefab) });
}
}
}
struct Spawner : IComponentData
{
public Entity Prefab;
}
Aspect 可以将多个实体组件包装在一个结构体中。如原本在遍历组件的时候需要在 OnUpdate 中写一些获取组件以及对应执行的方法,如果有多个系统或者代码公用就可以写在包装器中,代码写起来会更加方便。
readonly partial struct VerticalMovementAspect : IAspect
{
readonly RefRW<LocalToWorldTransform> m_Transform;
readonly RefRO<RotationSpeed> m_Speed;
public void Move(double elapsedTime)
{
m_Transform.ValueRW.Value.Position.y = (float)math.sin(elapsedTime * m_Speed.ValueRO.RadiansPerSecond);
}
}
然后在 OnUpdate 或者 JobUpdate 中可以直接去 Query 这个 Aspect,并且执行对应的方法。
public void OnUpdate(ref SystemState state)
{
foreach (var movement in SystemAPI.Query<VerticalMovementAspect>())
{
movement.Move(elapsedTime);
}
}
可启动/关闭组件
一个小小的启动或者关闭组件在 DOTS 中可以说是很复杂的操作,因为它会改变 Archetypes 的内存结构,还会影响 Query 非常影响性能。新版 Dots 引用了 IEnableableComponent 接口,配合 SetComponentEnabled 方法动态开关组件,这是一个底层的操作,号称比普通的删除添加组件要快 9 倍左右。
public struct TargetEnableable : IComponentData, IEnableableComponent
{
public float3 target;
}
// ...
var archetype = m_Manager.CreateArchetype(typeof(EcsTestData), typeof(TargetEnableable));
var entities = m_Manager.CreateEntity(archetype, 1024, World.UpdateAllocator.ToAllocator);
EntityQuery query = GetEntityQuery(typeof(TargetEnableable));
//关闭第数组中下标4的实体组件TargetEnableable
m_Manager.SetComponentEnabled<TargetEnableable>(entities[4], false);
int fooCount = query.CalculateEntityCount(); // 关闭了一个所以这里返回 1023
[BurstCompile]
public partial struct RotationSpeedSystem : ISystem
{
[BurstCompile]
public void OnCreate(ref SystemState state)
{
}
[BurstCompile]
public void OnDestroy(ref SystemState state)
{
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
var job = new RotationSpeedJob { deltaTime = SystemAPI.Time.DeltaTime };
job.ScheduleParallel();
}
}
IJobEntity
原本的 Entities.ForEach 已经不推荐使用,它虽然简单方便但在一些复杂的环境下不好用,比如无法在 ForEach 中实现嵌套,无法在多个 System 中共同操作,取而代之的则是 IJobEntity。用法非常简单在 Execute 中传入需要的实体组件即可。
partial struct RotationSpeedJob : IJobEntity
{
public float deltaTime;
void Execute(ref LocalToWorldTransform transform, in RotationSpeed speed)
{
transform.Value = transform.Value.RotateY(speed.RadiansPerSecond * deltaTime);
}
}
foreach (var (rotateAspect, speedModifierRef) in
SystemAPI.Query<RotateAspect, RefRO<SpeedModifier>>())
rotateAspect.Rotate(time, speedModifierRef.ValueRO.Value);
https://developer.unity.cn/projects/633c1ed4edbc2a09bd9fefd8
长按关注
第一时间了解Unity引擎动向,学习最新开发技巧
点击“阅读原文”,跳转社区原文