Search Unity

Can game objects get access to component data?

Discussion in 'Entity Component System' started by RuanJacobz, Oct 8, 2019.

  1. RuanJacobz

    RuanJacobz

    Joined:
    Jan 24, 2014
    Posts:
    59
    I'm currently thinking of my next game and I thought it could have a very clean architecture if I could do a kind of MVVM(Model, View, Viewmodel) approach involving entities.

    I'd like to have entities and systems always running in the background, and just represent some of these entities in the foreground (ie on screen) with game objects.

    For example, there may be a health component.
    And I have a health bar game object acting as the "view" of the health.
    Can I access the data on the component from a monobehaviour on a gameobject?
     
  2. alexandre-fiset

    alexandre-fiset

    Joined:
    Mar 19, 2012
    Posts:
    715
    I think you should think the other way around.

    What you need is a system that grabs your health data and applies it to your health display. No component should do anything other than holding data.
     
    RuanJacobz likes this.
  3. RuanJacobz

    RuanJacobz

    Joined:
    Jan 24, 2014
    Posts:
    59
    Hey, I think you're right.
    It's probably best if I design in such a way that game objects never actually need to "know" about components or systems.
    Ty Alexandre
     
  4. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    Here's a script that would give you an idea of how to do that. This is a script I put on my game camera, because it can't be converted to DOTS yet, but I wanted the camera controls to all be coded in DOTS

    This script allows you to either copy pos/rot from the DOTS world to the GameObject world, or vice-versa. But it is very inefficient

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using Unity.Entities;
    4. using Unity.Transforms;
    5. using UnityEngine;
    6.  
    7. public class TransformEntityBridge : MonoBehaviour
    8. {
    9.     public bool Write = false;
    10.     public Entity BridgedEntity;
    11.     public EntityManager EntityManager;
    12.  
    13.     private Transform _transform;
    14.  
    15.     private void Start()
    16.     {
    17.         _transform = this.transform;
    18.     }
    19.  
    20.     void Update()
    21.     {
    22.         if (Write)
    23.         {
    24.             EntityManager.SetComponentData<Translation>(BridgedEntity, new Translation() { Value = _transform.position });
    25.             EntityManager.SetComponentData<Rotation>(BridgedEntity, new Rotation() { Value = _transform.rotation });
    26.         }
    27.         else
    28.         {
    29.             _transform.position = EntityManager.GetComponentData<Translation>(BridgedEntity).Value;
    30.             _transform.rotation = EntityManager.GetComponentData<Rotation>(BridgedEntity).Value;
    31.         }
    32.     }
    33. }
    34.  
     
    Neiist, Gekigengar, Hexodust and 2 others like this.
  5. RuanJacobz

    RuanJacobz

    Joined:
    Jan 24, 2014
    Posts:
    59
    Hey there Phil, thank you so much. This does indeed answer my question about interaction between the two worlds. I just wasn't sure if it's feasible, but seems like it definitely is!
    And even if it's inefficient I should be ok.
    The game I plan to work on won't be anything impossible to achieve with normal game objects.
    I just really like the strict and straightforward way of coding in ECS.

     
  6. Phr34z3r

    Phr34z3r

    Joined:
    Mar 5, 2015
    Posts:
    6
    Maybe thats better for GameObject<->Entity bridges:
    Code (CSharp):
    1.  
    2.         EntityManager.AddComponentObject( BridgedEntity, this.transform );
    3.         EntityManager.AddComponentData( BridgedEntity, new CopyTransformFromGameObject() { } );
    4.         EntityManager.AddComponentData( BridgedEntity, new CopyTransformToGameObject() { } );
     
  7. alexandre-fiset

    alexandre-fiset

    Joined:
    Mar 19, 2012
    Posts:
    715
    Again I'd strongly advise not adding any more logic to monobehaviours.

    What you need here is something like:
    • Hero Entity (or Player or whatever)
      • Hero IComponentData
      • Health IComponentData
    • HealthBar Entity
      • HealthBar ComponentData
      • Image ComponentObject
    Then have a HealthBarUpdateSystem use GetSingletonEntity<Hero> to get the entity, then EntityManager.GetComponentData<Health>(entity) to get the health, then set Image size.x according to the health value.

    In this scenario, no monobehaviour is responsible for updating anything, which is what you want in DOTS. Once a DOTS UI arrives, the only thing you need to do is change the authoring part and nothing else. So your code becomes reusable and much more maintainable :)

    As for the authoring, your HealthBar GameObject could just have an Entity child, on which you would have a HealthBarAutoring IConvertGameObjectToEntity that adds both the image and HealthBar components to the entity.
     
    Yanne065 likes this.