RunnerSpawnerSystem.cs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. using System;
  2. using GPUECSAnimationBaker.Engine.AnimatorSystem;
  3. using Unity.Burst;
  4. using Unity.Collections;
  5. using Unity.Entities;
  6. using Unity.Mathematics;
  7. using Unity.Transforms;
  8. namespace GPUECSAnimationBaker.Samples.SampleScenes.Marathon.RunnerSystems
  9. {
  10. [BurstCompile]
  11. public partial struct RunnerSpawnerSystem : ISystem
  12. {
  13. private ComponentLookup<LocalTransform> localTransformLookup;
  14. [BurstCompile]
  15. public void OnCreate(ref SystemState state)
  16. {
  17. localTransformLookup = state.GetComponentLookup<LocalTransform>(isReadOnly: true);
  18. }
  19. [BurstCompile]
  20. public void OnUpdate(ref SystemState state)
  21. {
  22. localTransformLookup.Update(ref state);
  23. EndSimulationEntityCommandBufferSystem.Singleton ecbSystem =
  24. SystemAPI.GetSingleton<EndSimulationEntityCommandBufferSystem.Singleton>();
  25. EntityCommandBuffer.ParallelWriter ecb = ecbSystem.CreateCommandBuffer(state.WorldUnmanaged).AsParallelWriter();
  26. float deltaTime = SystemAPI.Time.DeltaTime;
  27. state.Dependency = new RunnerSpawnerJob()
  28. {
  29. ecb = ecb,
  30. deltaTime = deltaTime,
  31. localTransformLookup = localTransformLookup
  32. }.ScheduleParallel(state.Dependency);
  33. }
  34. [BurstCompile]
  35. private partial struct RunnerSpawnerJob : IJobEntity
  36. {
  37. public EntityCommandBuffer.ParallelWriter ecb;
  38. [ReadOnly] public float deltaTime;
  39. [ReadOnly] public ComponentLookup<LocalTransform> localTransformLookup;
  40. public void Execute(
  41. ref RunnerSpawnerUpdateComponent runnerSpawnerUpdate,
  42. in RunnerSpawnerComponent runnerSpawner,
  43. in DynamicBuffer<RunnerSpawnerAnimatorBufferElement> runnerSpawnerAnimators,
  44. in DynamicBuffer<RunnerSpawnerAnimatorPrefabBufferElement> runnerSpawnerAnimatorPrefabs,
  45. Entity runnerSpawnerEntity, [ChunkIndexInQuery] int sortKey)
  46. {
  47. double TOLERANCE = 0.01f;
  48. if (runnerSpawner.nbrOfRunners != runnerSpawnerUpdate.nbrOfRunners
  49. || Math.Abs(runnerSpawner.fieldSizeX - runnerSpawnerUpdate.fieldSizeX) > TOLERANCE
  50. || Math.Abs(runnerSpawner.fieldSizeZ - runnerSpawnerUpdate.fieldSizeZ) > TOLERANCE)
  51. {
  52. runnerSpawnerUpdate.updateTime -= deltaTime;
  53. if (runnerSpawnerUpdate.updateTime <= 0)
  54. {
  55. // First Delete all existing entities
  56. foreach (RunnerSpawnerAnimatorBufferElement runnerSpawnerAnimator in runnerSpawnerAnimators)
  57. {
  58. ecb.DestroyEntity(sortKey, runnerSpawnerAnimator.gpuEcsAnimator);
  59. }
  60. DynamicBuffer<RunnerSpawnerAnimatorBufferElement> newCrowdSpawnerAnimators
  61. = ecb.SetBuffer<RunnerSpawnerAnimatorBufferElement>(sortKey, runnerSpawnerEntity);
  62. newCrowdSpawnerAnimators.Clear();
  63. for (int i = 0; i < runnerSpawnerUpdate.nbrOfRunners; i++)
  64. {
  65. newCrowdSpawnerAnimators.Add(new RunnerSpawnerAnimatorBufferElement()
  66. {
  67. gpuEcsAnimator = CreateNewAnimator(ref runnerSpawnerUpdate, runnerSpawner, sortKey, runnerSpawnerAnimatorPrefabs)
  68. });
  69. }
  70. ecb.SetComponent<RunnerSpawnerComponent>(sortKey, runnerSpawnerEntity, new RunnerSpawnerComponent()
  71. {
  72. fieldSizeZ = runnerSpawnerUpdate.fieldSizeZ,
  73. fieldSizeX = runnerSpawnerUpdate.fieldSizeX,
  74. nbrOfRunners = runnerSpawnerUpdate.nbrOfRunners,
  75. speedWalking = runnerSpawner.speedWalking,
  76. speedRunning = runnerSpawner.speedRunning,
  77. speedSprinting = runnerSpawner.speedSprinting,
  78. minSpeed = runnerSpawner.minSpeed,
  79. maxSpeed = runnerSpawner.maxSpeed
  80. });
  81. }
  82. }
  83. }
  84. private Entity CreateNewAnimator(ref RunnerSpawnerUpdateComponent runnerSpawnerUpdate, RunnerSpawnerComponent runnerSpawner,
  85. int sortKey, in DynamicBuffer<RunnerSpawnerAnimatorPrefabBufferElement> runnerSpawnerAnimatorPrefabs)
  86. {
  87. // Select a random runner prefab from the available buffer
  88. Entity gpuEcsAnimatorPrefab = runnerSpawnerAnimatorPrefabs[
  89. runnerSpawnerUpdate.random.NextInt(0, runnerSpawnerAnimatorPrefabs.Length)].gpuEcsAnimatorPrefab;
  90. // Spawn a new runner
  91. Entity gpuEcsAnimator = ecb.Instantiate(sortKey, gpuEcsAnimatorPrefab);
  92. // Place it randomly in the running field
  93. ecb.SetComponent(sortKey, gpuEcsAnimator, new LocalTransform()
  94. {
  95. Position = new float3(
  96. runnerSpawnerUpdate.random.NextFloat(-runnerSpawnerUpdate.fieldSizeX / 2f, +runnerSpawnerUpdate.fieldSizeX / 2f),
  97. 0,
  98. runnerSpawnerUpdate.random.NextFloat(-runnerSpawnerUpdate.fieldSizeZ / 2f, +runnerSpawnerUpdate.fieldSizeZ / 2f)),
  99. Rotation = quaternion.identity,
  100. Scale = localTransformLookup[gpuEcsAnimatorPrefab].Scale
  101. });
  102. // Select a random speed for the new runner between minimum & maximum speed
  103. float speed = runnerSpawnerUpdate.random.NextFloat(runnerSpawner.minSpeed, runnerSpawner.maxSpeed);
  104. ecb.SetComponent(sortKey, gpuEcsAnimator, new RunnerStateComponent()
  105. {
  106. speed = speed,
  107. fieldSizeZ = runnerSpawnerUpdate.fieldSizeZ
  108. });
  109. // Calculate blendFactor, speedFactor & select animation
  110. float blendFactor;
  111. AnimationIdsRunnerMarathon animationID;
  112. float speedFactor;
  113. if (speed < runnerSpawner.speedWalking)
  114. {
  115. animationID = AnimationIdsRunnerMarathon.WalkToRun;
  116. blendFactor = 0;
  117. speedFactor = speed / runnerSpawner.speedWalking;
  118. }
  119. else if (speed < runnerSpawner.speedRunning)
  120. {
  121. animationID = AnimationIdsRunnerMarathon.WalkToRun;
  122. blendFactor = (speed - runnerSpawner.speedWalking)
  123. / (runnerSpawner.speedRunning - runnerSpawner.speedWalking);
  124. speedFactor = 1f;
  125. }
  126. else if(speed < runnerSpawner.speedSprinting)
  127. {
  128. animationID = AnimationIdsRunnerMarathon.RunToSprint;
  129. blendFactor = (speed - runnerSpawner.speedRunning)
  130. / (runnerSpawner.speedSprinting - runnerSpawner.speedWalking);
  131. speedFactor = 1f;
  132. }
  133. else
  134. {
  135. animationID = AnimationIdsRunnerMarathon.RunToSprint;
  136. blendFactor = 1f;
  137. speedFactor = speed / runnerSpawner.speedSprinting;
  138. }
  139. // Kick off the correct animation with a random time offset so to avoid synchronized animations
  140. ecb.SetComponent(sortKey, gpuEcsAnimator, new GpuEcsAnimatorControlComponent()
  141. {
  142. animatorInfo = new AnimatorInfo()
  143. {
  144. animationID = (int) animationID,
  145. blendFactor = blendFactor,
  146. speedFactor = speedFactor
  147. },
  148. startNormalizedTime = runnerSpawnerUpdate.random.NextFloat(0f, 1f),
  149. transitionSpeed = 0
  150. });
  151. return gpuEcsAnimator;
  152. }
  153. }
  154. }
  155. }