| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 | using GPUECSAnimationBaker.Engine.AnimatorSystem;using Unity.Burst;using Unity.Collections;using Unity.Entities;using Unity.Mathematics;using Unity.Transforms;namespace GPUECSAnimationBaker.Samples.SampleScenes.Festival.CrowdSpawnerSystem{    [BurstCompile]    public partial struct CrowdSpawnerSystem : ISystem    {        private BufferLookup<GpuEcsAnimationDataBufferElement> gpuEcsAnimationDataBufferLookup;        private ComponentLookup<LocalTransform> localTransformLookup;                [BurstCompile]        public void OnCreate(ref SystemState state)        {            gpuEcsAnimationDataBufferLookup = state.GetBufferLookup<GpuEcsAnimationDataBufferElement>(isReadOnly: true);            localTransformLookup = state.GetComponentLookup<LocalTransform>(isReadOnly: true);        }        [BurstCompile]        public void OnUpdate(ref SystemState state)        {            gpuEcsAnimationDataBufferLookup.Update(ref state);            localTransformLookup.Update(ref state);            EndSimulationEntityCommandBufferSystem.Singleton ecbSystem =                SystemAPI.GetSingleton<EndSimulationEntityCommandBufferSystem.Singleton>();            EntityCommandBuffer.ParallelWriter ecb = ecbSystem.CreateCommandBuffer(state.WorldUnmanaged).AsParallelWriter();            float deltaTime = SystemAPI.Time.DeltaTime;                        state.Dependency = new CrowdSpawnerJob()            {                ecb = ecb,                deltaTime = deltaTime,                gpuEcsAnimationDataBufferLookup = gpuEcsAnimationDataBufferLookup,                localTransformLookup = localTransformLookup            }.ScheduleParallel(state.Dependency);        }        [BurstCompile]        private partial struct CrowdSpawnerJob : IJobEntity        {            public EntityCommandBuffer.ParallelWriter ecb;            [ReadOnly] public float deltaTime;            [ReadOnly] public BufferLookup<GpuEcsAnimationDataBufferElement> gpuEcsAnimationDataBufferLookup;            [ReadOnly] public ComponentLookup<LocalTransform> localTransformLookup;                        public void Execute(                ref CrowdSpawnerUpdateComponent crowdSpawnerUpdate,                in CrowdSpawnerComponent crowdSpawner,                in DynamicBuffer<CrowdSpawnerAnimatorBufferElement> crowdSpawnerAnimators,                in DynamicBuffer<CrowdSpawnerAnimatorPrefabBufferElement> crowdSpawnerAnimatorPrefabs,                Entity crowdSpawnerEntity, [ChunkIndexInQuery] int sortKey)            {                if (crowdSpawner.rows != crowdSpawnerUpdate.rows || crowdSpawner.cols != crowdSpawnerUpdate.cols)                {                    crowdSpawnerUpdate.updateTime -= deltaTime;                    if (crowdSpawnerUpdate.updateTime <= 0)                    {                        // First delete all existing entities                        foreach (CrowdSpawnerAnimatorBufferElement crowdSpawnerAnimator in crowdSpawnerAnimators)                            ecb.DestroyEntity(sortKey, crowdSpawnerAnimator.gpuEcsAnimator);                        DynamicBuffer<CrowdSpawnerAnimatorBufferElement> newCrowdSpawnerAnimators                            = ecb.SetBuffer<CrowdSpawnerAnimatorBufferElement>(sortKey, crowdSpawnerEntity);                        newCrowdSpawnerAnimators.Clear();                        // Calculate the base offset so that the square of entities is centered around the origin                        float3 baseOffset = new float3(                            -(crowdSpawnerUpdate.cols - 1) * crowdSpawner.spacing / 2f,                            0f,                            -(crowdSpawnerUpdate.rows - 1) * crowdSpawner.spacing / 2f);                        for (int col = 0; col < crowdSpawnerUpdate.cols; col++)                        {                            for (int row = 0; row < crowdSpawnerUpdate.rows; row++)                            {                                newCrowdSpawnerAnimators.Add(new CrowdSpawnerAnimatorBufferElement()                                {                                    gpuEcsAnimator = CreateNewAnimator(ref crowdSpawnerUpdate, crowdSpawner, sortKey,                                        baseOffset, col, row, crowdSpawnerAnimatorPrefabs)                                });                            }                        }                        ecb.SetComponent<CrowdSpawnerComponent>(sortKey, crowdSpawnerEntity, new CrowdSpawnerComponent()                        {                            cols = crowdSpawnerUpdate.cols,                            rows = crowdSpawnerUpdate.rows,                            spacing = crowdSpawner.spacing                        });                    }                }            }            private Entity CreateNewAnimator(ref CrowdSpawnerUpdateComponent crowdSpawnerUpdate, CrowdSpawnerComponent crowdSpawner,                int sortKey, float3 baseOffset, int col, int row,                in DynamicBuffer<CrowdSpawnerAnimatorPrefabBufferElement> crowdSpawnerAnimatorPrefabs)            {                // Select a random prefab from the available buffer                Entity gpuEcsAnimatorPrefab = crowdSpawnerAnimatorPrefabs[                    crowdSpawnerUpdate.random.NextInt(0, crowdSpawnerAnimatorPrefabs.Length)].gpuEcsAnimatorPrefab;                // Spawn a character                Entity gpuEcsAnimator = ecb.Instantiate(sortKey, gpuEcsAnimatorPrefab);                                // set the position according to column, row & spacing values                // Preserve the scale that was set in the prefab                ecb.SetComponent(sortKey, gpuEcsAnimator, new LocalTransform()                {                    Position = baseOffset + new float3(                        col * crowdSpawner.spacing + crowdSpawnerUpdate.random.NextFloat(-crowdSpawner.spacing / 4f, crowdSpawner.spacing / 4f)                        , 0,                        row * crowdSpawner.spacing + crowdSpawnerUpdate.random.NextFloat(-crowdSpawner.spacing / 4f, crowdSpawner.spacing / 4f)                    ),                    Rotation = quaternion.Euler(0, crowdSpawnerUpdate.random.NextFloat(-math.PI, math.PI), 0),                    Scale = localTransformLookup[gpuEcsAnimatorPrefab].Scale                });                                // Pick a random animation ID from the available animations                DynamicBuffer<GpuEcsAnimationDataBufferElement> animationDataBuffer = gpuEcsAnimationDataBufferLookup[gpuEcsAnimatorPrefab];                int animationID = crowdSpawnerUpdate.random.NextInt(0, animationDataBuffer.Length);                                // Kick off the correct animation with a random time offset so to avoid synchronized animations                ecb.SetComponent(sortKey, gpuEcsAnimator, new GpuEcsAnimatorControlComponent()                {                    animatorInfo = new AnimatorInfo()                    {                        animationID = animationID,                        blendFactor = 0,                        speedFactor = 1f                    },                    startNormalizedTime = crowdSpawnerUpdate.random.NextFloat(0f, 1f),                    transitionSpeed = 0                });                return gpuEcsAnimator;            }        }    }}
 |