Accessing properties on ECS components directly

  • A* version: [5.2.4]
  • Unity version: [2022.3.42]

Hi, I am having issues trying to access properties directly from the ECS (FollowerEntity) as there is a higher overhead from accessing them through the script (as state in the documentation). I am particularly attempting to access updateRotation and updatePosition bools, after trying to deconstruct how it was done for the AIDestinationSetter- I am confused on the matter. Can anyone shed some light on how to access these bools without getting them directly from the FollowerEntity script?

Thank you for any suggestions

Each component is a little different on the ECS side. Those ECS components are SyncPositionWithTransform and SyncRotationWithTransform. They are added/removed on the Entity to indicate if they are true/false.

Looking at them in FollowerEntity, I don’t think those variables have higher overhead unless your setting them, the getter just returns a script variable. If you need them in an ECS system, I would suggest either using EntityManager.HasComponent to check true/false, or ComponentLookup.HasComponent if its in a job.

Hi Curtis, thanks for the response- I am indeed trying to set the values, not get them(and have noted high overhead in the profiler doing so). I see the “SyncWithTransforms.cs” script that has the two functions SyncPositionWithTransform / SyncRotationWithTransform that are empty. I assume this function is in question:

public bool updatePosition {
			get => syncPosition;
			set {
				syncPosition = value;
				ToggleComponent<SyncPositionWithTransform>(entity, value, false);
			}
		}

How would I go about changing their values in FollowerEntity? I apologize for my lack of understanding in ECS

Ya that is the function, the reason is that ToggleComponent adds or removes the component, which has some overhead. If you are looking to completely stop the unit from moving/turning, it might be more efficient to use FollowerEntity.isStopped since that is just setting a component value, which I think is cheaper.

The most efficient way would be to go completely ECS and use an ISystem something like this.

partial struct StopMovingSystem : ISystem
{
    public void OnUpdate(ref SystemState state)
    {
        //Probably need some other info in your query to determine if the stop condition is met
        foreach (var (movementSettings, entity) in SystemAPI.Query<RefRW<MovementSettings>>().WithEntityAccess())
        {
             if(stopConditionMet)
             {
                  movementSettings.ValueRW.isStopped = true;
             }
             else
             {
                  movementSettings.ValueRW.isStopped = false;
             }
        }
    }
}

If you expect there to be lots of units you could optimize further by turning it into a multithreaded parallel job. If you need to make the decision in a Monobehaviour and want the execution optimized you would need to add some sort of static list of requests that a System like this would handle.

Ah that explains the overhead (adding/removing components). The problem I am having is I am in fact making the decision in a MonoBehaviour, which is causing issues accessing/changing properties in the ECS itself; so its not exactly clear what is meant by creating a static list of requests that you mentioned.

Thanks for the sample code, I understand what its doing, though having a hard time seeing how to get this linked to a monobehaviour :frowning_face:

If your not familiar with ECS the request system is probably going to be challenging. I haven’t even tried to make one yet myself because I suspect it’s going to be hard to optimize.

It sounds like the overhead might be caused by your logic changing the value too frequently. If you are calling FollowerEntity.updatePosition = true/false on many things, or worse many times in a single frame, that could add up quickly. There is a way to call EntityManager.Add/Remove Component using a NativeArray of Entity. This is similar to the request system I mentioned, but using a Monobehaviour as the manager instead of getting into ECS Systems.

public class FollowerEntityManager: Monobehaviour
{
    //Add to these from other scripts using FollowerEntity.Entity
    //Ensure that the FollowerEntity.updateRotation is true
    public NativeList<Entity> stopTurningEntities;
    //Ensure that the FollowerEntity.updateRotation is false
    public NativeList<Entity> startTurningEntities;

    //Allocate/Dispose NativeLists in Start/Destroy

    //Do this in LateUpdate assuming lists are set from some other Update
    public void LateUpdate()
    {
         //Add and Remove From all entities in the NativeLists
         if(stopTurningEntities.Length > 0)
             World.DefaultGameObjectInjectionWorld.EntityManager.RemoveComponent<SyncRotationWithTransform>(stopTurningEntities.ToArray());
         if(startTurningEntities.Length > 0)
             World.DefaultGameObjectInjectionWorld.EntityManager.AddComponent<SyncRotationWithTransform>(startTurningEntities.ToArray());

         //Clear the lists for the next frame
         stopTurningList.Clear();
         startTuringList.Clear();
    }
}