一、目的
- 实现生成Cube
- 随机移动Cube
- 随机修改方向数据
- 移动
二、开始
1、构建一个CubeMoveAuthoring类,用于将数据拿进ECS
2、创建一些需要的ComponentData
- SpawnerObjComponentData:用于生成cube
- CubeMoveComponentData:用于移动
- ChangeMoveDirIntervalComponentData:用于切换移动方向的计时器数据
using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;
namespace DEMO._01_CubeMove
{
/// <summary>
/// 场景中挂载的,类似Config的东西
/// </summary>
public class CubeMoveAuthoring : MonoBehaviour
{
// 随机切换位置的时间
public float intervalTime;
// 生成的数量
public int spawnerCount;
// 最小速度
public float minSpeed;
// 最大速度
public float maxSpeed;
// 生成的obj原型
public GameObject obj;
// 构建Baker
private class CubeMoveBaker : Baker<CubeMoveAuthoring>
{
public override void Bake(CubeMoveAuthoring authoring)
{
// 动态构建一个Entity
var entity = GetEntity(TransformUsageFlags.Dynamic);
// 给这个Entity添加SpawnerObjComponentData组件
AddComponent(entity,new SpawnerObjComponentData()
{
spawnerCount = authoring.spawnerCount,
spawnerObj = GetEntity(authoring.obj,TransformUsageFlags.Dynamic),
minSpeed = authoring.minSpeed,
maxSpeed = authoring.maxSpeed,
intervalTime = authoring.intervalTime
});
}
}
}
// 用于将编辑器里的值拿给ECS 的Bake用组件
public struct SpawnerObjComponentData : IComponentData
{
public int spawnerCount;
public Entity spawnerObj;
public float minSpeed;
public float maxSpeed;
public float intervalTime;
}
// 移动组件
public struct CubeMoveComponentData : IComponentData
{
public float3 moveDir;
public float moveSpeed;
}
/// <summary>
/// 修改移动方向的数据的组件
/// </summary>
public struct ChangeMoveDirIntervalComponentData : IComponentData
{
public float intervalTime;
public float curIntervalTime;
}
}
3、创建SpawnerObjSystem.cs用于生成Cube
using DEMO.Common;
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
namespace DEMO._01_CubeMove
{
/// <summary>
/// 负责生成cube (没用job)
/// </summary>
[BurstCompile]
public partial struct SpawnerObjSystem : ISystem
{
[BurstCompile]
public void OnCreate(ref SystemState state)
{
//限制只有在有DemoCubeMove和SpawnerObjComponentData的情况下才执行
state.RequireForUpdate<DemoCubeMove>();
state.RequireForUpdate<SpawnerObjComponentData>();
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
//只执行一次
state.Enabled = false;
//获取单例
var spawnerObjData = SystemAPI.GetSingleton<SpawnerObjComponentData>();
//构建需要生成的数组
NativeArray<Entity> entities = new NativeArray<Entity>(spawnerObjData.spawnerCount,Allocator.Temp);
//实例化Entity
state.EntityManager.Instantiate(spawnerObjData.spawnerObj, entities);
//创建随机数
Random random = Random.CreateFromIndex((uint)SystemAPI.Time.ElapsedTime);
foreach (Entity entity in entities)
{
//修改坐标
state.EntityManager.SetComponentData(entity,LocalTransform.FromPosition(random.NextFloat3(-10,10)));
//添加修改位置间隔组件
state.EntityManager.AddComponentData(entity,new ChangeMoveDirIntervalComponentData()
{
intervalTime = spawnerObjData.intervalTime,
curIntervalTime = spawnerObjData.intervalTime
});
//添加移动组件
state.EntityManager.AddComponentData(entity, new CubeMoveComponentData()
{
moveDir = 0,
moveSpeed = random.NextFloat(spawnerObjData.minSpeed,spawnerObjData.maxSpeed)
});
}
}
}
}
4、创建ChangeCubeMoveDirSystem.cs,根据倒计时间隔,随机修改移动方向
using DEMO.Common;
using Unity.Burst;
using Unity.Entities;
using Unity.Mathematics;
namespace DEMO._01_CubeMove
{
/// <summary>
/// 修改移动方向,在CubeMoveSystem之前调用 (没用job)
/// </summary>
[UpdateBefore(typeof(CubeMoveSystem))]
[BurstCompile]
public partial struct ChangeCubeMoveDirSystem : ISystem
{
[BurstCompile]
public void OnCreate(ref SystemState state)
{
//限制只有在有DemoCubeMove和CubeMoveComponentData和ChangeMoveDirIntervalComponentData的情况下才执行
state.RequireForUpdate<DemoCubeMove>();
state.RequireForUpdate<CubeMoveComponentData>();
state.RequireForUpdate<ChangeMoveDirIntervalComponentData>();
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
// deltaTime用于间隔时间的计算
float deltaTime = SystemAPI.Time.DeltaTime;
// 用流逝时间做个随机数
Random r = Random.CreateFromIndex((uint)SystemAPI.Time.ElapsedTime);
// 遍历查询
foreach (var changeCubeMoveDirAspect in SystemAPI.Query<ChangeCubeMoveDirAspect>())
{
// 判断间隔时间是否达到
if (changeCubeMoveDirAspect.UpdateChangeTime(deltaTime))
{
// 如果达到则随机修改移动方向
changeCubeMoveDirAspect.ChangeMoveDir(r.NextFloat3(new float3(-1),new float3(1)));
}
}
}
}
/// <summary>
/// 构建了个结构,用于查询
/// </summary>
readonly partial struct ChangeCubeMoveDirAspect: IAspect
{
public readonly RefRW<CubeMoveComponentData> moveData;
public readonly RefRW<ChangeMoveDirIntervalComponentData> changeDirData;
/// <summary>
/// 更新时间
/// </summary>
public bool UpdateChangeTime(float deltaTime)
{
if (changeDirData.ValueRO.curIntervalTime > 0)
{
changeDirData.ValueRW.curIntervalTime -= deltaTime;
return false;
}
changeDirData.ValueRW.curIntervalTime = changeDirData.ValueRO.intervalTime;
return true;
}
/// <summary>
/// 修改移动方向
/// </summary>
public void ChangeMoveDir(float3 dir)
{
moveData.ValueRW.moveDir = dir;
}
}
}
5、创建CubeMoveSystem.cs让cube移动
using DEMO.Common;
using Unity.Burst;
using Unity.Entities;
using Unity.Transforms;
namespace DEMO._01_CubeMove
{
/// <summary>
/// 负责Cube移动 (没用job)
/// </summary>
[BurstCompile]
public partial struct CubeMoveSystem : ISystem
{
[BurstCompile]
public void OnCreate(ref SystemState state)
{
// 限制只有在有DemoCubeMove和CubeMoveComponentData的情况下才执行
state.RequireForUpdate<DemoCubeMove>();
state.RequireForUpdate<CubeMoveComponentData>();
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
// 查询组件,更新位置
var deltaTime = SystemAPI.Time.DeltaTime;
foreach (var (transform, moveData) in
SystemAPI.Query<RefRW<LocalTransform>, RefRO<CubeMoveComponentData>>())
{
transform.ValueRW.Position += moveData.ValueRO.moveDir * moveData.ValueRO.moveSpeed * deltaTime;
}
}
}
}
三、效果展示
直接拉满生成数量
运行看看
十万个Cube,没使用job,能跑45~50帧