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;
}
}