Unable to get ECS physics PhysicsVelocity and PhysicsGravityFactor data from outside the object

Hi, I was going through the Physics sample projects given by Unity for ECS, I opened scene 2d1 (trigger scene) and saw how it worked. My curiosity had the better of me and I wanted to create a system just to see the velocity and gravityFactor in the Inspector.

The First logic I made was to add a component called TrackComp so I can find the entity and get the data from its components.

Now, the first attempt I made, I wanted to access the data from ECS and present it on a MonoBehaviour. I went ahead and got a SystemHandle for the system, but how to get a specific Entity in the system got me confused (I am new to the whole ECS accessing thing). This ends me cancelling the approach, but I am adding the script in case someone out there can help me with this as this is what I really want to access.

The Final approach that I was more hopeful about was to make a new System and populate the data in my TrackComp as I can then at least access the data from outside the system as a intermediate step before I access it through some logic in my MonoBehaviour. I wrote the system, I have ensured that my new system runs after FixedStepSimulationSystemGroup in Update but I still see both my fields as having default data.

I am attaching all three scripts where TriggerGravityFactorAuthoring.cs is the default script by Unity.

using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Physics;
using Unity.Physics.Systems;
using UnityEngine;

public struct TriggerGravityFactor : IComponentData
{
    public float GravityFactor;
    public float DampingFactor;
}

public class TriggerGravityFactorAuthoring : MonoBehaviour
{
    public float GravityFactor = 0f;
    public float DampingFactor = 0.9f;

    void OnEnable() {}

    class TriggerGravityFactorBaker : Baker<TriggerGravityFactorAuthoring>
    {
        public override void Bake(TriggerGravityFactorAuthoring authoring)
        {
            AddComponent(new TriggerGravityFactor()
            {
                GravityFactor = authoring.GravityFactor,
                DampingFactor = authoring.DampingFactor,
            });
        }
    }
}

// This system sets the PhysicsGravityFactor of any dynamic body that enters a Trigger Volume.
// A Trigger Volume is defined by a PhysicsShapeAuthoring with the `Is Trigger` flag ticked and a
// TriggerGravityFactor behaviour added.
[RequireMatchingQueriesForUpdate]
[UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
[UpdateAfter(typeof(PhysicsSystemGroup))]
[BurstCompile]
public partial struct TriggerGravitySystem : ISystem
{
    ComponentDataHandles m_Handles;

    struct ComponentDataHandles
    {
        public ComponentLookup<TriggerGravityFactor> TriggerGravityFactorGroup; // component with gravity and dampning factor created by user
        public ComponentLookup<PhysicsGravityFactor> PhysicsGravityFactorGroup; // The factor by which gravity is applied in physics step to each PhysicsBody(rigidbody) - https://docs.unity3d.com/Packages/com.unity.physics@1.0/api/Unity.Physics.PhysicsGravityFactor.html?q=PhysicsGravityFactor
        public ComponentLookup<PhysicsVelocity> PhysicsVelocityGroup; // the velocity of a rigidbody in simulation - https://docs.unity3d.com/Packages/com.unity.physics@1.0/api/Unity.Physics.PhysicsVelocity.html?q=PhysicsVelocity

        public ComponentDataHandles(ref SystemState state)
        {
            // Constructor Sets the data based on SystemState data
            TriggerGravityFactorGroup = state.GetComponentLookup<TriggerGravityFactor>(true);
            PhysicsGravityFactorGroup = state.GetComponentLookup<PhysicsGravityFactor>(false);
            PhysicsVelocityGroup = state.GetComponentLookup<PhysicsVelocity>(false);
        }

        // On every update, we update the data stored in the three groups
        public void Update(ref SystemState state)
        {
            TriggerGravityFactorGroup.Update(ref state);
            PhysicsGravityFactorGroup.Update(ref state);
            PhysicsVelocityGroup.Update(ref state);
        }
    }

    [BurstCompile]
    public void OnCreate(ref SystemState state)
    {
        // This system requires data to be present in the Query if we want to run the system.
        state.RequireForUpdate(state.GetEntityQuery(ComponentType.ReadOnly<TriggerGravityFactor>()));
        // https://docs.unity3d.com/Packages/com.unity.entities@1.0/api/Unity.Entities.SystemState.RequireForUpdate.html
        // create a new object to have local reference to all data we needed from SystemState
        m_Handles = new ComponentDataHandles(ref state);
    }

    [BurstCompile]
    public void OnDestroy(ref SystemState state)
    {
    }

    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        // update local data
        m_Handles.Update(ref state);
        // create a new Job which does not run unless the previous Dependencies are completed.
        state.Dependency = new TriggerGravityFactorJob
        {
            TriggerGravityFactorGroup = m_Handles.TriggerGravityFactorGroup,
            PhysicsGravityFactorGroup = m_Handles.PhysicsGravityFactorGroup,
            PhysicsVelocityGroup = m_Handles.PhysicsVelocityGroup,
        }.Schedule(SystemAPI.GetSingleton<SimulationSingleton>(), state.Dependency);
    }

    [BurstCompile]
    struct TriggerGravityFactorJob : ITriggerEventsJob
    {
        [ReadOnly] public ComponentLookup<TriggerGravityFactor> TriggerGravityFactorGroup; // user defined component
        public ComponentLookup<PhysicsGravityFactor> PhysicsGravityFactorGroup; // Physics gravity Factor present all over this system at this frame
        public ComponentLookup<PhysicsVelocity> PhysicsVelocityGroup; // the velocity of all rididbody(physicsBody) in system at this frame

        public void Execute(TriggerEvent triggerEvent)
        {
            Entity entityA = triggerEvent.EntityA;
            Entity entityB = triggerEvent.EntityB;

            bool isBodyATrigger = TriggerGravityFactorGroup.HasComponent(entityA);
            bool isBodyBTrigger = TriggerGravityFactorGroup.HasComponent(entityB);

            // Ignoring Triggers with user defined component overlapping other Triggers
            if (isBodyATrigger == isBodyBTrigger)
                return;

            bool isBodyADynamic = PhysicsVelocityGroup.HasComponent(entityA);
            bool isBodyBDynamic = PhysicsVelocityGroup.HasComponent(entityB);

            // Ignoring overlapping static bodies
            if ((isBodyATrigger && !isBodyBDynamic) || (isBodyBTrigger && !isBodyADynamic))
                return;

            var triggerEntity = isBodyATrigger ? entityA : entityB;
            var dynamicEntity = isBodyATrigger ? entityB : entityA;

            var triggerGravityComponent = TriggerGravityFactorGroup[triggerEntity];
            // tweak PhysicsGravityFactor
            {
                var component = PhysicsGravityFactorGroup[dynamicEntity];
                component.Value = triggerGravityComponent.GravityFactor;
                PhysicsGravityFactorGroup[dynamicEntity] = component;
            }
            // damp velocity
            {
                var component = PhysicsVelocityGroup[dynamicEntity];
                component.Linear *= triggerGravityComponent.DampingFactor;
                PhysicsVelocityGroup[dynamicEntity] = component;
            }
        }
    }
}

TrackGravityDampning.cs is the MonoBehaviour script which I added in Unity trying to fetch ECS values inside Unity and hit a point that I could not understand how I should approach the problem.

using System.Collections;
using System.Collections.Generic;
using Unity.Collections;
using Unity.Entities;
using UnityEngine;

public class TrackGravityDampning : MonoBehaviour
{
    public float currGravity;
    public Vector3 currVelocity;
    private Entity targetEntity = Entity.Null;
    private Entity GetRandomEntity()
    {
        EntityQuery entitiesWithoutGravity = World.DefaultGameObjectInjectionWorld.EntityManager.CreateEntityQuery(typeof(TrackComp));

        if (entitiesWithoutGravity.CalculateEntityCount() <= 0)
        {
            return Entity.Null ;
        }

        NativeArray<Entity> queryNativeArray = entitiesWithoutGravity.ToEntityArray(Unity.Collections.Allocator.Temp);
        return queryNativeArray[0];
    }

    private void Start()
    {
        SystemHandle tSystem = World.DefaultGameObjectInjectionWorld.GetExistingSystem<TriggerGravitySystem>();
        if (tSystem != null)
        {
            Debug.Log("Got the system Hanel");
        }
        //TriggerGravityFactor tSystemBase = World.DefaultGameObjectInjectionWorld.GetOrCreateSystemManaged(typeof(TriggerGravitySystem));
    }

    private void LateUpdate()
    {
        if (targetEntity != Entity.Null)
        {
            currGravity = 0f; // need a logic to access PhysicsGravityFactor component of this entity
            currVelocity = Vector3.zero; // need a logic to access PhysicsVelocity's Linear component of this entity
        }
        else
        {
            currGravity = 0f;
            currVelocity = Vector3.zero;
        }

        if (Input.GetKeyDown(KeyCode.Space))
        {
            targetEntity = GetRandomEntity();
        }
    }
}

TrackCompAuthoring.cs is the new system I made along with the TrackComp and I still get no data in the Component view of Inspector(runtime) even though my new system runs after Unity’s system.

using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Physics;
using Unity.Physics.Systems;
using UnityEngine;

public class TrackCompAuthoring : MonoBehaviour
{
    public GameObject target;
    void OnEnable() {}
}

public class TrackCompBaker : Baker<TrackCompAuthoring>
{
    public override void Bake(TrackCompAuthoring authoring)
    {
        AddComponent(new TrackComp()
        {
            targetE = GetEntity(authoring.target)
        }
        );
    }
}

public struct TrackComp : IComponentData
{
    public Entity targetE;
    public float gravity;
    public float3 velocity;
}


public partial class TrackCompSystem : SystemBase
{
    protected override void OnUpdate()
    {
        TrackComp trackComp = SystemAPI.GetSingleton<TrackComp>();

        //foreach ((PhysicsVelocity phyVel, PhysicsGravityFactor physicsGravity) in //SystemAPI.Query<PhysicsVelocity, PhysicsGravityFactor>())
        //{
        //    trackComp.gravity = physicsGravity.Value;
        //    trackComp.velocity = phyVel.Linear;
        //}
        trackComp.gravity = EntityManager.GetComponentData<PhysicsGravityFactor>(trackComp.targetE).Value;
        trackComp.velocity = EntityManager.GetComponentData<PhysicsVelocity>(trackComp.targetE).Linear;
    }
}

I wanted to create a system just to see the velocity and gravityFactor in the Inspector

I wanted to access the data from ECS and present it on a MonoBehaviour

com.unity.entities 1.0.0-pre.15 comes with dedicated tools for that; you don’t need to write your own here. I suggest you start with Windows / Entities / Hierarchy as it lists all entities in Play Mode. This window has a search bar and writing there c=TriggerGravityFactor will query for all entities with this components for you to inspect their data.

204148-screenshot-2023-01-23-102653.png

Entities can be split in multiple Worlds (World is like a Scene but for entities) in some cases, so watch for that in the future.

I went ahead and got a SystemHandle for the system, but how to get a specific Entity in the system got me confused

To list entities filtered by system, open Windows / Entities / Systems window, find and select your system there to see list of queries in the inspector. Clicking a window icon next to query name ( “Query #1”) will open up a window with “Entities” tab; selecting entities there allows you to inspect their data in the Inspector.

Query type defines a search query - it is a filter to find specific type of entities. Many systems define multiple such queries but it should be just a single one ideally (single responsibility for simplicity and clarity).
_

TrackCompAuthoring.cs

using UnityEngine;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Physics;

// add this component to one of the physics bodies in the sub scene
[RequireComponent(typeof(Unity.Physics.Authoring.PhysicsBodyAuthoring))]
public class TrackCompAuthoring : MonoBehaviour { }

public class TrackCompBaker : Baker<TrackCompAuthoring>
{
    public override void Bake(TrackCompAuthoring authoring) => AddComponent(new TrackComp { });
}

public struct TrackComp : IComponentData
{
    public float gravity;
    public float3 velocity;
}

public partial class TrackCompSystem : SystemBase
{
    protected override void OnUpdate()
    {
        var copyJob = new CopyToTrackCompJob { };
        Dependency = copyJob.ScheduleParallel(Dependency);
    }

    [Unity.Burst.BurstCompile]
    partial struct CopyToTrackCompJob : IJobEntity
    {
        public void Execute(ref TrackComp trackComp, in PhysicsVelocity phyVel, in PhysicsGravityFactor physicsGravity)
        {
            trackComp.gravity = physicsGravity.Value;
            trackComp.velocity = phyVel.Linear;
        }
    }
}

_

TrackGravityDamping.cs

using UnityEngine;
using Unity.Mathematics;
using Unity.Collections;
using Unity.Entities;
using Unity.Physics;

public class TrackGravityDamping : MonoBehaviour
{
    [SerializeField] float _gravity;
    [SerializeField] Vector3 _velocity;
    [SerializeField] bool _read = true;
    [SerializeField] bool _write = false;
    EntityManager _entityManager;
    EntityQuery _query;

    void Start()
    {
        var world = World.DefaultGameObjectInjectionWorld;
        _entityManager = world.EntityManager;

        // this query will search for entities with all 3 component types: 
        _query = _entityManager.CreateEntityQuery(new EntityQueryDesc
        {
            All = new ComponentType[] {
                typeof(TrackComp),
                typeof(PhysicsGravityFactor),
                typeof(PhysicsVelocity)
            }
        });
    }

    void FixedUpdate()
    {
        if (_read)
        {
            _query.CompleteDependency();
            foreach (var gravityFactor in _query.ToComponentDataArray<PhysicsGravityFactor>(Allocator.Temp))
                _gravity = gravityFactor.Value;
            foreach (var velocity in _query.ToComponentDataArray<PhysicsVelocity>(Allocator.Temp))
                _velocity = velocity.Linear;
        }
        if (_write)
        {
            _query.CompleteDependency();
            foreach (Entity entity in _query.ToEntityArray(Allocator.Temp))
            {
                _entityManager.SetComponentData(entity, new PhysicsGravityFactor { Value = _gravity });
                _entityManager.SetComponentData(entity, new PhysicsVelocity { Linear = _velocity, Angular = new float3(0, 0, 0) });
            }
        }
    }
}