| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 | using System;using GPUECSAnimationBaker.Engine.AnimatorSystem;using Unity.Burst;using Unity.Collections;using Unity.Entities;using Unity.Mathematics;using Unity.Transforms;namespace GPUECSAnimationBaker.Samples.SampleScenes.Marathon.RunnerSystems{    [BurstCompile]    public partial struct RunnerSpawnerSystem : ISystem    {        private ComponentLookup<LocalTransform> localTransformLookup;                [BurstCompile]        public void OnCreate(ref SystemState state)        {            localTransformLookup = state.GetComponentLookup<LocalTransform>(isReadOnly: true);        }        [BurstCompile]        public void OnUpdate(ref SystemState 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 RunnerSpawnerJob()            {                ecb = ecb,                deltaTime = deltaTime,                localTransformLookup = localTransformLookup            }.ScheduleParallel(state.Dependency);        }        [BurstCompile]        private partial struct RunnerSpawnerJob : IJobEntity        {            public EntityCommandBuffer.ParallelWriter ecb;            [ReadOnly] public float deltaTime;            [ReadOnly] public ComponentLookup<LocalTransform> localTransformLookup;                        public void Execute(                ref RunnerSpawnerUpdateComponent runnerSpawnerUpdate,                in RunnerSpawnerComponent runnerSpawner,                 in DynamicBuffer<RunnerSpawnerAnimatorBufferElement> runnerSpawnerAnimators,                in DynamicBuffer<RunnerSpawnerAnimatorPrefabBufferElement> runnerSpawnerAnimatorPrefabs,                Entity runnerSpawnerEntity, [ChunkIndexInQuery] int sortKey)            {                double TOLERANCE = 0.01f;                if (runnerSpawner.nbrOfRunners != runnerSpawnerUpdate.nbrOfRunners                    || Math.Abs(runnerSpawner.fieldSizeX - runnerSpawnerUpdate.fieldSizeX) > TOLERANCE                    || Math.Abs(runnerSpawner.fieldSizeZ - runnerSpawnerUpdate.fieldSizeZ) > TOLERANCE)                {                    runnerSpawnerUpdate.updateTime -= deltaTime;                    if (runnerSpawnerUpdate.updateTime <= 0)                    {                        // First Delete all existing entities                        foreach (RunnerSpawnerAnimatorBufferElement runnerSpawnerAnimator in runnerSpawnerAnimators)                        {                            ecb.DestroyEntity(sortKey, runnerSpawnerAnimator.gpuEcsAnimator);                        }                        DynamicBuffer<RunnerSpawnerAnimatorBufferElement> newCrowdSpawnerAnimators                            = ecb.SetBuffer<RunnerSpawnerAnimatorBufferElement>(sortKey, runnerSpawnerEntity);                        newCrowdSpawnerAnimators.Clear();                        for (int i = 0; i < runnerSpawnerUpdate.nbrOfRunners; i++)                        {                            newCrowdSpawnerAnimators.Add(new RunnerSpawnerAnimatorBufferElement()                            {                                gpuEcsAnimator = CreateNewAnimator(ref runnerSpawnerUpdate, runnerSpawner, sortKey, runnerSpawnerAnimatorPrefabs)                            });                        }                        ecb.SetComponent<RunnerSpawnerComponent>(sortKey, runnerSpawnerEntity, new RunnerSpawnerComponent()                        {                            fieldSizeZ = runnerSpawnerUpdate.fieldSizeZ,                            fieldSizeX = runnerSpawnerUpdate.fieldSizeX,                            nbrOfRunners = runnerSpawnerUpdate.nbrOfRunners,                            speedWalking = runnerSpawner.speedWalking,                            speedRunning = runnerSpawner.speedRunning,                            speedSprinting = runnerSpawner.speedSprinting,                            minSpeed = runnerSpawner.minSpeed,                            maxSpeed = runnerSpawner.maxSpeed                        });                    }                }            }            private Entity CreateNewAnimator(ref RunnerSpawnerUpdateComponent runnerSpawnerUpdate, RunnerSpawnerComponent runnerSpawner,                int sortKey, in DynamicBuffer<RunnerSpawnerAnimatorPrefabBufferElement> runnerSpawnerAnimatorPrefabs)            {                // Select a random runner prefab from the available buffer                Entity gpuEcsAnimatorPrefab = runnerSpawnerAnimatorPrefabs[                    runnerSpawnerUpdate.random.NextInt(0, runnerSpawnerAnimatorPrefabs.Length)].gpuEcsAnimatorPrefab;                                 // Spawn a new runner                Entity gpuEcsAnimator = ecb.Instantiate(sortKey, gpuEcsAnimatorPrefab);                // Place it randomly in the running field                ecb.SetComponent(sortKey, gpuEcsAnimator, new LocalTransform()                {                    Position = new float3(                        runnerSpawnerUpdate.random.NextFloat(-runnerSpawnerUpdate.fieldSizeX / 2f, +runnerSpawnerUpdate.fieldSizeX / 2f),                        0,                        runnerSpawnerUpdate.random.NextFloat(-runnerSpawnerUpdate.fieldSizeZ / 2f, +runnerSpawnerUpdate.fieldSizeZ / 2f)),                    Rotation = quaternion.identity,                    Scale = localTransformLookup[gpuEcsAnimatorPrefab].Scale                });                // Select a random speed for the new runner between minimum & maximum speed                float speed = runnerSpawnerUpdate.random.NextFloat(runnerSpawner.minSpeed, runnerSpawner.maxSpeed);                 ecb.SetComponent(sortKey, gpuEcsAnimator, new RunnerStateComponent()                {                    speed = speed,                    fieldSizeZ = runnerSpawnerUpdate.fieldSizeZ                });                                // Calculate blendFactor, speedFactor & select animation                float blendFactor;                AnimationIdsRunnerMarathon animationID;                float speedFactor;                if (speed < runnerSpawner.speedWalking)                {                    animationID = AnimationIdsRunnerMarathon.WalkToRun;                    blendFactor = 0;                    speedFactor = speed / runnerSpawner.speedWalking;                }                else if (speed < runnerSpawner.speedRunning)                {                    animationID = AnimationIdsRunnerMarathon.WalkToRun;                    blendFactor = (speed - runnerSpawner.speedWalking)                                   / (runnerSpawner.speedRunning - runnerSpawner.speedWalking);                    speedFactor = 1f;                }                else if(speed < runnerSpawner.speedSprinting)                {                    animationID = AnimationIdsRunnerMarathon.RunToSprint;                    blendFactor = (speed - runnerSpawner.speedRunning)                                   / (runnerSpawner.speedSprinting - runnerSpawner.speedWalking);                    speedFactor = 1f;                }                else                {                    animationID = AnimationIdsRunnerMarathon.RunToSprint;                    blendFactor = 1f;                    speedFactor = speed / runnerSpawner.speedSprinting;                }                                // 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 = (int) animationID,                        blendFactor = blendFactor,                        speedFactor = speedFactor                    },                    startNormalizedTime = runnerSpawnerUpdate.random.NextFloat(0f, 1f),                    transitionSpeed = 0                });                return gpuEcsAnimator;            }        }    }}
 |