14. EntitiesSample_StateChange

这个示例的内容是鼠标控制cube旋转,点击到哪里,范围内的cube变色和旋转
1.第一个关键点:鼠标发射线
 //函数中掉用了托管代码,不能使用[BurstCompile]标签
        public void OnUpdate(ref SystemState state)
        {
            //获取射线的数据组件
            var hit = SystemAPI.GetSingletonRW<Hit>();
            //射线数据初始化
            hit.ValueRW.HitChanged = false;
            //调用托管api
            if (Camera.main == null || !Input.GetMouseButton(0))
            {
                return;
            }
            //设置射线数据组件
            var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            if (new Plane(Vector3.up, 0f).Raycast(ray, out var dist))
            {
                hit.ValueRW.HitChanged = true;
                hit.ValueRW.Value = ray.GetPoint(dist);
            }
        }
        //射线数据组件
        //public struct Hit : IComponentData
        //{
        //    射线的位置
        //    public float3 Value;
        //    射线的状态
        //    public bool HitChanged;
        //}

需要注意的是:对于这种类全局单例功能,场景中只需要添加一次hit 数据组件

2.世界空间鼠标范围,设置cube的状态

SetStateSystem功能:设置颜色,旋转,添加旋转,移除旋转,激活旋转,不激活旋转,这些功能通过Mode枚举进行切换,调度不同的实体作业

        [BurstCompile]
        public void OnUpdate(ref SystemState state)
        {
            //获取配置数据 预制体 Size鼠标范围,Radius鼠标半径,Mode模式
            var config = SystemAPI.GetSingleton<Config>();
            //获取射线数据
            var hit = SystemAPI.GetSingleton<Hit>();
            //射线的状态
            if (!hit.HitChanged)
            {
#if UNITY_EDITOR
                SystemAPI.GetSingletonRW<StateChangeProfilerModule.FrameData>().ValueRW.SetStatePerf = 0;
#endif
                return;
            }
            //鼠标范围
            var radiusSq = config.Radius * config.Radius;
            //ECB:开始时的命令缓冲,
            var ecbSystem = SystemAPI.GetSingleton<BeginSimulationEntityCommandBufferSystem.Singleton>();
            //需要调度作业完成,才能执行下面逻辑
            state.Dependency.Complete();
            //非托管性能工具时间戳
            var before = ProfilerUnsafeUtility.Timestamp;
            //配置中的模式字段,不能模式执行不同的作业
            if (config.Mode == Mode.VALUE)
            {
                new SetValueJob
                {
                    RadiusSq = radiusSq,
                    Hit = hit.Value
                }.ScheduleParallel();
            }
            else if (config.Mode == Mode.STRUCTURAL_CHANGE)
            {
                new AddSpinJob
                {
                    RadiusSq = radiusSq,
                    Hit = hit.Value,
                    ECB = ecbSystem.CreateCommandBuffer(state.WorldUnmanaged).AsParallelWriter()
                }.ScheduleParallel();

                new RemoveSpinJob
                {
                    RadiusSq = radiusSq,
                    Hit = hit.Value,
                    ECB = ecbSystem.CreateCommandBuffer(state.WorldUnmanaged).AsParallelWriter()
                }.ScheduleParallel();
            }
            else if (config.Mode == Mode.ENABLEABLE_COMPONENT)
            {
                new EnableSpinJob
                {
                    RadiusSq = radiusSq,
                    Hit = hit.Value,
                    ECB = ecbSystem.CreateCommandBuffer(state.WorldUnmanaged).AsParallelWriter()
                }.ScheduleParallel();

                new DisableSpinJob
                {
                    RadiusSq = radiusSq,
                    Hit = hit.Value,
                }.ScheduleParallel();
            }
            //需要调度作业完成,才能执行下面逻辑
            state.Dependency.Complete();
            var after = ProfilerUnsafeUtility.Timestamp;

#if UNITY_EDITOR
            // profiling  性能计算和设置
            var conversionRatio = ProfilerUnsafeUtility.TimestampToNanosecondsConversionRatio;
            var elapsed = (after - before) * conversionRatio.Numerator / conversionRatio.Denominator;
            SystemAPI.GetSingletonRW<StateChangeProfilerModule.FrameData>().ValueRW.SetStatePerf = elapsed;
#endif
        }
    }

    /// <summary>
    /// 实体作业,设置cube状态,执行主要的逻辑
    /// </summary>
    [BurstCompile]
    partial struct SetValueJob : IJobEntity
    {
        public float RadiusSq;
        public float3 Hit;
        //所有拥有 URPMaterialPropertyBaseColor,Spin,LocalTransform三个数据组件的实体都会执行函数中的逻辑
        // URPMaterialPropertyBaseColor 内置的URP材质组件
        //Spin 旋转标识
        void Execute(ref URPMaterialPropertyBaseColor color, ref Spin spin, in LocalTransform transform)
        {
            if (math.distancesq(transform.Position, Hit) <= RadiusSq)
            {
                color.Value = (Vector4)Color.red;
                spin.IsSpinning = true;
            }
            else
            {
                color.Value = (Vector4)Color.white;
                spin.IsSpinning = false;
            }
        }
    }
    /// <summary>
    /// 对于所有没有spin组件的实体,执行这个job
    /// </summary>
    [WithNone(typeof(Spin))]
    [BurstCompile]
    partial struct AddSpinJob : IJobEntity
    {
        public float RadiusSq;
        public float3 Hit;
        public EntityCommandBuffer.ParallelWriter ECB;

        void Execute(Entity entity, ref URPMaterialPropertyBaseColor color, in LocalTransform transform,
            [ChunkIndexInQuery] int chunkIndex)
        {
            // If cube is inside the hit radius.
            if (math.distancesq(transform.Position, Hit) <= RadiusSq)
            {
                color.Value = (Vector4)Color.red;
                ECB.AddComponent<Spin>(chunkIndex, entity);
            }
        }
    }
    /// <summary>
    /// 对于所有有spin组件的实体,执行这个job
    /// </summary>
    [WithAll(typeof(Spin))]
    [BurstCompile]
    partial struct RemoveSpinJob : IJobEntity
    {
        public float RadiusSq;
        public float3 Hit;
        public EntityCommandBuffer.ParallelWriter ECB;

        void Execute(Entity entity, ref URPMaterialPropertyBaseColor color, in LocalTransform transform,
            [ChunkIndexInQuery] int chunkIndex)
        {
            // If cube is NOT inside the hit radius.
            if (math.distancesq(transform.Position, Hit) > RadiusSq)
            {
                color.Value = (Vector4)Color.white;
                ECB.RemoveComponent<Spin>(chunkIndex, entity);
            }
        }
    }

    [WithNone(typeof(Spin))]
    [BurstCompile]
    public partial struct EnableSpinJob : IJobEntity
    {
        public float RadiusSq;
        public float3 Hit;
        public EntityCommandBuffer.ParallelWriter ECB;

        void Execute(Entity entity, ref URPMaterialPropertyBaseColor color, in LocalTransform transform,
            [ChunkIndexInQuery] int chunkIndex)
        {
            // If cube is inside the hit radius.
            if (math.distancesq(transform.Position, Hit) <= RadiusSq)
            {
                color.Value = (Vector4)Color.red;
                ECB.SetComponentEnabled<Spin>(chunkIndex, entity, true);
            }
        }
    }

    [BurstCompile]
    public partial struct DisableSpinJob : IJobEntity
    {
        public float RadiusSq;
        public float3 Hit;

        void Execute(Entity entity, ref URPMaterialPropertyBaseColor color, in LocalTransform transform,
            EnabledRefRW<Spin> spinnerEnabled)
        {
            // If cube is NOT inside the hit radius.
            if (math.distancesq(transform.Position, Hit) > RadiusSq)
            {
                color.Value = (Vector4)Color.white;
                spinnerEnabled.ValueRW = false;
            }
        }
    }

主要的意思是:因为对于ecs,通过组件标识查找物体的,所以如果需要我们整体操作实体的时候,需要像代码中的操作一样,例如:我要设置鼠标范围的方块,通过spin组件标识在鼠标范围内的方块,鼠标外的方块没有spin组件,然后在作业逻辑中,需要执行两段代码,一个是查找有spin标识的实体,一个是查找没有spin标识的实体,这个是一个示例说明:对于不同的实体,拥有不同的标识,然后执行不同的job,上面代码完合成一个job,对于所有的实体,整体进行判断

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值