Here’s a situation, I’ve got a bunch of monobehaviours that have entities related to them.
I want to read transform.position from Monobehaviour side, and set it as a float3 data to the entity as a component.
Bruteforce solution works (just iterate collection of them and manually write via ECB to the EntityManager via SetComponentData) but it takes too much time to sync it when numbers of those objects rise.
I’ve searched for TransformAccess examples that use transform for reading position manually, but couldn’t find any up-to-date. Rest of the examples just point towards the full conversion, which I don’t need (only world position is required in my case).
This approach is still valid and fastest way if you don’t need any other stuff.
If you need to know what Entity has the transformAccess, using EntityQuery.ToEntityArrayAsync() too. It returns entity list which is exactly same order to TransformAccessArray() so you can grab correct Entity.
EDIT: WUuuutt its possible to attach managed objects? Wow. I didn’t know that.
It’s EntityManager.AddComponentObject that I was missing this whole time. That is super cool to have.
using UnityEngine;
using Unity.Entities;
using Unity.Burst;
using Unity.Mathematics;
using UnityEngine.Jobs;
using Unity.Collections;
public class TransformStashSystem : SystemBase
{
private EntityQuery transformQuery;
protected override void OnCreate()
{
this.transformQuery = this.GetEntityQuery(ComponentType.ReadOnly<Transform>(), ComponentType.ReadWrite<Position>());
}
protected override void OnUpdate()
{
var entityArray = this.transformQuery.ToEntityArray(Allocator.TempJob);
var transformArray = this.transformQuery.GetTransformAccessArray();
var positionFromEntity = this.GetComponentDataFromEntity<Position>();
this.Dependency = new StashTransformJob()
{
Entities = entityArray,
PositionFromEntity = positionFromEntity,
}.Schedule(transformArray, this.Dependency);
}
}
public struct Position : IComponentData
{
public float3 value;
}
[BurstCompile]
public struct StashTransformJob : IJobParallelForTransform
{
[DeallocateOnJobCompletion]
public NativeArray<Entity> Entities;
[NativeDisableParallelForRestriction]
public ComponentDataFromEntity<Position> PositionFromEntity;
public void Execute(int index, TransformAccess transform)
{
Entity entity = this.Entities[index];
Position component = this.PositionFromEntity[entity];
component.value = transform.position;
this.PositionFromEntity[entity] = component;
}
}
Create entity
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Entities;
public class TransformSample : MonoBehaviour
{
private Entity entity;
private void OnEnable()
{
var entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
this.entity = entityManager.CreateEntity();
entityManager.AddComponent<Position>(this.entity);
entityManager.AddComponentObject(this.entity, this.transform);
}
private void OnDisable()
{
var entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
entityManager.DestroyEntity(this.entity);
this.entity = default;
}
}
These two files contains all you need I think.
Additional tips:
If your transforms share same root transform, it cannot be read as parallel. This is Unity’s restrction so you should manage your transforms does not share same root as possible as for maximum performance.
Yeah, its unfortunately the case. Lots of points attached to the single root.
Good to know though. Perhaps I’ll remake it someday.
Got a x2-3 performance boost compared to the bruteforce method, not quite zero, but its better than it was before.
Guess that’s the price for using Hybrid & this kind of hierarchy.