Skip to content

Instantly share code, notes, and snippets.

@daimahou
Last active July 27, 2026 01:35
Show Gist options
  • Select an option

  • Save daimahou/4f3da33e689074a8459d83bc6db9e042 to your computer and use it in GitHub Desktop.

Select an option

Save daimahou/4f3da33e689074a8459d83bc6db9e042 to your computer and use it in GitHub Desktop.
Simple implementation of hybrid game objects - entity in unity ECS
// Spawns a game object and link it to the entity this component is attached to.
// The linked game object will have the local transform of the entity copied to its transform automatically by the system
// Any additional monobehaviour can be made accessible from the ECS world by implementing the ICompanionComponent interface
//
// Note: Game Object / Entity destruction is not handled in this gist
public class CompanionObjectAuthoring : MonoBehaviour {
[SerializeField] GameObject prefab;
class Baker : Baker<CompanionObjectAuthoring> {
public override void Bake(CompanionObjectAuthoring authoring) {
Entity e = GetEntity(TransformUsageFlags.Dynamic);
AddComponent(e, new CompanionObjectPrefab {
reference = authoring.prefab,
});
}
}
}
public struct CompanionObject : IComponentData {
public UnityObjectRef<GameObject> reference;
public GameObject GameObject => reference.Value;
}
public struct CompanionObjectPrefab : IComponentData {
public UnityObjectRef<GameObject> reference;
public GameObject Prefab => reference.Value;
}
public interface ICompanionComponent {
void CreateCompanionComponent(EntityCommandBuffer ecb, Entity entity);
}
public partial class CompanionObjectSystemGroup : ComponentSystemGroup {}
[UpdateInGroup(typeof(CompanionObjectInitializeSystemGroup))]
public partial struct InstantiateCompanionObjectSystem : ISystem {
public void OnUpdate(ref SystemState state) {
EntityCommandBuffer ecb = new(state.WorldUpdateAllocator);
foreach ((CompanionObjectPrefab companionObjectPrefab, Entity e)
in SystemAPI.Query<CompanionObjectPrefab>().WithNone<CompanionObject>().WithEntityAccess()) {
InstantiateCompanionObject(companionObjectPrefab.Prefab, ecb, e);
}
ecb.Playback(state.EntityManager);
}
static void InstantiateCompanionObject(GameObject prefab, EntityCommandBuffer ecb, Entity e) {
GameObject companion = Object.Instantiate(prefab);
ecb.AddComponent(e, new CompanionObject { reference = companion });
foreach (ICompanionComponent companionComponent in companion.GetComponents<ICompanionComponent>()) {
companionComponent.CreateCompanionComponent(ecb, e);
}
}
}
public partial class SyncTransformSystem : SystemBase {
protected override void OnUpdate() {
foreach ((RefRO<LocalTransform> localTransform, CompanionObject companionObject)
in SystemAPI.Query<RefRO<LocalTransform>, CompanionObject>()) {
SyncTransform(companionObject.GameObject, localTransform.ValueRO);
}
}
void SyncTransform(GameObject companionObject, in LocalTransform localTransform) {
companionObject.transform.position = localTransform.Position;
companionObject.transform.rotation = localTransform.Rotation;
companionObject.transform.localScale = Vector3.one * localTransform.Scale;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment