Search Unity

Feedback Changing player character state

Discussion in 'Entity Component System' started by nantoaqui, May 21, 2019.

  1. nantoaqui

    nantoaqui

    Joined:
    Oct 1, 2014
    Posts:
    42
    Hello,

    Could you please review the solution to handle the player character state?

    I created tag components for these states: Idle, Roll, Walk, Slash.
    The system is only allowed to run when it doesn't contains the states Roll & Slash. One thing that I didn't like is that I need to remove all states from the entity. Is there a better way to handle this?

    Code (CSharp):
    1.  public class MainCharacterAbilitySystem : JobComponentSystem {
    2.         [ExcludeComponent (typeof (Roll), typeof (Slash))]
    3.         [RequireComponentTag (typeof (Player))]
    4.         struct UpdateJob : IJobForEachWithEntity<PlayerInput> {
    5.             public EntityCommandBuffer.Concurrent Commands;
    6.  
    7.             public void Execute (Entity entity, int index, [ReadOnly] ref PlayerInput input) {
    8.                 Commands.RemoveComponent (index, entity, typeof (Idle));
    9.                 Commands.RemoveComponent (index, entity, typeof (Roll));
    10.                 Commands.RemoveComponent (index, entity, typeof (Walk));
    11.                 Commands.RemoveComponent (index, entity, typeof (Slash));
    12.  
    13.                 switch (input.action) {
    14.                     case InputAction.ATTACK:
    15.                         Commands.AddComponent (index, entity, new Slash { coolDown = 0 });
    16.                         break;
    17.                     case InputAction.MOVE:
    18.                         Commands.AddComponent (index, entity, new Walk ());
    19.                         break;
    20.                     case InputAction.ROLL:
    21.                         Commands.AddComponent (index, entity, new Roll { direction = input.axis, timer = 0 });
    22.                         break;
    23.                     default:
    24.                         Commands.AddComponent (index, entity, new Idle ());
    25.                         break;
    26.                 }
    27.             }
    28.         }
    29.  
    30.         private BeginSimulationEntityCommandBufferSystem beginSimEcbSystem;
    31.  
    32.         protected override void OnCreateManager () {
    33.             this.beginSimEcbSystem = World.GetOrCreateSystem<BeginSimulationEntityCommandBufferSystem> ();
    34.         }
    35.  
    36.         protected override JobHandle OnUpdate (JobHandle inputDeps) {
    37.             var job = new UpdateJob {
    38.                 Commands = this.beginSimEcbSystem.CreateCommandBuffer ().ToConcurrent (),
    39.             };
    40.  
    41.             var jobHandle = job.Schedule (this, inputDeps);
    42.  
    43.             this.beginSimEcbSystem.AddJobHandleForProducer (jobHandle);
    44.  
    45.             return jobHandle;
    46.         }
    47.     }
    RollStateSystem:

    Code (CSharp):
    1.    public class RollStateSystem : JobComponentSystem {
    2.         public struct UpdateJob : IJobForEachWithEntity<Velocity, Roll, RollSettings, Facing> {
    3.             public EntityCommandBuffer.Concurrent Commands;
    4.             public float2 axis;
    5.             public float deltaTime;
    6.  
    7.             public void Execute (Entity entity, int index, ref Velocity velocity, [ReadOnly] ref Roll roll, [ReadOnly] ref RollSettings rollSettings, [ReadOnly] ref Facing facing) {
    8.                 roll.timer = roll.timer + deltaTime;
    9.  
    10.                 if (roll.timer >= rollSettings.duration) {
    11.                     Commands.RemoveComponent (index, entity, typeof (Roll));
    12.                 } else {
    13.                     var direction = roll.direction;
    14.                     if (roll.direction.x == 0 && roll.direction.y == 0) {
    15.                         direction = facing.Value * -1;
    16.                     }
    17.  
    18.                     velocity.Value = direction * rollSettings.speed * deltaTime;
    19.                 }
    20.             }
    21.         }
    22.  
    23.         private BeginSimulationEntityCommandBufferSystem beginSimEcbSystem;
    24.  
    25.         protected override void OnCreateManager () {
    26.             this.beginSimEcbSystem = World.GetOrCreateSystem<BeginSimulationEntityCommandBufferSystem> ();
    27.         }
    28.  
    29.         protected override JobHandle OnUpdate (JobHandle inputDeps) {
    30.             var job = new UpdateJob {
    31.                 Commands = this.beginSimEcbSystem.CreateCommandBuffer ().ToConcurrent (),
    32.                 axis = new float2 (Input.GetAxisRaw ("Horizontal"), Input.GetAxisRaw ("Vertical")),
    33.                 deltaTime = Time.deltaTime
    34.             };
    35.  
    36.             var jobHandle = job.Schedule (this, inputDeps);
    37.  
    38.             this.beginSimEcbSystem.AddJobHandleForProducer (jobHandle);
    39.  
    40.             return jobHandle;
    41.         }
    42.     }
    RollComponent:

    Code (CSharp):
    1.     public struct Roll : IComponentData {
    2.         public float timer;
    3.         public float2 direction;
    4.     }
    RollSettingsComponent:

    Code (CSharp):
    1.     public struct RollSettings : IComponentData {
    2.         public float duration;
    3.         public float speed;
    4.     }
    Also I split the roll state into two components: RollSettings is being set on the prefab object and being accessed through the RollStateSystem. Is this workflow correct?

    Thanks!
     
  2. JooleanLogic

    JooleanLogic

    Joined:
    Mar 1, 2018
    Posts:
    447
    I'm maybe missing some concept here but in MainCharacterAbilitySystem, how is it you're removing Roll and Slash components when they don't exist on the entity?
     
  3. nantoaqui

    nantoaqui

    Joined:
    Oct 1, 2014
    Posts:
    42
    I think that RemoveComponent just skip through when the entity doesn't have a component. This could also be an issue, since it will always remove and add over and over again the idle state. :/