Search Unity

Resolved Having issues with reading Inputs in FixedStepSimulation

Discussion in 'Entity Component System' started by toomasio, Jan 22, 2021.

  1. toomasio

    toomasio

    Joined:
    Nov 19, 2013
    Posts:
    198
    I have a UserInputJumpSystem that reads inputs from my main input system. It activates a bool on the jump component. I then have a JumpSystem that checks if I am grounded, then jump.

    Sometimes the fixed step will miss this bool switch. Not sure what I can do to fix this. The execution order is pretty important here because I need the jump velocity to be affected the same frame as when you push the jump button. Any Ideas?

    Code (CSharp):
    1. [UpdateInGroup(typeof(UserInputGroup))]
    2.     public class UserInputJumpSystem : SystemBase
    3.     {
    4.         private DotsInputSystem input;
    5.  
    6.         protected override void OnCreate()
    7.         {
    8.             input = World.GetExistingSystem<DotsInputSystem>();
    9.         }
    10.  
    11.         protected override void OnUpdate()
    12.         {
    13.             var jumpInput = input.InputActions.Player.Jump.triggered;
    14.  
    15.             Entities
    16.                 .WithAll<Player>()
    17.                 .ForEach((ref Jump jump, ref PhysicsVelocity vel) =>
    18.                 {
    19.                     jump.activated = jumpInput;
    20.                 })
    21.                 .Schedule();
    22.         }
    23.     }
    Code (CSharp):
    1. [UpdateInGroup(typeof(PhysicsControlGroup))]
    2.     public class JumpSystem : SystemBase
    3.     {
    4.         protected override void OnUpdate()
    5.         {
    6.             Entities
    7.                 .ForEach((ref PhysicsVelocity vel, in Jump jump, in CheckGrounded grounded) =>
    8.                 {
    9.                     if (!grounded.grounded) return;
    10.  
    11.                     if (jump.activated)
    12.                     {
    13.                         Debug.Log($"Jumped Fixed Step");
    14.                         vel.Linear.y = jump.jumpPower;
    15.                     }
    16.                        
    17.                 })
    18.                 .Schedule();
    19.         }
    20.     }
     
  2. jasons-novaleaf

    jasons-novaleaf

    Joined:
    Sep 13, 2012
    Posts:
    181
    when you say "Sometimes the fixed step will miss this bool switch" what does that mean? The JumpSystem
    if (jump.activated)
    is false? if so, that means
    jumpInput = input.InputActions.Player.Jump.triggered;
    was also false. I haven't used the input system, but maybe see if there is something like
    jumpInput = input.InputActions.Player.Jump.isPressed;
    you can call instead?
     
  3. toomasio

    toomasio

    Joined:
    Nov 19, 2013
    Posts:
    198
    Nevermind. I fixed this with adding Tags instead of using bools. new Code:

    Code (CSharp):
    1. [UpdateInGroup(typeof(UserInputGroup))]
    2.     public class UserInputJumpSystem : SystemBase
    3.     {
    4.         private DotsInputSystem input;
    5.         private BeginFixedStepSimulationEntityCommandBufferSystem buffer;
    6.  
    7.         protected override void OnCreate()
    8.         {
    9.             input = World.GetExistingSystem<DotsInputSystem>();
    10.             buffer = World.GetExistingSystem<BeginFixedStepSimulationEntityCommandBufferSystem>();
    11.         }
    12.  
    13.         protected override void OnUpdate()
    14.         {
    15.             var jumpInput = input.InputActions.Player.Jump.triggered;
    16.             var ecb = buffer.CreateCommandBuffer().AsParallelWriter();
    17.  
    18.             Dependency = Entities
    19.                 .WithAll<Player>()
    20.                 .ForEach((Entity entity, int entityInQueryIndex, ref Jump jump, ref PhysicsVelocity vel) =>
    21.                 {
    22.                     if (jumpInput)
    23.                     {
    24.                         Debug.Log($"adding jump component");
    25.                         ecb.AddComponent<IsJumping>(entityInQueryIndex, entity);
    26.                     }
    27.                        
    28.                 })
    29.                 .Schedule(Dependency);
    30.  
    31.             buffer.AddJobHandleForProducer(Dependency);
    32.         }
    33.     }
    Code (CSharp):
    1. [UpdateInGroup(typeof(PhysicsControlGroup))]
    2.     public class JumpSystem : SystemBase
    3.     {
    4.         private EndFixedStepSimulationEntityCommandBufferSystem buffer;
    5.  
    6.         protected override void OnCreate()
    7.         {
    8.             buffer = World.GetExistingSystem<EndFixedStepSimulationEntityCommandBufferSystem>();
    9.         }
    10.  
    11.         protected override void OnUpdate()
    12.         {
    13.  
    14.             var ecb = buffer.CreateCommandBuffer().AsParallelWriter();
    15.  
    16.             Dependency = Entities
    17.                 .WithAll<IsJumping>()
    18.                 .ForEach((Entity entity, int entityInQueryIndex, ref PhysicsVelocity vel, in Jump jump, in CheckGrounded grounded) =>
    19.                 {
    20.                     if (!grounded.grounded) return;
    21.  
    22.                     Debug.Log($"Jumped Fixed Step");
    23.                     vel.Linear.y = jump.jumpPower;
    24.  
    25.                     ecb.RemoveComponent<IsJumping>(entityInQueryIndex, entity);
    26.  
    27.                 })
    28.                 .Schedule(Dependency);
    29.  
    30.             buffer.AddJobHandleForProducer(Dependency);
    31.         }
    32.     }
     
  4. jasons-novaleaf

    jasons-novaleaf

    Joined:
    Sep 13, 2012
    Posts:
    181
    oh I see what you mean.
    var jumpInput = input.InputActions.Player.Jump.triggered;
    was true, but then that UserInputJumpSystem updated again and then jumpInput was false, before the JumpSystem : even runs.

    While your tag version works, it seems super hacky to me and probably want to avoid it's pattern when possible due to sync points.

    But based on your tag solution, I can see the best of both worlds:

    Code (CSharp):
    1. //UserInputJumpSystem
    2.  
    3. .ForEach((ref Jump jump, ref PhysicsVelocity vel) =>
    4.                 {
    5.                     if(jumpInput){ jump.activated = true;}
    6.                 })
    Code (CSharp):
    1. //JumpSystem
    2.  
    3. .ForEach((ref PhysicsVelocity vel, ref Jump jump, in CheckGrounded grounded) =>
    4.                 {
    5.                     if (!grounded.grounded) return;
    6.                     if (jump.activated)
    7.                     {
    8.                         Debug.Log($"Jumped Fixed Step");
    9.                         vel.Linear.y = jump.jumpPower;
    10.                         jump.activated = false;
    11.                     }
    12.                      
    13.                 })
     
    toomasio likes this.
  5. toomasio

    toomasio

    Joined:
    Nov 19, 2013
    Posts:
    198
    Well that is a much easier solution. definitely over analyzed that one! it works Thanks!
     
  6. jasons-novaleaf

    jasons-novaleaf

    Joined:
    Sep 13, 2012
    Posts:
    181
    also consider putting both systems in the same simulation group, and set the UpdateAfter attribute. that will make sure they update in order. I've never done that before, so sorry I can't share the exact code to do so.
     
  7. toomasio

    toomasio

    Joined:
    Nov 19, 2013
    Posts:
    198
    yeah I have custom groups everywhere in my project. I can't put these in the same sim though as my jump relies on some physics calculations, like checking the ground.