Search Unity

How to reference sprites in component data?

Discussion in 'Entity Component System' started by Deleted User, Aug 16, 2019.

  1. Deleted User

    Deleted User

    Guest

    I have a component like this:
    Code (CSharp):
    1.     [InternalBufferCapacity(Capacity)]
    2.     public struct PlayerConfig : IBufferElementData
    3.     {
    4.         public const int Capacity = 8;
    5.  
    6.         public Entity Prefab;
    7.         public Sprite Avatar;
    8.     }
    When I spawn a player, I want to show its avatar in UI that is injected using conversion workflow. But unity complains about Avatar field since it's not blittable. How can I work around this?
     
  2. elcionap

    elcionap

    Joined:
    Jan 11, 2016
    Posts:
    138
    Sprite is a class and don't inherits UnityEngine.Component, so cannot be used in IComponentData, IBufferElementData or attached to a Entity. For your case, you can configure hybrid prefab with injection to create a hybrid entity using a MonoBehaviour to hold the Sprite. Then reference this hybrid entity in your player entity using some component/dynamic buffer.

    This code have a lot more than it needs (and some implicit assumptions), but I think it can give you some grasps about what I said:

    Code (CSharp):
    1. public struct AvatarReference : IComponentData {
    2.     public Entity Value;
    3. }
    4.  
    5. [RequiresEntityConversion, DisallowMultipleComponent]
    6. public class AvatarBehaviour : MonoBehaviour, IConvertGameObjectToEntity {
    7.     public Sprite Sprite;
    8.    
    9.     public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) {
    10.         // When referenced by a convert and destroy entity, the prefab will strip all component objects from entity
    11.         // This is a hack to keep this component object
    12.         dstManager.AddComponentObject(entity, this);
    13.     }
    14. }
    15.  
    16. [RequiresEntityConversion, DisallowMultipleComponent]
    17. public class PlayerBehaviour : MonoBehaviour, IDeclareReferencedPrefabs, IConvertGameObjectToEntity {
    18.     public AvatarBehaviour Avatar;
    19.    
    20.     public void DeclareReferencedPrefabs(List<GameObject> referencedPrefabs) {
    21.         Assert.IsNotNull(Avatar);
    22.         referencedPrefabs.Add(Avatar.gameObject);
    23.     }
    24.    
    25.     public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) {
    26.         dstManager.AddComponentData(entity, new AvatarReference {
    27.             Value = conversionSystem.GetPrimaryEntity(Avatar)
    28.         });
    29.     }
    30. }
    31.  
    32. public class ShowAvatarSystem : ComponentSystem {
    33.     protected override void OnCreate() {
    34.         base.OnCreate();
    35.        
    36.         RequireSingletonForUpdate<ShowAvatarWindow>();
    37.         RequireSingletonForUpdate<AvatarWindow>();
    38.     }
    39.    
    40.     protected override void OnUpdate() {
    41.         var showAvatarWindowEntity = GetSingletonEntity<ShowAvatarWindow>();
    42.         var avatarReference = EntityManager.GetComponentData<AvatarReference>(showAvatarWindowEntity);
    43.         var avatar = EntityManager.GetComponentObject<AvatarBehaviour>(avatarReference.Value);
    44.         var avatarWindowEntity = GetSingletonEntity<AvatarWindow>();
    45.         var avatarWindow = EntityManager.GetComponentObject<AvatarWindowBehaviour>(avatarWindowEntity);
    46.        
    47.         avatarWindow.SetAvatar(avatar.Sprite);
    48.        
    49.         EntityManager.RemoveComponent(showAvatarWindowEntity, typeof(ShowAvatarWindow));
    50.     }
    51. }
    52.  
    53. EntityManager.AddComponent(playerEntity, typeof(ShowAvatarWindow));
    54.  
    []'s
     
    MostHated and Deleted User like this.
  3. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    One correction, they can be attached to an entity

    EntityManager.AddComponentObject(Entity, object)
    EntityManager.GetComponentObject<T>(Entity entity)

    Can't be used in burst obviously.

    -edit-

    to actually answer original question. I tend to just have a collection of, in this case sprites, and store an index on a component data instead.

    I like doing this, and did even before I started using ECS because it gives you a lot flexibility in the future to easily allows adding localization, events etc. For example maybe I want to run a Christmas event. I can just load a different set of sprites for the holiday season without having to change any code. I can even push this with asset bundles (or new addressables) without even having to submit to a stores.
     
    Last edited: Aug 17, 2019
    Deleted User likes this.