Search Unity

StepPhysicsWorld Taking Over 100 ms

Discussion in 'Physics for ECS' started by EternalAmbiguity, Jan 26, 2021.

  1. EternalAmbiguity

    EternalAmbiguity

    Joined:
    Dec 27, 2014
    Posts:
    3,144
    See image below - the StepPhysicsWorld execution seems to take over 100 ms.
    Unity_2021-01-26_17-22-52.png
    I'm clearly doing something wrong. See the second image below:
    Unity_2021-01-26_17-24-32.png
    I have ~2400 of the entity shown in the Inspector in the second image. The map's meshes are entities with colliders, and the player is a moving entity. There's nothing else active in the scene.

    The ComponentSystem of the entity shown is below:

    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using Unity.Jobs;
    6. using UnityEngine.Jobs;
    7. using Unity.Entities;
    8. using Unity.Transforms;
    9. using System.Linq;
    10. using Unity.Mathematics;
    11. using Unity.Physics;
    12. using Unity.Physics.Systems;
    13.  
    14. using Unity.Collections;
    15. using Unity.Rendering;
    16. using System.Threading.Tasks;
    17. using Unity.Burst;
    18.  
    19. //[UpdateBefore(typeof(PlayerMovementSystem))]
    20. public class EnemySystem : SystemBase
    21. {
    22.     EntityManager em = World.DefaultGameObjectInjectionWorld.EntityManager;
    23.     NativeList<UniqueEnemy> allEnemies;
    24.  
    25.     protected override void OnCreate()
    26.     {
    27.         base.OnCreate();
    28.         allEnemies = new NativeList<UniqueEnemy>(Allocator.TempJob);
    29.     }
    30.     //private ComponentGroup group;
    31.  
    32.     //// Here we define the group
    33.     //protected void OnCreateManager()
    34.     //{
    35.     //    // Get all entities with both Position and RigidBody
    36.     //    group = GetComponentGroup(
    37.     //        typeof(PlayerInput)
    38.     //    );
    39.     //}
    40.  
    41.     protected override void OnUpdate()
    42.     {
    43.         var delta = Time.DeltaTime;
    44.         var player = em.CreateEntityQuery(typeof(PlayerEntity)).GetSingletonEntity();
    45.         var playerPosition = new Tuple(StaticClass.playerCell.Item1, StaticClass.playerCell.Item2);
    46.         var mapCorners = StaticClass.mapCorners;
    47.         var x0 = mapCorners[0].x;
    48.         var x1 = mapCorners[2].x;
    49.         var y0 = mapCorners[0].y;
    50.         var y1 = mapCorners[2].y;
    51.         var grid = StaticClass.GetFlatWalkableGrid();
    52.         var positions = StaticClass.GetFlatPositionGrid();
    53.         var positionGrid0 = new NativeArray<float3>(positions, Allocator.TempJob);
    54.         var positionGrid = positionGrid0.AsReadOnly();
    55.         var gridHeight = StaticClass.interactiveGrids[StaticClass.currentLevel].GetLength(1);
    56.         var cellWalkable0 = new NativeArray<CellWalkableState>(grid, Allocator.TempJob);
    57.         var cellWalkable = cellWalkable0.AsReadOnly();
    58.         var enemyType = StaticClass.enemyType;
    59.         var weaponCreation = new NativeQueue<WeaponCreationStruct>(Allocator.TempJob);
    60.         var parallel = weaponCreation.AsParallelWriter();
    61.         List<(int, int)> antisepticList = new List<(int, int)>();
    62.         List<(int, int)> poisonList = new List<(int, int)>();
    63.         if (StaticClass.ca != null)
    64.         {
    65.             antisepticList = StaticClass.ca.ActiveCells.Where(x => x.Atmosphere == CellAtmosphere.Antiseptic).Select(y => (y.X, y.Y)).ToList();
    66.             antisepticList = antisepticList.Distinct().ToList();
    67.             poisonList = StaticClass.ca.ActiveCells.Where(x => x.Atmosphere == CellAtmosphere.Poison).Select(y => (y.X, y.Y)).ToList();
    68.             poisonList = poisonList.Distinct().ToList();
    69.         }
    70.         var antisepticA = new NativeArray<int>(antisepticList.Select(x => x.Item1).ToArray(), Allocator.TempJob);
    71.         var antisepticReaderA = antisepticA.AsReadOnly();
    72.         var antisepticB = new NativeArray<int>(antisepticList.Select(x => x.Item2).ToArray(), Allocator.TempJob);
    73.         var antisepticReaderB = antisepticB.AsReadOnly();
    74.         int antisepticLength = antisepticA.Length;
    75.         var poisonA = new NativeArray<int>(poisonList.Select(x => x.Item1).ToArray(), Allocator.TempJob);
    76.         var poisonReaderA = poisonA.AsReadOnly();
    77.         var poisonB = new NativeArray<int>(poisonList.Select(x => x.Item2).ToArray(), Allocator.TempJob);
    78.         var poisonReaderB = poisonB.AsReadOnly();
    79.         int poisonLength = poisonA.Length;
    80.         var damaged = new NativeQueue<Entity>(Allocator.TempJob);
    81.         var damagedWriter = damaged.AsParallelWriter();
    82.         var tracker = new NativeQueue<Tracker>(Allocator.TempJob);
    83.         var trackerParallel = tracker.AsParallelWriter();
    84.         var patrol = new NativeQueue<Tracker>(Allocator.TempJob);
    85.         var patrolParallel = patrol.AsParallelWriter();
    86.         var melee = new NativeQueue<float>(Allocator.TempJob);
    87.         var meleeParallel = melee.AsParallelWriter();
    88.         var currentEntities = new NativeQueue<UniqueEnemy>(Allocator.TempJob);
    89.         var currentEntityWriter = currentEntities.AsParallelWriter();
    90.         var traps = new NativeQueue<TrapStruct>(Allocator.TempJob);
    91.         var trapWriter = traps.AsParallelWriter();
    92.         var currentAllEnemies = allEnemies.AsArray().AsReadOnly();
    93.         int enemyLength = allEnemies.Length;
    94.         var meleeSpeed = StaticClass.meleeSpeed;
    95.         var actionThreshold = StaticClass.shootThreshold;
    96.         Entities
    97.             .WithName("EnemySystem")
    98.             .WithBurst(Unity.Burst.FloatMode.Default, Unity.Burst.FloatPrecision.Standard, true)
    99.             .ForEach((Entity entity, int nativeThreadIndex, ref Translation translation, ref Rotation rotation, ref EnemyEntity enemy, in LocalToWorld localToWorld) =>
    100.             {
    101.                 currentEntityWriter.Enqueue(new UniqueEnemy { id = entity.Index, version = entity.Version, enemy = enemy, position = translation.Value});
    102.                 if(enemy.state >= 0 && enemy.state < 6)
    103.                 {
    104.                     for (int i = 0; i < antisepticLength; i++)
    105.                     {
    106.                         if(enemy.X.Equals(antisepticReaderA[i]) && enemy.Y.Equals(antisepticReaderB[i]))
    107.                         {
    108.                             damagedWriter.Enqueue(entity);
    109.                         }
    110.                     }
    111.                 }
    112.                 else if (enemy.state >= 6)
    113.                 {
    114.                     for (int i = 0; i < poisonLength; i++)
    115.                     {
    116.                         if (enemy.X.Equals(poisonReaderA[i]) && enemy.Y.Equals(poisonReaderB[i]))
    117.                         {
    118.                             damagedWriter.Enqueue(entity);
    119.                         }
    120.                     }
    121.                 }
    122.                 if (enemy.state >= 2)
    123.                 {
    124.                     WeaponType type = (enemy.state < 6) ? WeaponType.MainBio : WeaponType.MainEn;
    125.                     if (enemy.oldPosition.Equals(enemy.newPosition) == false)
    126.                     {
    127.                         enemy.lerp += (delta * enemy.speed);
    128.                         // move
    129.                         float3 newPosition = Vector3.Lerp(enemy.oldPosition, enemy.newPosition, enemy.lerp);
    130.                         translation.Value = newPosition;
    131.                         if (enemy.lerp > 1)
    132.                         {
    133.                             enemy.lerp = 0;
    134.                             enemy.oldPosition = enemy.newPosition;
    135.                         }
    136.                     }
    137.                     if (enemy.state == 2) // spinner
    138.                     {
    139.                         rotation.Value = math.mul(rotation.Value, quaternion.AxisAngle(Vector3.up, 1 * delta));
    140.                         if (enemy.actionValue > actionThreshold)
    141.                         {
    142.                             var front = translation.Value + (localToWorld.Forward * 1.5f);
    143.                             var frontDir = Quaternion.LookRotation(localToWorld.Forward, localToWorld.Up);
    144.                             var right = translation.Value + (localToWorld.Right * 1.5f);
    145.                             var rightDir = Quaternion.LookRotation(localToWorld.Right, localToWorld.Up);
    146.                             var back = translation.Value - (localToWorld.Forward * 1.5f);
    147.                             var backDir = Quaternion.LookRotation(-localToWorld.Forward, localToWorld.Up);
    148.                             var left = translation.Value - (localToWorld.Right * 1.5f);
    149.                             var leftDir = Quaternion.LookRotation(-localToWorld.Right, localToWorld.Up);
    150.                             CreateWeapon(front, frontDir, localToWorld.Forward * 55, type, x0, y0, x1, y1, parallel);
    151.                             CreateWeapon(back, backDir, -localToWorld.Forward * 55, type, x0, y0, x1, y1, parallel);
    152.                             CreateWeapon(left, leftDir, -localToWorld.Right * 55, type, x0, y0, x1, y1, parallel);
    153.                             CreateWeapon(right, rightDir, localToWorld.Right * 55, type, x0, y0, x1, y1, parallel);
    154.                             enemy.actionValue = 0;
    155.                         }
    156.                     }
    157.                     else if (enemy.state == 3) // aimer // attack random
    158.                     {
    159.                         var view = GetInView(entity, enemy, currentAllEnemies, enemyLength, playerPosition, cellWalkable, gridHeight);
    160.                         // if in range and if in view
    161.                         if (view.Distance > 0)
    162.                         {
    163.                             var pos = positionGrid[(view.X * gridHeight) + view.Y];
    164.                             var targetPoint = pos - translation.Value;
    165.                             var rotationSet = quaternion.LookRotation(targetPoint, localToWorld.Up);
    166.                             if (view.Distance < 20)
    167.                             {
    168.                                 rotation.Value = rotationSet;
    169.                                 if (enemy.actionValue > actionThreshold)
    170.                                 {
    171.                                     quaternion direction;
    172.                                     if(view.index == -1)
    173.                                     {
    174.                                         direction = Quaternion.LookRotation(localToWorld.Forward, localToWorld.Up);
    175.                                     }
    176.                                     else
    177.                                     {
    178.                                         var asa = currentAllEnemies[view.index].position - translation.Value;
    179.                                         direction = quaternion.Euler(asa);
    180.                                     }
    181.                                     CreateWeapon(translation.Value + (localToWorld.Forward * 1.5f), direction, localToWorld.Forward * 55, type, x0, y0, x1, y1, parallel);
    182.                                     enemy.actionValue = 0;
    183.                                 }
    184.                             }
    185.                             else
    186.                             {
    187.                                 trackerParallel.Enqueue(new Tracker() { X = enemy.X, Y = enemy.Y, X2 = view.X, Y2 = view.Y });
    188.                             }
    189.                         }
    190.                         else
    191.                         {
    192.                             trackerParallel.Enqueue(new Tracker() { X = enemy.X, Y = enemy.Y, X2 = -1, Y2 = -1 });
    193.                         }
    194.                     }
    195.                     else if (enemy.state == 5) // melee
    196.                     {
    197.                         var view = GetInView(entity, enemy, currentAllEnemies, enemyLength, playerPosition, cellWalkable, gridHeight);
    198.                         //Debug.Log("getting inview");
    199.                         if (view.Distance > 0)
    200.                         {
    201.                             var pos = positionGrid[(view.X * gridHeight) + view.Y];
    202.                             var targetPoint = pos - translation.Value;
    203.                             var rotationSet = quaternion.LookRotation(targetPoint, localToWorld.Up);
    204.                             rotation.Value = rotationSet;
    205.                             if (view.Distance < 2)
    206.                             {
    207.                                 // animation hitting and health drop
    208.                                 if (enemy.actionValue > enemy.actionThreshold)
    209.                                 {
    210.                                     meleeParallel.Enqueue(25);
    211.                                     enemy.actionValue = 0;
    212.                                 }
    213.                             }
    214.                             else
    215.                             {
    216.                                 enemy.speed = meleeSpeed;
    217.                                 trackerParallel.Enqueue(new Tracker() { X = enemy.X, Y = enemy.Y, X2 = view.X, Y2 = view.Y });
    218.                             }
    219.                         }
    220.                         else
    221.                         {
    222.                             enemy.speed = 3;
    223.                         }
    224.                     }
    225.                     else if (enemy.state == 6) // aimer or turret // attack things first - primarily defense
    226.                     {
    227.                         var view = GetInView(entity, enemy, currentAllEnemies, enemyLength, playerPosition, cellWalkable, gridHeight);
    228.                         // if in range and if in view
    229.                         if (view.Distance > 0)
    230.                         {
    231.                             var pos = positionGrid[(view.X * gridHeight) + view.Y];
    232.                             var targetPoint = pos - translation.Value;
    233.                             var rotationSet = quaternion.LookRotation(targetPoint, localToWorld.Up);
    234.                             if (view.Distance < 30)
    235.                             {
    236.                                 rotation.Value = rotationSet;
    237.                                 if (enemy.actionValue > actionThreshold)
    238.                                 {
    239.                                     quaternion direction;
    240.                                     if (view.index == -1)
    241.                                     {
    242.                                         direction = Quaternion.LookRotation(localToWorld.Forward, localToWorld.Up);
    243.                                     }
    244.                                     else
    245.                                     {
    246.                                         var asa = currentAllEnemies[view.index].position - translation.Value;
    247.                                         direction = quaternion.Euler(asa);
    248.                                     }
    249.                                     CreateWeapon(translation.Value + (localToWorld.Forward * 1.5f), direction, localToWorld.Forward * 75, WeaponType.MainEn, x0, y0, x1, y1, parallel);
    250.                                     enemy.actionValue = 0;
    251.                                 }
    252.                             }
    253.                         }
    254.                     }
    255.                     else if (enemy.state == 7)// attack things first - primarily defense
    256.                     {
    257.                         var view = GetInView(entity, enemy, currentAllEnemies, enemyLength, playerPosition, cellWalkable, gridHeight);
    258.  
    259.                         if (view.Distance > 0)
    260.                         {
    261.                             var pos = positionGrid[(view.X * gridHeight) + view.Y];
    262.                             var targetPoint = pos - translation.Value;
    263.                             var rotationSet = quaternion.LookRotation(targetPoint, localToWorld.Up);
    264.                             if (view.Distance < 200)
    265.                             {
    266.                                 rotation.Value = rotationSet;
    267.                                 // speak/make noise
    268.                                 if (view.Distance < 100)
    269.                                 {
    270.                                     if (enemy.actionValue > actionThreshold)
    271.                                     {
    272.                                         quaternion direction;
    273.                                         if (view.index == -1)
    274.                                         {
    275.                                             direction = Quaternion.LookRotation(localToWorld.Forward, localToWorld.Up);
    276.                                         }
    277.                                         else
    278.                                         {
    279.                                             var asa = currentAllEnemies[view.index].position - translation.Value;
    280.                                             direction = quaternion.Euler(asa);
    281.                                         }
    282.                                         CreateWeapon(translation.Value + (localToWorld.Forward * 1.5f), direction, localToWorld.Forward * 55, WeaponType.MainEn, x0, y0, x1, y1, parallel);
    283.                                         enemy.actionValue = 0;
    284.                                     }
    285.                                 }
    286.                                 trackerParallel.Enqueue(new Tracker() { X = enemy.X, Y = enemy.Y, X2 = view.X, Y2 = view.Y });
    287.                             }
    288.                         }
    289.                         else
    290.                         {
    291.                             patrolParallel.Enqueue(new Tracker() { X = enemy.X, Y = enemy.Y });
    292.                         }
    293.                     }
    294.                     enemy.actionValue += 1 * delta;
    295.                 }
    296.             })
    297.             .ScheduleParallel();
    298.         Dependency.Complete();
    299.         var enemies = currentEntities.ToArray(Allocator.TempJob);
    300.         allEnemies.Clear();
    301.         allEnemies.AddRange(enemies);
    302.         enemies.Dispose();
    303.         if (weaponCreation.Count > 0)
    304.         {
    305.             int count = weaponCreation.Count;
    306.             for (int i = 0; i < count; i++)
    307.             {
    308.                 var current = weaponCreation.Dequeue();
    309.                 Entity create = (current.weaponEntity.type == WeaponType.MainBio) ? StaticClass.entityWeaponBio : StaticClass.entityWeaponEn;
    310.                 var instance = EntityManager.Instantiate(create);
    311.                 EntityManager.SetComponentData(instance, new Translation { Value = current.position });
    312.                 EntityManager.SetComponentData(instance, new Rotation { Value = current.rotation });
    313.                 EntityManager.SetComponentData(instance, new Unity.Physics.PhysicsVelocity() { Linear = current.velocity });
    314.                 EntityManager.SetComponentData(instance, current.weaponEntity);
    315.                 StaticClass.playAudioShoot(current.position);
    316.             }
    317.         }
    318.         for (int i = 0; i < tracker.Count; i++)
    319.         {
    320.             var cur = tracker.Dequeue();
    321.             StaticClass.SetTracker(cur.X, cur.Y, cur.X2, cur.Y2);
    322.         }
    323.         for (int i = 0; i < patrol.Count; i++)
    324.         {
    325.             var cur = patrol.Dequeue();
    326.             StaticClass.SetPatrol(cur.X, cur.Y);
    327.         }
    328.         for (int i = 0; i < melee.Count; i++)
    329.         {
    330.             var cur = melee.Dequeue();
    331.             StaticClass.DamagePlayer(WeaponType.Melee);
    332.         }
    333.         for (int i = 0; i < damaged.Count; i++)
    334.         {
    335.             StaticClass.DamageEnemy(damaged.Dequeue(), WeaponType.Atmosphere);
    336.         }
    337.         for (int i = 0; i < traps.Count; i++)
    338.         {
    339.             var cur = traps.Dequeue();
    340.             var loc = StaticClass.CoordinatesFromWorldSpace(cur.position);
    341.             cur.enemy.X = loc.Item1;
    342.             cur.enemy.Y = loc.Item2;
    343.             em.SetComponentData(cur.entity, cur.enemy);
    344.         }
    345.         currentEntities.Dispose();
    346.         melee.Dispose();
    347.         tracker.Dispose();
    348.         patrol.Dispose();
    349.         weaponCreation.Dispose();
    350.         cellWalkable0.Dispose();
    351.         positionGrid0.Dispose();
    352.         damaged.Dispose();
    353.         antisepticA.Dispose();
    354.         antisepticB.Dispose();
    355.         poisonA.Dispose();
    356.         poisonB.Dispose();
    357.         traps.Dispose();
    358.     }
    359.  
    360.     struct TrapStruct
    361.     {
    362.         public Entity entity;
    363.         public EnemyEntity enemy;
    364.         public float3 position;
    365.     }
    366.    
    367.     struct Truple
    368.     {
    369.         public int X;
    370.         public int Y;
    371.         public float Distance;
    372.         public int index;
    373.         public Truple(int x, int y, float distance, int index)
    374.         {
    375.             this.X = x;
    376.             this.Y = y;
    377.             this.Distance = distance;
    378.             this.index = index;
    379.         }
    380.     }
    381.  
    382.     static Truple GetInView(Entity entity, EnemyEntity self, NativeArray<UniqueEnemy>.ReadOnly enemies, int enemyLength, Tuple playerPosition, NativeArray<CellWalkableState>.ReadOnly grid, int gridHeight)
    383.     {
    384.         NativeArray<int> currentEnemies;
    385.         if(self.state < 6) // blob
    386.         {
    387.             currentEnemies = new NativeArray<int>(3, Allocator.Temp);
    388.             currentEnemies[0] = 6;
    389.             currentEnemies[1] = 7;
    390.             currentEnemies[2] = -1;
    391.         }
    392.         else if(self.state < 8) // 8 will be
    393.         {
    394.             currentEnemies = new NativeArray<int>(7, Allocator.Temp);
    395.             currentEnemies[0] = -1;
    396.             currentEnemies[1] = 0;
    397.             currentEnemies[2] = 1;
    398.             currentEnemies[3] = 2;
    399.             currentEnemies[4] = 3;
    400.             currentEnemies[5] = 4;
    401.             currentEnemies[6] = 5;
    402.         }
    403.         else
    404.         {
    405.             currentEnemies = new NativeArray<int>(9, Allocator.Temp);
    406.             currentEnemies[0] = 0;
    407.             currentEnemies[1] = 1;
    408.             currentEnemies[2] = 2;
    409.             currentEnemies[3] = 3;
    410.             currentEnemies[4] = 4;
    411.             currentEnemies[5] = 5;
    412.             currentEnemies[6] = 6;
    413.             currentEnemies[7] = 7;
    414.             currentEnemies[8] = -1;
    415.         }
    416.  
    417.         for (int i = 0; i < enemyLength; i++)
    418.         {
    419.             var cur = enemies[i];
    420.             if(entity.Index.Equals(cur.id) && entity.Version.Equals(cur.version))
    421.             {
    422.                 continue;
    423.             }
    424.             else
    425.             {
    426.                 if(currentEnemies.Contains(cur.enemy.state))
    427.                 {
    428.                     if(InView(self.X, self.Y, cur.enemy.X, cur.enemy.Y, grid, gridHeight))
    429.                     {
    430.                         currentEnemies.Dispose();
    431.                         var distance = math.sqrt(((self.X - cur.enemy.X) * (self.X - cur.enemy.X)) + ((self.Y - cur.enemy.Y) * (self.Y - cur.enemy.Y)));
    432.                         return new Truple(cur.enemy.X, cur.enemy.Y, distance, i);
    433.                     }
    434.                 }
    435.             }
    436.         }
    437.         if (InView(self.X, self.Y, playerPosition.X, playerPosition.Y, grid, gridHeight))
    438.         {
    439.             currentEnemies.Dispose();
    440.             float distance = math.sqrt(((self.X - playerPosition.X) * (self.X - playerPosition.X)) + ((self.Y - playerPosition.Y) * (self.Y - playerPosition.Y)));
    441.             return new Truple(playerPosition.X, playerPosition.Y, distance, -1);
    442.         }
    443.         currentEnemies.Dispose();
    444.         return new Truple(-1, -1, -1, -1);
    445.     }
    446.  
    447.     struct Tuple
    448.     {
    449.         public int X;
    450.         public int Y;
    451.         public Tuple(int x, int y)
    452.         {
    453.             this.X = x;
    454.             this.Y = y;
    455.         }
    456.     }
    457.  
    458.     struct UniqueEnemy
    459.     {
    460.         public int id;
    461.         public int version;
    462.         public EnemyEntity enemy;
    463.         public float3 position;
    464.     }
    465.  
    466.     protected override void OnDestroy()
    467.     {
    468.         base.OnDestroy();
    469.         allEnemies.Dispose();
    470.     }
    471.  
    472.     static void CreateWeapon(float3 position, quaternion direction, float3 velocity, WeaponType type, float x0, float y0, float x1, float y1, NativeQueue<WeaponCreationStruct>.ParallelWriter parallel)
    473.     {
    474.         parallel.Enqueue(new WeaponCreationStruct()
    475.         {
    476.             velocity = velocity /** velocity*/,
    477.             weaponEntity = new WeaponEntity(type, x0, x1, y0, y1),
    478.             position = position, // any lower and it collides with the player when the player moves
    479.             rotation = direction,
    480.         });
    481.     }
    482.  
    483.     static bool InView(int x1, int y1, int x2, int y2, NativeArray<CellWalkableState>.ReadOnly grid, int gridHeight)
    484.     {
    485.         //Debug.Log("height: " + gridHeight);
    486.         NativeList<int> xs = new NativeList<int>(Allocator.Temp);
    487.         NativeList<int> ys = new NativeList<int>(Allocator.Temp);
    488.         //List<(int, int)> onLine = new List<(int, int)>();
    489.         int i;               // loop counter
    490.         int ystep, xstep;    // the step on y and x axis
    491.         int error;           // the error accumulated during the increment
    492.         int errorprev;       // *vision the previous value of the error variable
    493.         int y = y1, x = x1;  // the line points
    494.         int ddy, ddx;        // compulsory variables: the double values of dy and dx
    495.         int dx = x2 - x1;
    496.         int dy = y2 - y1;
    497.         xs.Add(x1);
    498.         ys.Add(y1);
    499.         // NB the last point can't be here, because of its previous point (which has to be verified)
    500.         if (dy < 0)
    501.         {
    502.             ystep = -1;
    503.             dy = -dy;
    504.         }
    505.         else
    506.         {
    507.             ystep = 1;
    508.         }
    509.         if (dx < 0)
    510.         {
    511.             xstep = -1;
    512.             dx = -dx;
    513.         }
    514.         else
    515.         {
    516.             xstep = 1;
    517.         }
    518.         ddy = 2 * dy;  // work with double values for full precision
    519.         ddx = 2 * dx;
    520.         if (ddx >= ddy)
    521.         {  // first octant (0 <= slope <= 1)
    522.            // compulsory initialization (even for errorprev, needed when dx==dy)
    523.             errorprev = error = dx;  // start in the middle of the square
    524.             for (i = 0; i < dx; i++)
    525.             {  // do not use the first point (already done)
    526.                 x += xstep;
    527.                 error += ddy;
    528.                 if (error > ddx)
    529.                 {  // increment y if AFTER the middle ( > )
    530.                     y += ystep;
    531.                     error -= ddx;
    532.                     // three cases (octant == right->right-top for directions below):
    533.                     if (error + errorprev < ddx)  // bottom square also
    534.                     {
    535.                         xs.Add(x);
    536.                         ys.Add(y - ystep);
    537.                     }
    538.                     else if (error + errorprev > ddx)  // left square also
    539.                     {
    540.                         xs.Add(x - xstep);
    541.                         ys.Add(y);
    542.                     }
    543.                     else
    544.                     {  // corner: bottom and left squares also
    545.                         xs.Add(x);
    546.                         ys.Add(y - ystep);
    547.                         xs.Add(x - xstep);
    548.                         ys.Add(y);
    549.                     }
    550.                 }
    551.                 xs.Add(x);
    552.                 ys.Add(y);
    553.                 errorprev = error;
    554.             }
    555.         }
    556.         else
    557.         {  // the same as above
    558.             errorprev = error = dy;
    559.             for (i = 0; i < dy; i++)
    560.             {
    561.                 y += ystep;
    562.                 error += ddx;
    563.                 if (error > ddy)
    564.                 {
    565.                     x += xstep;
    566.                     error -= ddy;
    567.                     if (error + errorprev < ddy)
    568.                     {
    569.                         xs.Add(x - xstep);
    570.                         ys.Add(y);
    571.                     }
    572.                     else if (error + errorprev > ddy)
    573.                     {
    574.                         xs.Add(x);
    575.                         ys.Add(y - ystep);
    576.                     }
    577.                     else
    578.                     {
    579.                         xs.Add(x - xstep);
    580.                         ys.Add(y);
    581.                         xs.Add(x);
    582.                         ys.Add(y - ystep);
    583.                     }
    584.                 }
    585.                 xs.Add(x);
    586.                 ys.Add(y);
    587.                 errorprev = error;
    588.             }
    589.         }
    590.         for (int iii = 0; iii < xs.Length; iii++)
    591.         {
    592.             //Debug.Log("next: " + xs[iii] + ", " + ys[iii]);
    593.             var pos = (xs[iii] * gridHeight) + ys[iii];
    594.             if (grid[pos] == CellWalkableState.Unwalkable || grid[pos] == CellWalkableState.InteractableObject)
    595.             {
    596.                 return false;
    597.             }
    598.         }
    599.         return true;
    600.     }
    601.  
    602.     struct WeaponCreationStruct
    603.     {
    604.         public WeaponEntity weaponEntity;
    605.         public float3 position;
    606.         public float3 velocity;
    607.         public quaternion rotation;
    608.     }
    609.  
    610.     struct Tracker
    611.     {
    612.         public int X;
    613.         public int Y;
    614.         public int X2;
    615.         public int Y2;
    616.     }
    617. }
    618.  
    What could be causing this performance? What does StepPhysicsWorld involve?
     
  2. EternalAmbiguity

    EternalAmbiguity

    Joined:
    Dec 27, 2014
    Posts:
    3,144
    Unity_2021-01-26_18-13-17.png
    I was able to use Deep Profile...but it's just as confusing. What is a "JacobianJob"? How do I optimize this?
     
  3. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    481
    StepPhysicsWorld is performing all the physics Collision Detection and Resolution.
    Do you have a the JobsDebugger enabled (see 'Jobs > JobsDebugger' menu item)? This can kill performance.
    Do you have a dynamic or kinematic body that has a Physics Shape with a Mesh Collider? If so, this will create a crazy number of contacts to resolve and you should make any Mesh Collider static.
     
  4. EternalAmbiguity

    EternalAmbiguity

    Joined:
    Dec 27, 2014
    Posts:
    3,144
    Hmm. Not really sure if that fixed anything, but I switched to "Raw Hierarchy" in the profiler and saw something weird.
    Unity_2021-01-27_10-24-03.png
    Looks like now regular physics are taking up a lot of time, but in particular - there are multiple calls of each type (Fixedupdate, StepPhysicsWorld). Is that supposed to happen?

    Edit: And the timeline seems to show the same thing - physics is updating twice, in sequence.
    Unity_2021-01-27_10-29-24.png
     
  5. EternalAmbiguity

    EternalAmbiguity

    Joined:
    Dec 27, 2014
    Posts:
    3,144
    I realized I'd left an asset (archimatix) enabled that was using Update...I disabled that, and performance is better, but still poor. Another timeline image:
    Unity_2021-01-27_15-29-11.png
    As can be seen from the popup, that's StepPhysicsSystem repeating 10+ times during the same frame. Is that normal?
     
  6. milos85miki

    milos85miki

    Joined:
    Nov 29, 2019
    Posts:
    197
    Looks like physics was taking too much time in previous steps (longer than fixed timestep) and is now trying to make it up (see Cort's explanation here). What are the fixed timestep and max allowed timestep values in your project settings -> time and what's the first frame when physics step lasted longer than that?
     
  7. EternalAmbiguity

    EternalAmbiguity

    Joined:
    Dec 27, 2014
    Posts:
    3,144
    Fixed is 0.02, max allowed is 0.333. Don't recall changing them at all, so I assume they're defaults (if I want to target 60 FPS, should the former be 0.016?). Ran again, and this time starting out it was just spikes...
    Unity_2021-01-27_23-57-26.png Unity_2021-01-27_23-58-20.png Unity_2021-01-27_23-58-47.png Unity_2021-01-27_23-59-06.png

    Here it looks like it was the EditorLoop that caused the initial delay, but it looks like my EnemySystem has GC issues...

    Related to that, earlier I actually tried to modify it to pull some of those variable assignments outside of the update loop, but had issues doing so. The problem is that some of those things are updated periodically so they'd need to be reassigned within the system. I suppose I could add a bool array to my static class to tell the system to update, but is there any other way to access the system? Such that for instance when I change my cellWalkableState grid, I can call a function in EnemySystem to update that variable outside of the OnUpdate function?

    Edit: Okay, for now I just added a bool to my static class, and my performance is back where it needs to be, so crisis averted. However I'd still like to know how to update class (or whatever a SystemBase is) -global variables after start, but not in update.
     
    Last edited: Jan 28, 2021
  8. milos85miki

    milos85miki

    Joined:
    Nov 29, 2019
    Posts:
    197
    From pure programming perspective - would it make sense to create a static method in your EnemySystem and call it for the stuff you need to do outside of update loop (you can also use the static method in OnUpdate, of course)?

    Not discussing whether it makes sense to do those frequent updates, you're best suited to make that call since you know the project.
     
  9. EternalAmbiguity

    EternalAmbiguity

    Joined:
    Dec 27, 2014
    Posts:
    3,144
    Okay, I was able to do what you suggested, as well as simply add a static bool to the EnemySystem, which allows me to trigger an update to the "class-global" variable in OnUpdate only when needed. Both solutions work, so I consider this resolved.

    Thanks for the help.
     
    milos85miki likes this.