Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Voting for the Unity Awards are OPEN! We’re looking to celebrate creators across games, industry, film, and many more categories. Cast your vote now for all categories
    Dismiss Notice
  3. Dismiss Notice

Update Interval

Discussion in 'Entity Component System' started by Spy-Shifty, Mar 26, 2018.

  1. Spy-Shifty

    Spy-Shifty

    Joined:
    May 5, 2011
    Posts:
    546
    Hi,

    first of all, the Unity-Team did a really really really great job on the ECS!!!
    The ECS is even better than I could imangine.
    So please go ahead!
    :):):)


    Now to my question...

    Does ComponentSystem.OnUpdate run on the same intervall as Monobehaviour.Update?
    I imagine, yes.

    Scenario:
    I've a hybrit system (2d game on XY). Just an animated character with Capsule Collider 2d and Rigidbody2d attached to it.
    ECS handles: the input, animator props, rootmotion, position sync in both ways...

    Problem:

    I use Cinemachine to track the player. Player position gets updated throught the ComponentSystem. Camera position is set through the brain, by the VCam which tracks the player in frame transposer mode.

    All modes on the brain (SmartUpdate, FixedUpdate, LateUpdate) result in flickering on character motion... (even without physic)

    Normaly I would solve this by just using FixedUpdate method on both, camera and character positioning.

    Any solution?
    Would it help, if I would convert Cinamachine behaviours to ECS?
    But this could also cause flickering when some physical collisions occur.
     
    Mikael-H and ArturMGS like this.
  2. Spy-Shifty

    Spy-Shifty

    Joined:
    May 5, 2011
    Posts:
    546
    Ah ok, I found a possible solution for my problem in this thead.
    I knew there is an UpdateBefor and UpdateAfter.
    What I didn't knew is, that I can even use FixedUpdate in form of typeof(UnityEngine.Experimental.PlayerLoop.FixedUpdate)

    https://gist.github.com/timj-unity/f1d514e4bbfe12599f6220401f71eb0f

    But will this force my system to get updated on each FixedUpdate?
     
    ArturMGS likes this.
  3. Spy-Shifty

    Spy-Shifty

    Joined:
    May 5, 2011
    Posts:
    546
    I love my monolog threads :D

    But I solved it ;)

    Ok I think they have it's own Update cycles depending on the UpdateBefore, UpdateAfter,...

    So to archive systems to run in the FixedUpdate loop use the UpdateBefore attribute with UnityEngine.Experimental.PlayerLoop.FixedUpdate

    Code (CSharp):
    1. [UpdateBefore(typeof(UnityEngine.Experimental.PlayerLoop.FixedUpdate))]
    2. public class SyncTransformSystem : ComponentSystem {
    3.    
    4.     public struct Data {
    5.         [ReadOnly] public Position2D Position;
    6.         [ReadOnly] public Heading Heading;
    7.         public Transform Transform;
    8.     }
    9.  
    10.     protected override void OnUpdate() {
    11.         foreach (var entity in GetEntities<Data>()) {
    12.  
    13.             float2 p = entity.Position.Value;
    14.             int h = entity.Heading.Value;
    15.  
    16.             entity.Transform.position = new float3(p.x, p.y, 0);
    17.             entity.Transform.rotation = Quaternion.Euler(0, 90 * h - 90, 0);
    18.         }
    19.     }
    20. }
     
  4. Spy-Shifty

    Spy-Shifty

    Joined:
    May 5, 2011
    Posts:
    546
    Short question to the Dev team:

    I want to sync Rigidbody.velocity with a velocity component in ecs.

    Therefore I want to be able to run a sync system befor FixedUpdate (rigid to ecs) and one between FixedUpdate and the internal Physic update routine (ecs to rigid).

    Can I just use [UpdateAfter(typeof(UnityEngine.Experimental.PlayerLoop.FixedUpdate))]?

    Thanks in advance
     
  5. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Yes thats the idea. Btw in Entity Debugger you can now show the whole player loop. Thus you can see exactly what effect the [UpdateAfter] actually had after all the systems have been injected into the player loop with all the other engine code.

    its in the drop down where it says "Default world"
     
    ArturMGS, Antypodish and Spy-Shifty like this.
  6. Spy-Shifty

    Spy-Shifty

    Joined:
    May 5, 2011
    Posts:
    546
    Thank you for the fast reply! That made my day!
     
  7. Spy-Shifty

    Spy-Shifty

    Joined:
    May 5, 2011
    Posts:
    546
    Maybe it's a bug:

    I have the following constellation:

    Code (CSharp):
    1. [UpdateBefore(typeof(SyncToPhysicBarrier))]
    2. [UpdateAfter(typeof(SyncFromPhysicBarrier))]
    3. public class PhysicUpdate { }
    4.  
    5. [UpdateAfter(typeof(UnityEngine.Experimental.PlayerLoop.FixedUpdate))]
    6. public class SyncToPhysicBarrier : BarrierSystem {
    7.      // I removed the sealed keyword on BarrierSystem.OnUpdate to be abe to override it
    8.     protected override void OnUpdate() {
    9.         base.OnUpdate();
    10.         Debug.Log("SyncToPhysicBarrier");
    11.     }
    12. }
    13.  
    14. [UpdateBefore(typeof(UnityEngine.Experimental.PlayerLoop.FixedUpdate))]
    15. public class SyncFromPhysicBarrier : BarrierSystem {
    16.     protected override void OnUpdate() {
    17.         base.OnUpdate();
    18.         Debug.Log("SyncFromPhysicBarrier");
    19.     }
    20. }
    21.  

    Code (CSharp):
    1. [UpdateAfter(typeof(SyncFromPhysicBarrier))]
    2. public class SyncToRigidbodySystem : ComponentSystem {
    3.  
    4.  
    5.     struct MoveRotationData {
    6.         public readonly int Length;
    7.         [ReadOnly] public ComponentDataArray<MoveRotation> moveRotation;
    8.         public EntityArray entity;
    9.     }
    10.  
    11.     struct AddForceData {
    12.         public readonly int Length;
    13.         [ReadOnly] public ComponentDataArray<AddForce> addForce;
    14.         public EntityArray entity;
    15.     }
    16.  
    17.     struct AddRelativeTorqueData {
    18.         public readonly int Length;
    19.         [ReadOnly] public ComponentDataArray<AddRelativeTorque> addRelativeTorque;
    20.         public EntityArray entity;
    21.     }
    22.  
    23.     struct VelocityData {
    24.         public readonly int Length;
    25.         [ReadOnly] public ComponentDataArray<Velocity> velocity;
    26.         public ComponentArray<Rigidbody> rigidbody;
    27.     }
    28.  
    29.     struct AngularVelocityData {
    30.         public readonly int Length;
    31.         [ReadOnly] public ComponentDataArray<AngularVelocity> angularVelocity;
    32.         public ComponentArray<Rigidbody> rigidbody;
    33.     }
    34.  
    35.     [Inject] MoveRotationData moveRotationData;
    36.     [Inject] AddForceData addForceData;
    37.     [Inject] AddRelativeTorqueData addRelativeTorqueData;
    38.     [Inject] VelocityData velocityData;
    39.     [Inject] AngularVelocityData angularVelocityData;
    40.  
    41.     protected override void OnUpdate() {
    42.  
    43.         for (int i = 0; i < moveRotationData.Length; i++) {
    44.             MoveRotation moveRotation = moveRotationData.moveRotation[i];
    45.             Rigidbody rigidbody = EntityManager.GetComponentObject<Rigidbody>(moveRotation.receiver);
    46.             rigidbody.MoveRotation(moveRotation.rotation);
    47.             PostUpdateCommands.DestroyEntity(moveRotationData.entity[i]);
    48.         }
    49.  
    50.         for (int i = 0; i < addForceData.Length; i++) {
    51.             AddForce force = addForceData.addForce[i];
    52.             Rigidbody rigidbody = EntityManager.GetComponentObject<Rigidbody>(force.receiver);
    53.             rigidbody.AddForce(force.force, force.mode);
    54.             PostUpdateCommands.DestroyEntity(addForceData.entity[i]);
    55.         }
    56.  
    57.         for (int i = 0; i < addRelativeTorqueData.Length; i++) {
    58.             AddRelativeTorque torque = addRelativeTorqueData.addRelativeTorque[i];
    59.             Rigidbody rigidbody = EntityManager.GetComponentObject<Rigidbody>(torque.receiver);
    60.             rigidbody.AddRelativeTorque(torque.torque, torque.mode);
    61.             PostUpdateCommands.DestroyEntity(addRelativeTorqueData.entity[i]);
    62.         }
    63.  
    64.         for (int i = 0; i < velocityData.Length; i++) {
    65.             Velocity velocity = velocityData.velocity[i];
    66.             Rigidbody rigidbody = velocityData.rigidbody[i];
    67.             rigidbody.velocity = velocity.value;
    68.         }
    69.  
    70.         for (int i = 0; i < angularVelocityData.Length; i++) {
    71.             AngularVelocity velocity = angularVelocityData.angularVelocity[i];
    72.             Rigidbody rigidbody = angularVelocityData.rigidbody[i];
    73.             rigidbody.angularVelocity = velocity.value;
    74.         }
    75.         Debug.Log("SyncToRigidbodySystem");
    76.     }
    77. }
    Code (CSharp):
    1. [UpdateBefore(typeof(SyncToPhysicBarrier))]
    2. public class SyncFromRigidbodySystem : ComponentSystem {
    3.  
    4.     struct VelocityData {
    5.         public readonly int Length;
    6.         [WriteOnly] public ComponentDataArray<Velocity> velocity;
    7.         public ComponentArray<Rigidbody> rigidbody;
    8.     }
    9.     struct AngularVelocityData {
    10.         public readonly int Length;
    11.         [WriteOnly] public ComponentDataArray<AngularVelocity> angularVelocity;
    12.         public ComponentArray<Rigidbody> rigidbody;
    13.     }
    14.  
    15.  
    16.     [Inject] VelocityData velocityData;
    17.     [Inject] AngularVelocityData angularVelocityData;
    18.  
    19.     protected override void OnUpdate() {
    20.         for (int i = 0; i < velocityData.Length; i++) {
    21.             Rigidbody rigidbody = velocityData.rigidbody[i];
    22.             velocityData.velocity[i] = new Velocity { value = rigidbody.velocity };
    23.         }
    24.  
    25.         for (int i = 0; i < angularVelocityData.Length; i++) {
    26.             AngularVelocity velocity = angularVelocityData.angularVelocity[i];
    27.             Rigidbody rigidbody = angularVelocityData.rigidbody[i];
    28.             velocity.value = rigidbody.angularVelocity;
    29.         }
    30.     }
    31. }
    Code (CSharp):
    1. [UpdateInGroup(typeof(PhysicUpdate))]
    2. public class VehicleMovementSystem : JobComponentSystem {
    3.  
    4.     [BurstCompile]
    5.     struct CalculateSpeedJob : IJobParallelForTransform {
    6.  
    7.         [ReadOnly] public ComponentDataArray<Velocity> velocities;
    8.         [WriteOnly] public ComponentDataArray<RacerSpeed> speeds;
    9.  
    10.  
    11.         public void Execute(int i, TransformAccess transformAccess) {
    12.             float3 forward = transformAccess.rotation * new float3(0, 0, 1);
    13.             speeds[i] = new RacerSpeed { value = math.dot(velocities[i].value, forward) };
    14.         }
    15.     }
    16.  
    17.     //[BurstCompile]
    18.     struct CalculatePropulsion : IJobParallelForTransform {
    19.  
    20.         [ReadOnly] public ComponentDataArray<PlayerInput> playerInput;
    21.         [ReadOnly] public ComponentDataArray<GroundedInfo> groundInfo;
    22.         [ReadOnly] public ComponentDataArray<DriveSettings> driveSettings;
    23.         [ReadOnly] public ComponentDataArray<RacerSpeed> racerSpeed;
    24.         [ReadOnly] public EntityArray entities;
    25.  
    26.         public float deltaTime;
    27.         public EntityCommandBuffer.Concurrent commandBuffer;
    28.         public ComponentDataArray<Velocity> velocities;
    29.         public ComponentDataArray<AngularVelocity> angularVelocity;
    30.  
    31.  
    32.         public void Execute(int i, TransformAccess transformAccess) {
    33.             Velocity velocity = velocities[i];
    34.             PlayerInput input = playerInput[i];
    35.             DriveSettings driveSetting = driveSettings[i];
    36.             //Calculate the yaw torque based on the rudder and current angular velocity
    37.             float rotationTorque = driveSetting.turnVelocity * input.rudder - angularVelocity[i].value.y;
    38.  
    39.             //Apply the torque to the ship's Y axis
    40.             //commandBuffer.CreateEntity();
    41.             //commandBuffer.AddComponent(new AddRelativeTorque { torque = new float3(0, rotationTorque, 0), mode = ForceMode.VelocityChange, receiver = entities[i] });
    42.  
    43.             //Calculate the current sideways speed by using the dot product. This tells us
    44.             //how much of the ship's velocity is in the "right" or "left" direction
    45.             float3 right = transformAccess.rotation * new float3(1,0,0);
    46.             float sidewaysSpeed = math.dot(velocity.value, right);
    47.  
    48.             //Calculate the desired amount of friction to apply to the side of the vehicle. This
    49.             //is what keeps the ship from drifting into the walls during turns. If you want to add
    50.             //drifting to the game, divide Time.fixedDeltaTime by some amount
    51.             Vector3 sideFriction = -right * (sidewaysSpeed / deltaTime);
    52.  
    53.             //Finally, apply the sideways friction
    54.             commandBuffer.CreateEntity();
    55.             commandBuffer.AddComponent(new AddForce { force = sideFriction, mode = ForceMode.Acceleration, receiver = entities[i] });
    56.  
    57.             //If not propelling the ship, slow the ships velocity
    58.             if (input.thruster <= 0f)
    59.                 velocity.value *= driveSetting.slowingVelFactor;
    60.  
    61.             //Braking or driving requires being on the ground, so if the ship
    62.             //isn't on the ground, exit this method
    63.             if (!groundInfo[i].isOnGround)
    64.                 return;
    65.  
    66.             //If the ship is braking, apply the braking velocty reduction
    67.             if (input.isBraking)
    68.                 velocity.value *= driveSetting.brakingVelFactor;
    69.  
    70.             //Calculate and apply the amount of propulsion force by multiplying the drive force
    71.             //by the amount of applied thruster and subtracting the drag amount
    72.             float3 forward = transformAccess.rotation * new float3(0, 0, 1);
    73.  
    74.             float drag = driveSetting.driveForce / driveSetting.terminalVelocity;
    75.             float propulsion = driveSetting.driveForce * input.thruster - drag * Mathf.Clamp(racerSpeed[i].value, 0f, driveSetting.terminalVelocity);
    76.             commandBuffer.CreateEntity();
    77.             commandBuffer.AddComponent(new AddForce { force = forward * propulsion, mode = ForceMode.Acceleration, receiver = entities[i] });
    78.  
    79.             velocities[i] = velocity;
    80.         }
    81.     }
    82.  
    83.     struct VehicleData {
    84.         [ReadOnly] public ComponentDataArray<PlayerInput> playerInput;
    85.         [ReadOnly] public ComponentDataArray<GroundedInfo> groundInfo;
    86.         [ReadOnly] public ComponentDataArray<DriveSettings> driveSettings;
    87.         [WriteOnly] public ComponentDataArray<RacerSpeed> racerSpeed;
    88.         [ReadOnly] public EntityArray entities;
    89.         public ComponentDataArray<Velocity> velocities;
    90.         public ComponentDataArray<AngularVelocity> angularVelocity;
    91.         public TransformAccessArray transformAccessArray;
    92.     }
    93.  
    94.     [Inject] VehicleData vehicleData;
    95.     [Inject] SyncToPhysicBarrier physicBarrier;
    96.     protected override JobHandle OnUpdate(JobHandle inputDeps) {
    97.         var speedJob = new CalculateSpeedJob() {
    98.             speeds = vehicleData.racerSpeed,
    99.             velocities = vehicleData.velocities,
    100.         };
    101.         inputDeps =  speedJob.Schedule(vehicleData.transformAccessArray, inputDeps);
    102.         inputDeps.Complete(); // only for debugging
    103.  
    104.         var propulsionJob = new CalculatePropulsion() {
    105.             deltaTime = Time.fixedDeltaTime,
    106.             commandBuffer = physicBarrier.CreateCommandBuffer(),
    107.             angularVelocity = vehicleData.angularVelocity,
    108.             velocities = vehicleData.velocities,
    109.             driveSettings = vehicleData.driveSettings,
    110.             groundInfo = vehicleData.groundInfo,
    111.             playerInput = vehicleData.playerInput,
    112.             racerSpeed = vehicleData.racerSpeed,
    113.             entities = vehicleData.entities
    114.         };
    115.  
    116.         inputDeps = propulsionJob.Schedule(vehicleData.transformAccessArray, inputDeps);
    117.         inputDeps.Complete(); // only for debugging
    118.         Debug.Log("VehicleMovementSystem");
    119.         return inputDeps;
    120.     }
    121. }
    122.  


    Well the problem is the following:
    SyncToPhysicBarrier and SyncFromRigidbodySystem arn't in the FixedUpdate interval...
    upload_2018-8-26_10-9-41.png
     
    Antypodish likes this.
  8. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,624
    If you chuck a FixedUpdate attribute to SyncFromRigidbodySystem does it work?
     
  9. Spy-Shifty

    Spy-Shifty

    Joined:
    May 5, 2011
    Posts:
    546
    Ok it seems to be really buggy at all!

    So what I've tested yet: I've remove all Update before and after and in group tags from all my scripts.

    After that I only assigned the [UpdateBefore(FixedUpdate)] to the SyncToPhysicBarrier
    Code (CSharp):
    1. [UpdateBefore(typeof(UnityEngine.Experimental.PlayerLoop.FixedUpdate))]
    2. public class SyncToPhysicBarrier : BarrierSystem {
    3.  
    4.     protected override void OnUpdate() {
    5.         base.OnUpdate();
    6.         Debug.Log("SyncToPhysicBarrier");
    7.     }
    8. }
    9.  
    10. //[UpdateBefore(typeof(SyncToPhysicBarrier))]
    11. public class SyncFromPhysicBarrier : BarrierSystem {
    12.     protected override void OnUpdate() {
    13.         base.OnUpdate();
    14.         Debug.Log("SyncFromPhysicBarrier");
    15.     }
    16. }

    The behaviour is correct:
    upload_2018-8-26_10-53-12.png

    But ass soon as I add the [UpdateBefore(typeof(SyncToPhysicBarrier))] to the SyncFromPhysicBarrier
    It breaks!
    Code (CSharp):
    1. [UpdateBefore(typeof(UnityEngine.Experimental.PlayerLoop.FixedUpdate))]
    2. public class SyncToPhysicBarrier : BarrierSystem {
    3.  
    4.     protected override void OnUpdate() {
    5.         base.OnUpdate();
    6.         Debug.Log("SyncToPhysicBarrier");
    7.     }
    8. }
    9.  
    10. [UpdateBefore(typeof(SyncToPhysicBarrier))]
    11. public class SyncFromPhysicBarrier : BarrierSystem {
    12.     protected override void OnUpdate() {
    13.         base.OnUpdate();
    14.         Debug.Log("SyncFromPhysicBarrier");
    15.     }
    16. }

    upload_2018-8-26_10-55-23.png


    EDIT:

    But if I add also the [UpdateBefore(typeof(FixedUpdate))] to SyncFromPhysicBarrier
    it will work again!
    Code (CSharp):
    1. [UpdateBefore(typeof(UnityEngine.Experimental.PlayerLoop.FixedUpdate))]
    2. public class SyncToPhysicBarrier : BarrierSystem {
    3.  
    4.     protected override void OnUpdate() {
    5.         base.OnUpdate();
    6.         Debug.Log("SyncToPhysicBarrier");
    7.     }
    8. }
    9.  
    10. [UpdateBefore(typeof(UnityEngine.Experimental.PlayerLoop.FixedUpdate))]
    11. [UpdateBefore(typeof(SyncToPhysicBarrier))]
    12. public class SyncFromPhysicBarrier : BarrierSystem {
    13.     protected override void OnUpdate() {
    14.         base.OnUpdate();
    15.         Debug.Log("SyncFromPhysicBarrier");
    16.     }
    17. }
    18.  
    upload_2018-8-26_11-0-47.png
     
    Last edited: Aug 26, 2018
  10. Spy-Shifty

    Spy-Shifty

    Joined:
    May 5, 2011
    Posts:
    546
    So this seems to work!
    But it's more a workaround...

    Solution:
    So I added to the PhysicUpdate group, each of the barriers and each sync system the [UpdateBefore(FixedUpdate)] attribute

    Code (CSharp):
    1.  
    2. [UpdateBefore(typeof(UnityEngine.Experimental.PlayerLoop.FixedUpdate))]
    3. [UpdateBefore(typeof(SyncToPhysicBarrier))]
    4. [UpdateAfter(typeof(SyncFromPhysicBarrier))]
    5. public class PhysicUpdate { }
    6.  
    7. [UpdateBefore(typeof(UnityEngine.Experimental.PlayerLoop.FixedUpdate))]
    8. public class SyncToPhysicBarrier : BarrierSystem {
    9.      // I removed the sealed keyword on BarrierSystem.OnUpdate to be abe to override it
    10.     protected override void OnUpdate() {
    11.         base.OnUpdate();
    12.         Debug.Log("SyncToPhysicBarrier");
    13.     }
    14. }
    15.  
    16. [UpdateBefore(typeof(SyncToPhysicBarrier))]
    17. [UpdateBefore(typeof(UnityEngine.Experimental.PlayerLoop.FixedUpdate))]
    18. public class SyncFromPhysicBarrier : BarrierSystem {
    19.     protected override void OnUpdate() {
    20.         base.OnUpdate();
    21.         Debug.Log("SyncFromPhysicBarrier");
    22.     }
    23. }
    24.  

    Code (CSharp):
    1.  
    2.  
    3. [UpdateAfter(typeof(SyncToPhysicBarrier))]
    4. [UpdateBefore(typeof(UnityEngine.Experimental.PlayerLoop.FixedUpdate))]
    5. public class SyncToRigidbodySystem : ComponentSystem {
    6.  
    7.  
    8.     struct MoveRotationData {
    9.         public readonly int Length;
    10.         [ReadOnly] public ComponentDataArray<MoveRotation> moveRotation;
    11.         public EntityArray entity;
    12.     }
    13.  
    14.     struct AddForceData {
    15.         public readonly int Length;
    16.         [ReadOnly] public ComponentDataArray<AddForce> addForce;
    17.         public EntityArray entity;
    18.     }
    19.  
    20.     struct AddRelativeTorqueData {
    21.         public readonly int Length;
    22.         [ReadOnly] public ComponentDataArray<AddRelativeTorque> addRelativeTorque;
    23.         public EntityArray entity;
    24.     }
    25.  
    26.     struct VelocityData {
    27.         public readonly int Length;
    28.         [ReadOnly] public ComponentDataArray<Velocity> velocity;
    29.         public ComponentArray<Rigidbody> rigidbody;
    30.     }
    31.  
    32.     struct AngularVelocityData {
    33.         public readonly int Length;
    34.         [ReadOnly] public ComponentDataArray<AngularVelocity> angularVelocity;
    35.         public ComponentArray<Rigidbody> rigidbody;
    36.     }
    37.  
    38.     [Inject] MoveRotationData moveRotationData;
    39.     [Inject] AddForceData addForceData;
    40.     [Inject] AddRelativeTorqueData addRelativeTorqueData;
    41.     [Inject] VelocityData velocityData;
    42.     [Inject] AngularVelocityData angularVelocityData;
    43.  
    44.     protected override void OnUpdate() {
    45.  
    46.         for (int i = 0; i < moveRotationData.Length; i++) {
    47.             MoveRotation moveRotation = moveRotationData.moveRotation[i];
    48.             Rigidbody rigidbody = EntityManager.GetComponentObject<Rigidbody>(moveRotation.receiver);
    49.             rigidbody.MoveRotation(moveRotation.rotation);
    50.             PostUpdateCommands.DestroyEntity(moveRotationData.entity[i]);
    51.         }
    52.  
    53.         for (int i = 0; i < addForceData.Length; i++) {
    54.             AddForce force = addForceData.addForce[i];
    55.             Rigidbody rigidbody = EntityManager.GetComponentObject<Rigidbody>(force.receiver);
    56.             rigidbody.AddForce(force.force, force.mode);
    57.             PostUpdateCommands.DestroyEntity(addForceData.entity[i]);
    58.         }
    59.  
    60.         for (int i = 0; i < addRelativeTorqueData.Length; i++) {
    61.             AddRelativeTorque torque = addRelativeTorqueData.addRelativeTorque[i];
    62.             Rigidbody rigidbody = EntityManager.GetComponentObject<Rigidbody>(torque.receiver);
    63.             rigidbody.AddRelativeTorque(torque.torque, torque.mode);
    64.             PostUpdateCommands.DestroyEntity(addRelativeTorqueData.entity[i]);
    65.         }
    66.  
    67.         for (int i = 0; i < velocityData.Length; i++) {
    68.             Velocity velocity = velocityData.velocity[i];
    69.             Rigidbody rigidbody = velocityData.rigidbody[i];
    70.             rigidbody.velocity = velocity.value;
    71.         }
    72.  
    73.         for (int i = 0; i < angularVelocityData.Length; i++) {
    74.             AngularVelocity velocity = angularVelocityData.angularVelocity[i];
    75.             Rigidbody rigidbody = angularVelocityData.rigidbody[i];
    76.             rigidbody.angularVelocity = velocity.value;
    77.         }
    78.         Debug.Log("SyncToRigidbodySystem");
    79.     }
    80. }
    [UpdateBefore(typeof(SyncFromPhysicBarrier))]
    [UpdateBefore(typeof(UnityEngine.Experimental.PlayerLoop.FixedUpdate))]
    public class SyncFromRigidbodySystem : ComponentSystem {

    struct VelocityData {
    public readonly int Length;
    [WriteOnly] public ComponentDataArray<Velocity> velocity;
    public ComponentArray<Rigidbody> rigidbody;
    }
    struct AngularVelocityData {
    public readonly int Length;
    [WriteOnly] public ComponentDataArray<AngularVelocity> angularVelocity;
    public ComponentArray<Rigidbody> rigidbody;
    }


    [Inject] VelocityData velocityData;
    [Inject] AngularVelocityData angularVelocityData;

    protected override void OnUpdate() {
    for (int i = 0; i < velocityData.Length; i++) {
    Rigidbody rigidbody = velocityData.rigidbody;
    velocityData.velocity = new Velocity { value = rigidbody.velocity };
    }

    for (int i = 0; i < angularVelocityData.Length; i++) {
    AngularVelocity velocity = angularVelocityData.angularVelocity;
    Rigidbody rigidbody = angularVelocityData.rigidbody;
    velocity.value = rigidbody.angularVelocity;
    }
    }
    }[/code]

    Code (CSharp):
    1. [UpdateInGroup(typeof(PhysicUpdate))]
    2. public class VehicleMovementSystem : JobComponentSystem {
    3.  
    4.     [BurstCompile]
    5.     struct CalculateSpeedJob : IJobParallelForTransform {
    6.  
    7.         [ReadOnly] public ComponentDataArray<Velocity> velocities;
    8.         [WriteOnly] public ComponentDataArray<RacerSpeed> speeds;
    9.  
    10.  
    11.         public void Execute(int i, TransformAccess transformAccess) {
    12.             float3 forward = transformAccess.rotation * new float3(0, 0, 1);
    13.             speeds[i] = new RacerSpeed { value = math.dot(velocities[i].value, forward) };
    14.         }
    15.     }
    16.  
    17.     //[BurstCompile]
    18.     struct CalculatePropulsion : IJobParallelForTransform {
    19.  
    20.         [ReadOnly] public ComponentDataArray<PlayerInput> playerInput;
    21.         [ReadOnly] public ComponentDataArray<GroundedInfo> groundInfo;
    22.         [ReadOnly] public ComponentDataArray<DriveSettings> driveSettings;
    23.         [ReadOnly] public ComponentDataArray<RacerSpeed> racerSpeed;
    24.         [ReadOnly] public EntityArray entities;
    25.  
    26.         public float deltaTime;
    27.         public EntityCommandBuffer.Concurrent commandBuffer;
    28.         public ComponentDataArray<Velocity> velocities;
    29.         public ComponentDataArray<AngularVelocity> angularVelocity;
    30.  
    31.  
    32.         public void Execute(int i, TransformAccess transformAccess) {
    33.             Velocity velocity = velocities[i];
    34.             PlayerInput input = playerInput[i];
    35.             DriveSettings driveSetting = driveSettings[i];
    36.             //Calculate the yaw torque based on the rudder and current angular velocity
    37.             float rotationTorque = driveSetting.turnVelocity * input.rudder - angularVelocity[i].value.y;
    38.  
    39.             //Apply the torque to the ship's Y axis
    40.             //commandBuffer.CreateEntity();
    41.             //commandBuffer.AddComponent(new AddRelativeTorque { torque = new float3(0, rotationTorque, 0), mode = ForceMode.VelocityChange, receiver = entities[i] });
    42.  
    43.             //Calculate the current sideways speed by using the dot product. This tells us
    44.             //how much of the ship's velocity is in the "right" or "left" direction
    45.             float3 right = transformAccess.rotation * new float3(1,0,0);
    46.             float sidewaysSpeed = math.dot(velocity.value, right);
    47.  
    48.             //Calculate the desired amount of friction to apply to the side of the vehicle. This
    49.             //is what keeps the ship from drifting into the walls during turns. If you want to add
    50.             //drifting to the game, divide Time.fixedDeltaTime by some amount
    51.             Vector3 sideFriction = -right * (sidewaysSpeed / deltaTime);
    52.  
    53.             //Finally, apply the sideways friction
    54.             commandBuffer.CreateEntity();
    55.             commandBuffer.AddComponent(new AddForce { force = sideFriction, mode = ForceMode.Acceleration, receiver = entities[i] });
    56.  
    57.             //If not propelling the ship, slow the ships velocity
    58.             if (input.thruster <= 0f)
    59.                 velocity.value *= driveSetting.slowingVelFactor;
    60.  
    61.             //Braking or driving requires being on the ground, so if the ship
    62.             //isn't on the ground, exit this method
    63.             if (!groundInfo[i].isOnGround)
    64.                 return;
    65.  
    66.             //If the ship is braking, apply the braking velocty reduction
    67.             if (input.isBraking)
    68.                 velocity.value *= driveSetting.brakingVelFactor;
    69.  
    70.             //Calculate and apply the amount of propulsion force by multiplying the drive force
    71.             //by the amount of applied thruster and subtracting the drag amount
    72.             float3 forward = transformAccess.rotation * new float3(0, 0, 1);
    73.  
    74.             float drag = driveSetting.driveForce / driveSetting.terminalVelocity;
    75.             float propulsion = driveSetting.driveForce * input.thruster - drag * Mathf.Clamp(racerSpeed[i].value, 0f, driveSetting.terminalVelocity);
    76.             commandBuffer.CreateEntity();
    77.             commandBuffer.AddComponent(new AddForce { force = forward * propulsion, mode = ForceMode.Acceleration, receiver = entities[i] });
    78.  
    79.             velocities[i] = velocity;
    80.         }
    81.     }
    82.  
    83.     struct VehicleData {
    84.         [ReadOnly] public ComponentDataArray<PlayerInput> playerInput;
    85.         [ReadOnly] public ComponentDataArray<GroundedInfo> groundInfo;
    86.         [ReadOnly] public ComponentDataArray<DriveSettings> driveSettings;
    87.         [WriteOnly] public ComponentDataArray<RacerSpeed> racerSpeed;
    88.         [ReadOnly] public EntityArray entities;
    89.         public ComponentDataArray<Velocity> velocities;
    90.         public ComponentDataArray<AngularVelocity> angularVelocity;
    91.         public TransformAccessArray transformAccessArray;
    92.     }
    93.  
    94.     [Inject] VehicleData vehicleData;
    95.     [Inject] SyncToPhysicBarrier physicBarrier;
    96.     protected override JobHandle OnUpdate(JobHandle inputDeps) {
    97.         var speedJob = new CalculateSpeedJob() {
    98.             speeds = vehicleData.racerSpeed,
    99.             velocities = vehicleData.velocities,
    100.         };
    101.         inputDeps =  speedJob.Schedule(vehicleData.transformAccessArray, inputDeps);
    102.         inputDeps.Complete(); // only for debugging
    103.  
    104.         var propulsionJob = new CalculatePropulsion() {
    105.             deltaTime = Time.fixedDeltaTime,
    106.             commandBuffer = physicBarrier.CreateCommandBuffer(),
    107.             angularVelocity = vehicleData.angularVelocity,
    108.             velocities = vehicleData.velocities,
    109.             driveSettings = vehicleData.driveSettings,
    110.             groundInfo = vehicleData.groundInfo,
    111.             playerInput = vehicleData.playerInput,
    112.             racerSpeed = vehicleData.racerSpeed,
    113.             entities = vehicleData.entities
    114.         };
    115.  
    116.         inputDeps = propulsionJob.Schedule(vehicleData.transformAccessArray, inputDeps);
    117.         inputDeps.Complete(); // only for debugging
    118.         Debug.Log("VehicleMovementSystem");
    119.         return inputDeps;
    120.     }
    121. }
    122.  

    upload_2018-8-26_11-15-16.png
     
    rz_0lento likes this.
  11. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    We are aware of UpdateAfter & UpdateBefore having all kinds of issues, from performance to reliability. We will get to a rewrite sometime later this year.
     
  12. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,559
    HI,

    Can anyone a elaborate a bit more, on best approach of making system updating on desired frequency?
    I am reading this one and other topics, but I feel I am a bit lost on it.

    Experimetanl FixedUpdate works, and I can change frequency physics via inspector.
    But lets say, I want execute system every 0.5s? or every 1 sec.
    I read in one thread, about "hack" using timers. Of course that works. But I think I am doing something wrong.

    I simply would like have lets say OneSecondIntervalSystem, which will execute every sec.
    I thought, putting timer in update, to encapsulate execute, is way to go. But didn't worked for me.

    I think this snipped I tried to derive, is completely wrong for time control.
    Code (CSharp):
    1.  
    2. private float f_nextT ; // store future time interval
    3.         protected override JobHandle OnUpdate ( JobHandle inputDeps )
    4.         {
    5.             if ( UnityEngine.Time.time >= f_nextT ) // execute every 1 sec
    6.             {
    7.                 f_nextT = UnityEngine.Time.time + 1 ; // add 1 second
    8.          
    9.                 return new AddNode
    10.                 {
    11.                    ...
    12.                 }.Schedule (inputDeps) ;
    13.             }
    14.             return new JobHandle () ; // is this even correct?
    15.         }
    Hence, what are current the best solutions?
     
    PalmGroveSoftware likes this.
  13. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    If you want full control over the loop & timing then at the moment... (Clearly that will not be the final solution from our side, this area is very much not finished)

    * Turn off auto injection of systems into the player loop. Add relevant entry point into playerloop callback manually.
    * Call ComponentSystem.Update at the right time for all systems you want to run explicitly
    * Implement your own IComponentData storing time & input and update that in the first system that runs

    You can see the code we use for driving the bootstrap. Also visible is the define you can use to turn off the bootstrap and as such full ability to control it yourself.

    It's not the solution we think is good in any way. Clearly we need to solve that in a better way without going to the lowest levels. But for now this should get you unblocked.
     

    Attached Files:

  14. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,559
    Ah that superb.

    Looked briefly into attachments and appears to make sense. Definitely will try put it into work.

    Yep I am aware.
    For now instead of controlling system OnUpdate frequency, via adding removing entity component periodically, or other time base "hack", I would like have systems, which can run at its own speeds. Then I can have build on top of that systems order, with Update after/before etc., if required.
    So in the near future, I would have hopefully only one place to change frequency behavior, with updated Unity + ECS. Well, at least that is my understanding.
     
  15. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Yes exactly you can already write clean system code by just having your own time + input data.

    The only dirty bits for the time being will be controlling the systems but you can just put all data in a single place and don't need to leak into the actual game code.
     
  16. Gen_Scorpius

    Gen_Scorpius

    Joined:
    Nov 2, 2016
    Posts:
    65
    If only some systems need to update slower then you can always implement a counter in the system directly that decides if to continue with the code or return.
     
  17. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,559
    I may be wrong, but I don't think counter would be reliable solution, if I wan't other system to be dependent on the "slower" system.
     
  18. Gen_Scorpius

    Gen_Scorpius

    Joined:
    Nov 2, 2016
    Posts:
    65
    A slower system would only mean that the system doesn't update the data it normally processes when the set condition is met. So every dependent system either needs to be slowed down as well or use the [changefilter] or systemversionID of the data component. E.g. from TransformSystem:

    Code (CSharp):
    1. var chunkRotationsChanged = ChangeVersionUtility.DidAddOrChange(chunk.GetComponentVersion(rotationType), lastSystemVersion);
    2.                 var chunkPositionsChanged = ChangeVersionUtility.DidAddOrChange(chunk.GetComponentVersion(positionType), lastSystemVersion);
    3.                 var chunkScalesChanged = ChangeVersionUtility.DidAddOrChange(chunk.GetComponentVersion(scaleType), lastSystemVersion);
    4.                 var chunkAnyChanged = chunkRotationsChanged || chunkPositionsChanged || chunkScalesChanged;
    5.  
    6.                 if (!chunkAnyChanged)
    7.                   return;
     
  19. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,559
    I am not familiar wit this method.
    Is this something, I place on each system, which I need to be slowed down?

    I mean, it may be good option for now, but feels a bit clunky to me.
     
  20. OndrejP

    OndrejP

    Joined:
    Jul 19, 2017
    Posts:
    296
    I like possibility of low-frequency updates, that sounds good.
    What would you suggest as solution to following problem?

    Problem:
    Population of 100k people, they have one stat hunger, which increases very slowly.
    I need to update their hunger and when it reaches certain threshold do something.
    Do something might mean adding tag component Hungry (and then taking care of it in another system(s))
    I'm okay with Hungry being several frames late

    Their hunger increases very slowly, so it would be best to update only few of them every frame (e.g. one chunk).
    It this supported in ECS? Is it recommended pattern? Is it deterministic?

    Considered solutions:
    - making priority queue and checking only first element (where to store queue - in system? in singleton entity?)
    - using low-frequency update (would probably spike)
    - running separate world on different thread with different time step (e.g. 10s), reused for more "slow" systems
     
  21. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Processing one chunk at a time is quite reasonable. You could simply ask use EntityQuery.CreateArchetypeChunkArray and schedule a job and process only one of the chunks in a job every frame. And simply keep a local variable in the system that gets incremented so you pick a different index of which chunk to process every frame.

    This is deterministic & safe.
     
    OndrejP and FROS7 like this.
  22. Shinyclef

    Shinyclef

    Joined:
    Nov 20, 2013
    Posts:
    478
    if you loop over chunks over several frames, isn't their the issue or archetype changes between frames meaning you might miss some entities or process some entities more than once?
     
  23. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,624
    Does it matter?

    Realistically you'd probably fine for the majority of cases it won't, but for those that do you could lock your chunk.
     
    Last edited: May 14, 2019