Search Unity

Entity Visualizer OnDrawGizmos

Discussion in 'Entity Component System' started by RoughSpaghetti3211, May 28, 2019.

  1. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,705
    Just a quick question. Im a huge fan on data visualizing in the viewport eg. Debug.DrawLine and OnDrawGizmos to see my data. Is it ok for debugging reasons to get entities into a MonoBehaviour and draw them in OnDrawGizmos, or is there a better way? How would I get entities into an old school MonoBehaviour ? Thanks in advance

    Screen Shot 2019-05-27 at 11.45.32 PM.png


    Code (CSharp):
    1.                
    2.  
    3.                 entityManager = World.Active.EntityManager;
    4.                 entities = entityManager.GetAllEntities(Allocator.Temp);
    5. ...............................
    6.  
    7.  
    8.                 for (int 0 = 1; i < entities.Length; i++)
    9.                 {
    10.                    VertexComponent v = entityManager.GetComponentData<VertexComponent>(entities[i]);
    11.                     Vector3 p = new Vector3(v.position.x, v.position.y, v.position.z);
    12.                     Gizmos.DrawSphere(p, 0.5f);
    13.                 }
    14.  
    Got a feeling im gonna take some heat on this
     
    Last edited: May 28, 2019
  2. ilih

    ilih

    Joined:
    Aug 6, 2013
    Posts:
    1,408
    Create a system with function to draw gizmos or add function to the existing system, then call this function from MonoBehaviour.

    System
    Code (CSharp):
    1.     using Unity.Entities;
    2.     using Unity.Transforms;
    3.     using UnityEngine;
    4.  
    5.     public class GizmoSystem : ComponentSystem
    6.     {
    7.         EntityQuery query;
    8.  
    9.         protected override void OnCreateManager()
    10.         {
    11.             query = GetEntityQuery(ComponentType.ReadOnly<Station>(), ComponentType.ReadOnly<Translation>());
    12.         }
    13.  
    14.         protected override void OnUpdate()
    15.         {
    16.         }
    17.  
    18.         public void OnDrawGizmos()
    19.         {
    20.             Entities.With(query).ForEach((ref Translation translation) => {
    21.                 Gizmos.DrawSphere(translation.Value, 0.5f);
    22.             });
    23.         }
    24.     }
    MonoBehaviour
    Code (CSharp):
    1.     using Unity.Entities;
    2.     using UnityEngine;
    3.  
    4.     public class Gizmo : MonoBehaviour
    5.     {
    6.         GizmoSystem system;
    7.  
    8.         private void Start()
    9.         {
    10.             system = World.Active.GetExistingSystem<GizmoSystem>();
    11.         }
    12.  
    13.         private void OnDrawGizmos()
    14.         {
    15.             if (system != null)
    16.             {
    17.                 system.OnDrawGizmos();
    18.             }
    19.         }
    20.     }
     
    RoughSpaghetti3211 and Razmot like this.
  3. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,705
    Thank you very much, way cleaner and smarter that the Frankenstein visualizer I was building
     
  4. SamOld

    SamOld

    Joined:
    Aug 17, 2018
    Posts:
    333
    There's another way which you might find nicer, although it's a little bit of a hack and I've only done very minimal testing with it, so I don't know how well it holds up.

    Unity provides a DrawGizmo attribute which can be applied to a static method in any class to draw gizmos. We can use it like so.

    Code (CSharp):
    1. static class GizmoInvoker
    2. {
    3.     private static float doneTime;
    4.  
    5.     [DrawGizmo(GizmoType.NonSelected)]
    6.     private static void DrawSystemGizmos(MonoBehaviour obj, GizmoType gizmoType)
    7.     {
    8.         if (Time.time == doneTime) return;
    9.         doneTime = Time.time;
    10.  
    11.         foreach (var world in Unity.Entities.World.AllWorlds)
    12.         foreach (var system in world.Systems)
    13.             if (system is IGizmoDrawing gizmoDrawingSystem) gizmoDrawingSystem.DrawGizmos();
    14.     }
    15. }
    16.  
    17. interface IGizmoDrawing
    18. {
    19.     void DrawGizmos();
    20. }
    This should find all active systems which have the
    IGizmoDrawing
    interface and call the method on each. The reason it's a bit of a hack is that the attribute method is called once for each
    Monobehaviour
    in the scene. We can keep track of the time to make it run only once per frame, but if there are no
    Monobehaviour
    s it won't run.

    If anyone from Unity's reading this, it would be nice to allow the
    DrawGizmo
    attribute to be applied to a method with no parameters and to have it run once per frame.
     
    vanxining likes this.
  5. M_R

    M_R

    Joined:
    Apr 15, 2015
    Posts:
    559
    you can also do something like:
    Code (CSharp):
    1. [DisableAutoCreation]
    2. public class DrawGizmosGroup : ComponentSystemGroup {
    3. DrawGizmoRunner runner
    4. OnCreate() {
    5. runner = new GameObject($"{World.Name} DrawGizmoRunner").AddComponent<DrawGizmoRunner>();
    6. runner.system = this;
    7. Object.DontDestroyOnLoad(runner.gameObject);
    8. }
    9.  
    10. OnDestroy()  => Object.Destroy(runner.gameObject);
    11. }
    12.  
    13. public class DrawGizmoRunner : MonoBehaviour {
    14. internal DrawGizmosGroup system;
    15. OnDrawGizmos() => system.Update();
    16. }
    then your gizmo systems will look like
    Code (CSharp):
    1. [UpdateInGroup(typeof(DrawGizmosGroup))]
    2. public class MyGizmos : ComponentSystem{...code in OnUpdate...}
     
    vanxining, e199 and SamOld like this.
  6. SamOld

    SamOld

    Joined:
    Aug 17, 2018
    Posts:
    333
    I think I've seen advice given by Unity people saying that we should never put any code in a
    ComponentSystemGroup
    , but this does look like a nice way to do it.