Advertisement
Rengaw

FlowCollisionSystem

Apr 21st, 2018
196
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 8.31 KB | None | 0 0
  1. using Unity.Collections;
  2. using Unity.Entities;
  3. using Unity.Jobs;
  4. using Unity.Mathematics;
  5. using Unity.Transforms;
  6. using Unity.Transforms2D;
  7.  
  8. internal sealed class FlowCollisionSystem : JobComponentSystem
  9. {
  10.     private const int
  11.         WallWeight     = 1,
  12.         TilesPerUnit   = 8,
  13.         WallThickness  = 50,
  14.         BoundsUnitSize = 30,
  15.  
  16.         BoundsTileSize = BoundsUnitSize * TilesPerUnit;
  17.    
  18.     private const float
  19.         Speed            = 0.1f,
  20.         GravityScale     = 0f,
  21.         ParticleUnitSize = 1f,
  22.  
  23.         HalfParticleUnitSize = ParticleUnitSize * 0.5f,
  24.         HalfParticleTileSize = HalfParticleUnitSize * TilesPerUnit;
  25.    
  26.     [Inject]
  27.     private ParticleGroup       particleGroup;
  28.     private NativeArray<int>    integerField;
  29.     private NativeArray<float2> vectorField;
  30.  
  31.     protected override JobHandle OnUpdate(JobHandle inputDeps)
  32.     {
  33.         const int TileCount = BoundsTileSize * BoundsTileSize;
  34.  
  35.         this.TryDisposeNativeArrays();
  36.  
  37.         this.integerField = new NativeArray<int>(
  38.             TileCount,
  39.             Allocator.TempJob,
  40.             NativeArrayOptions.ClearMemory);
  41.         this.BuildWalls();
  42.         var integerJob = new BuildIntegerFieldJob()
  43.         {
  44.             IntegerField = this.integerField,
  45.             Positions    = this.particleGroup.Positions,
  46.         }.Schedule(this.particleGroup.Length, 1, inputDeps);
  47.  
  48.         this.vectorField = new NativeArray<float2>(
  49.             TileCount,
  50.             Allocator.TempJob,
  51.             NativeArrayOptions.UninitializedMemory);
  52.         var vectorJob    = new BuildVectorFieldJob()
  53.         {
  54.             IntegerField = this.integerField,
  55.             VectorField  = this.vectorField,
  56.         }.Schedule(TileCount, 64, integerJob);
  57.  
  58.         var navigateJob = new NavigateJob()
  59.         {
  60.             Headings    =  this.particleGroup.Headings,
  61.             Positions   = this.particleGroup.Positions,
  62.             Speeds      = this.particleGroup.Speeds,
  63.             VectorField = this.vectorField,
  64.         }.Schedule(this.particleGroup.Length, 1, vectorJob);
  65.  
  66.         return navigateJob;
  67.     }
  68.  
  69.     protected override void OnDestroyManager()
  70.     {
  71.         this.TryDisposeNativeArrays();
  72.     }
  73.  
  74.     private void BuildWalls()
  75.     {
  76.         for (int x = 0; x < BoundsTileSize; x++)
  77.         {
  78.             for (int i = 0; i < WallThickness; i++)
  79.             {
  80.                 int leftIndex  = x + (i * BoundsTileSize);
  81.                 int rightIndex = x + ((BoundsTileSize - (1 + i)) * BoundsTileSize);
  82.  
  83.                 this.integerField[leftIndex]  = (WallThickness - i) * WallWeight;
  84.                 this.integerField[rightIndex] = (WallThickness - i) * WallWeight;
  85.             }
  86.         }
  87.  
  88.         for (int y = 1; y < BoundsTileSize - 1; y++)
  89.         {
  90.             for (int i = 0; i < WallThickness; i++)
  91.             {
  92.                 int bottomIndex = i + (y * BoundsTileSize);
  93.                 int topIndex    = (BoundsTileSize - (1 + i)) + (y * BoundsTileSize);
  94.  
  95.                 this.integerField[bottomIndex] = (WallThickness - i) * WallWeight;
  96.                 this.integerField[topIndex]    = (WallThickness - i) * WallWeight;
  97.             }
  98.         }
  99.     }
  100.  
  101.     private void TryDisposeNativeArrays()
  102.     {
  103.         if (this.integerField.IsCreated)
  104.         {
  105.             this.integerField.Dispose();
  106.         }
  107.  
  108.         if (this.vectorField.IsCreated)
  109.         {
  110.             this.vectorField.Dispose();
  111.         }
  112.     }
  113.  
  114.     [ComputeJobOptimization]
  115.     private struct BuildIntegerFieldJob : IJobParallelFor
  116.     {
  117.         [NativeDisableParallelForRestriction]
  118.         public NativeArray<int>                          IntegerField;
  119.         [ReadOnly] public ComponentDataArray<Position2D> Positions;
  120.        
  121.         public void Execute(int particleIndex)
  122.         {
  123.             this.IncrementOccupiedTiles(particleIndex);
  124.         }
  125.        
  126.         private void IncrementOccupiedTiles(int index)
  127.         {
  128.             var position = this.Positions[index];
  129.             var offsetPosition = position.Value + (BoundsUnitSize * 0.5f);
  130.             int
  131.                 minX = (int)((offsetPosition.x - HalfParticleUnitSize) * TilesPerUnit),
  132.                 maxX = (int)((offsetPosition.x + HalfParticleUnitSize) * TilesPerUnit),
  133.                 minY = (int)((offsetPosition.y - HalfParticleUnitSize) * TilesPerUnit),
  134.                 maxY = (int)((offsetPosition.y + HalfParticleUnitSize) * TilesPerUnit);
  135.  
  136.             for (int y = minY; y < maxY; y++)
  137.             {
  138.                 for (int x = minX; x < maxX; x++)
  139.                 {
  140.                     this.IntegerField[x + (y * BoundsTileSize)] += 1;
  141.                 }
  142.             }
  143.         }
  144.     }
  145.  
  146.     [ComputeJobOptimization]
  147.     private struct BuildVectorFieldJob : IJobParallelFor
  148.     {
  149.         [NativeDisableParallelForRestriction]
  150.         [ReadOnly] public NativeArray<int> IntegerField;
  151.  
  152.         [NativeDisableParallelForRestriction]
  153.         public NativeArray<float2> VectorField;
  154.  
  155.         public void Execute(int index)
  156.         {
  157.             this.VectorField[index] = this.CalculateVector(index);
  158.         }
  159.  
  160.         private float2 CalculateVector(int index)
  161.         {
  162.             float2 vector = 0;
  163.  
  164.             int tileX = index % BoundsTileSize;
  165.             int startX = tileX > 0 ? tileX - 1 : tileX;
  166.             int endX = tileX < (BoundsTileSize - 1) ? tileX + 1 : tileX;
  167.  
  168.             int tileY = index / BoundsTileSize;
  169.             int startY = tileY > 0 ? tileY - 1 : tileY;
  170.             int endY = tileY < (BoundsTileSize - 1) ? tileY + 1 : tileY;
  171.  
  172.             for (int y = startY, vy = 1; y <= endY; y++, vy--)
  173.             {
  174.                 for (int x = startX, vx = 1; x <= endX; x++, vx--)
  175.                 {
  176.                     int loopIndex = x + (y * BoundsTileSize);
  177.                     if (loopIndex == index)
  178.                     {
  179.                         continue;
  180.                     }
  181.  
  182.                     var direction = math.normalize(new float2(vx, vy));
  183.                     vector += direction * this.IntegerField[loopIndex];
  184.                 }
  185.             }
  186.  
  187.             return vector;
  188.         }
  189.     }
  190.  
  191.     [ComputeJobOptimization]
  192.     private struct NavigateJob : IJobParallelFor
  193.     {
  194.         [NativeDisableParallelForRestriction]
  195.         [ReadOnly] public NativeArray<float2>            VectorField;
  196.         [ReadOnly] public ComponentDataArray<Position2D> Positions;
  197.         public ComponentDataArray<Heading2D>             Headings;
  198.         public ComponentDataArray<MoveSpeed>             Speeds;
  199.        
  200.         public void Execute(int particleIndex)
  201.         {
  202.             float2 vector = this.CalculateVector(particleIndex);
  203.  
  204.             ApplySpeedMultiplier(ref vector);
  205.             ApplyGravity(ref vector);
  206.  
  207.             this.Headings[particleIndex] = new Heading2D() { Value = math.normalize(vector) };
  208.             this.Speeds[particleIndex] = new MoveSpeed() { speed = math.length(vector) };
  209.         }
  210.  
  211.         private float2 CalculateVector(int index)
  212.         {
  213.             float2 vector = 0;
  214.             var position = this.Positions[index];
  215.             var offsetPosition = position.Value + (BoundsUnitSize * 0.5f);
  216.             int
  217.                 minX = (int)((offsetPosition.x - HalfParticleUnitSize) * TilesPerUnit),
  218.                 maxX = (int)((offsetPosition.x + HalfParticleUnitSize) * TilesPerUnit),
  219.                 minY = (int)((offsetPosition.y - HalfParticleUnitSize) * TilesPerUnit),
  220.                 maxY = (int)((offsetPosition.y + HalfParticleUnitSize) * TilesPerUnit);
  221.  
  222.             for (int y = minY; y <= maxY; y++)
  223.             {
  224.                 for (int x = minX; x <= maxX; x++)
  225.                 {
  226.                     vector += this.VectorField[x + (y * BoundsTileSize)];
  227.                 }
  228.             }
  229.  
  230.             return vector;
  231.         }
  232.  
  233.         private static void ApplySpeedMultiplier(ref float2 vector)
  234.         {
  235.             vector *= Speed;
  236.         }
  237.  
  238.         private static void ApplyGravity(ref float2 vector)
  239.         {
  240.             vector += new float2(0f, -9.82f) * GravityScale;
  241.         }
  242.     }
  243.  
  244.     private struct ParticleGroup
  245.     {
  246.         public ComponentDataArray<Heading2D>  Headings;
  247.         public ComponentDataArray<Position2D> Positions;
  248.         public ComponentDataArray<MoveSpeed>  Speeds;
  249.         public int Length;
  250.     }
  251. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement