使用实体组件系统和作业系统一起使用让性能起飞!
案例九:UnityECS和Job系统模拟雨滴降落(Scne10)
脚本:PureJob_DropData
using Unity.Entities;
[System.Serializable]
public struct PureJob_DropData : IComponentData
{
public int velocity;
public float delayTime;
}
脚本:PureJob_Proxy
using UnityEngine;
using Unity.Entities;
public class PureJob_Proxy : MonoBehaviour, IConvertGameObjectToEntity
{
public PureJob_DropData dropData;
public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
{
dstManager.AddComponentData<PureJob_DropData>(entity, dropData);
}
}
脚本:PureJob_Main
using UnityEngine;
using Unity.Entities;
using Unity.Collections;
using Unity.Transforms;
public class PureJob_Main : MonoBehaviour
{
public int createCount = 300;
public GameObject prefab; // 雨滴预制体
public int dropSpeed = 10;
public int dropHeight = 50;
public int insRnage = 40; // 生成范围
private EntityManager entityManager;
private NativeArray<Entity> entities;
void Start()
{
this.CreateMain();
}
private void CreateMain()
{
// 创建预制体实体
entityManager = World.Active.EntityManager;
entities = new NativeArray<Entity>(createCount, Allocator.Persistent);
Entity entityPrefab = GameObjectConversionUtility.ConvertGameObjectHierarchy(prefab, World.Active);
entityManager.Instantiate(entityPrefab, entities);
//初始化数据
for (int i = 0; i < createCount; i++)
{
entityManager.SetComponentData<PureJob_DropData>(entities[i], new PureJob_DropData
{
delayTime = UnityEngine.Random.Range(0, 10),
velocity = UnityEngine.Random.Range(dropSpeed / 10, dropSpeed),
});
var num = UnityEngine.Random.insideUnitSphere* insRnage;
num.y = dropHeight;
entityManager.SetComponentData<Translation>(entities[i], new Translation
{
Value = num
});
}
}
private void OnDestroy()
{
entities.Dispose();
}
}
脚本:PureJob_DropJobSystem
using UnityEngine;
using Unity.Entities;
using Unity.Jobs;
using Unity.Transforms;
using Unity.Collections;
public class PureJob_DropJobSystem : JobComponentSystem
{
// Unity Job提供的获取实体组件的方法
struct GravityJob : IJobForEach<PureJob_DropData, Translation>
{
[ReadOnly]
public int minHeight;
[ReadOnly]
public float deltaTime;
[ReadOnly]
public int velocity;
[ReadOnly]
public int delay;
public void Execute(ref PureJob_DropData dropData, ref Translation translation)
{
if (dropData.delayTime > 0)
{
dropData.delayTime -= deltaTime;
}
else
{
if (translation.Value.y < minHeight)
{
translation.Value.y = 0;
dropData.velocity = velocity;
dropData.delayTime = delay;
}
else
{
translation.Value.y -= dropData.velocity * deltaTime;
}
}
}
}
public int minHeight = -100; // 下落最低值
#region
/*
protected override void OnUpdate()
{
// 通过ECS提供的筛方式遍历场景中包含该数据组件的实体
Entities.ForEach((ref Translation translation, ref DropData dropData) =>
{
if (dropData.delay > 0)
{
dropData.delay -= Time.deltaTime;
}
else
{
if (translation.Value.y < minHeight)
{
translation.Value.y = 0;
dropData.velocity = Random.Range(1, 10);
dropData.delay = Random.Range(1, 10);
}
else
{
translation.Value.y -= dropData.velocity * Time.deltaTime;
}
}
});
}
*/
#endregion
protected override JobHandle OnUpdate(JobHandle inputDeps)
{
GravityJob gravityJobSystem = new GravityJob
{
minHeight = minHeight,
delay = UnityEngine.Random.Range(1, 10),
velocity = UnityEngine.Random.Range(1, 10) * 10,
deltaTime = Time.deltaTime
};
JobHandle jobHandle = gravityJobSystem.Schedule(this, inputDeps);
jobHandle.Complete();
return jobHandle;
}
}
如上图,生成了10万个小球模拟雨滴下落,不同的Job在并行计算从而提高性能。注意: PureJob_DropJobSystem中可以看到,UnityECS为Job也提供了单独的筛选方式来获取实体~
远程项目仓库(github):https://github.com/h1031464180/UnityECS