Reference Unity objects in your code
To store references to UnityEngine.Object
types in your code, you can use the UnityObjectRef
struct inside an unmanaged IComponentData
component. You can then use this reference to access the original object and use it in systems.
For example, you have a GameObject
with an Animator
object which you want to instantiate and access in a system. You can achieve this by creating an IComponentData
struct with a UnityObjectRef
field that holds a reference to the GameObject
. You can then instantiate this prefab from a system, and use the target Animator
component.
Using UnityObjectRef
The following example shows how to define an IComponentData
with a UnityObjectRef
field and how to use a baker to store a reference to the GameObject
prefab during conversion:
public class AnimatorAuthoring : MonoBehaviour
{
public GameObject AnimatorPrefab;
public class AnimatorBaker : Baker<AnimatorAuthoring>
{
public override void Bake(AnimatorAuthoring authoring)
{
var e = GetEntity(TransformUsageFlags.Renderable);
AddComponent(e, new AnimatorRefComponent
{
AnimatorAsGO = authoring.AnimatorPrefab
});
}
}
}
public struct AnimatorRefComponent : IComponentData
{
public UnityObjectRef<GameObject> AnimatorAsGO;
}
You can use SystemAPI
to access and instantiate the prefab:
public partial struct SpawnAnimatedCubeSystem : ISystem
{
public void OnCreate(ref SystemState state)
{
var entities = SystemAPI.QueryBuilder().WithAll<AnimatorRefComponent>().WithNone<Animator>().Build().ToEntityArray(state.WorldUpdateAllocator);
foreach (var entity in entities)
{
var animRef = SystemAPI.GetComponent<AnimatorRefComponent>(entity);
var rotatingCube = (GameObject)Object.Instantiate(animRef.AnimatorAsGO);
state.EntityManager.AddComponentObject(entity, rotatingCube.GetComponent<Animator>());
}
}
}
You can also access and modify the Animator
from a separate system. The following example shows how to adjust the animation speed dynamically:
public partial struct ChangeRotationAnimationSystem : ISystem
{
public void OnUpdate(ref SystemState state)
{
//Query and modify the speed of the Animator
foreach (var anim in SystemAPI.Query<SystemAPI.ManagedAPI.UnityEngineComponent<Animator>>())
{
var sineSpeed = 1f + Mathf.Sin(Time.time);
anim.Value.speed = sineSpeed;
}
}
}
Referencing the same asset in MonoBehaviour and IComponentData code
During a Player build, Unity collects all UntypedWeakReferenceId
values from each included subscene. This also includes any WeakObjectReference<T>
and WeakObjectSceneReference
properties. Any Unity objects directly referenced from entity data (including UnityObjectRef<T>
) are also collected and added to a special ScriptableObject
that has an UntypedWeakReferenceId
created for it.
Unity builds these references into a set of ContentArchive
instances that it optimizes for usage and duplication as follows:
- Any objects that are used together are put into the same archive to maximize loading efficiency.
- Any shared objects are put into separate archives to prevent duplication.
- Any objects that have direct references from normal scenes are built directly into Player data, which is separate from the archive data.
If an object is referenced by both normal and entity scenes it is duplicated in both sets of data and each has its own InstanceID at runtime. A normal scene can contain a WeakObjectReference<T>
and you can use this reference to load from the archive data at runtime as long as the reference is also included in an entity scene. This setup only includes one copy of the asset in the build.