欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Unity ECS学习笔记(9)SpawnAndRemove

程序员文章站 2022-06-06 22:59:36
...

最近在学习unity的ecs框架,转载几篇写的比较好的文章帮助理解

原文日期 2019-12-5 避免误导未来使用正式版的开发者。

 

1.IJobForEachWithEntity和IJobForEach

为了实现这个功能,我们顺便就引出了另外一种筛选实体的方式——IJobForEachWithEntity。

我们之前已经介绍过IJobForEach了,这次的IJobForEachWithEntity和之前的差不多,只是有一个小区别。

IJobForEach只能筛选出实体的组件,即,只能对组件进行读写操作。

IJobForEachWithEntity不仅能筛选出组件,还能筛选出实体,即,可以对组件和实体进行操作。

由于我们这次的例子是要删除物体的,所以必须把实体对象也筛选出来,否则无法执行删除操作。

注意,IJobForEachWithEntity为什么要放在这个后面讲呢?因为它涉及到了前面的很多知识,如果大家没有弄懂前面的Job、EntityCommandBuffer等知识,建议重复多看几遍,然后再接着往下看。

2.组件

为了演示这个例子,我们还是要创建一个组件,简单起见,我们用最开始的方式:

Unity ECS学习笔记(9)SpawnAndRemove

3.实体

Unity ECS学习笔记(9)SpawnAndRemove

我们新建一个Cube

Unity ECS学习笔记(9)SpawnAndRemove

4.系统

重点来了,我们来看看System的代码:

using Unity.Entities;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
using Unity.Transforms;
using Unity.Burst;

public struct LifeTime : IComponentData
{
	public float m_Value;
}

public class LifeTimeSystem : JobComponentSystem
{
	/// <summary>
	/// 实体命令缓存系统--阻塞
	/// </summary>
	private EntityCommandBufferSystem m_Barrier;

	[BurstCompile]
	struct LifeTimeJob : IJobForEachWithEntity<LifeTime>
	{
		public float DeltaTime;
		[WriteOnly]
		public EntityCommandBuffer.Concurrent CommandBuffer;

		/// <summary>
		/// 每帧执行,如果寿命 < 0 则摧毁实体
		/// </summary>
		/// <param name="entity">实体</param>
		/// <param name="jobIndex">任务索引</param>
		/// <param name="lifeTime">寿命</param>
		public void Execute(Entity entity, int jobIndex, ref LifeTime lifeTime)
		{
			lifeTime.m_Value -= DeltaTime;
			if (lifeTime.m_Value < 0)
			{
				CommandBuffer.DestroyEntity(jobIndex, entity);
			}
		}
	}

	/// <summary>
	/// 将阻塞缓存起来
	/// </summary>
	protected override void OnCreate()
	{
		m_Barrier = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
	}

	/// 在主线程上每帧运行OnUpdate
	/// </summary>
	/// <param name="inputDependencies">输入依赖</param>
	/// <returns>任务</returns>
	protected override JobHandle OnUpdate(JobHandle inputDeps)
	{
		var commandBuffer = m_Barrier.CreateCommandBuffer().ToConcurrent();
		var job = new LifeTimeJob
		{
			CommandBuffer = commandBuffer,
			DeltaTime = Time.deltaTime
		}.Schedule(this, inputDeps);
		m_Barrier.AddJobHandleForProducer(job);
		return job;
	}
}

虽然代码看起来很复杂,实际上都是我们熟悉的东西,比如JobComponent和EntityCommandBufferSystem。

唯一要关注的就是LifeTimeJob这个结构体:

Unity ECS学习笔记(9)SpawnAndRemove

这次我们使用了IJobForEachWithEntity接口,其实和IJobForEach的用法基本一致,只不过,我们在Execute函数的参数里可以获得Entity对象。

于是,我们判断实体的LifeTimeComponent的LifeTime是否小于0,是的话,则销毁实体。

当然,我们是通过EntityCommandBuffer来销毁实体的,因为在Job里是不能直接销毁实体的。

好,大家运行一下,Cube会在3秒后消失。

 

注意,本系列教程基于DOTS相关预览版的Package包,是预览版,不代表正式版的时候也适用。

相关标签: Unity ECS