Search Unity

Possible to anchor LineRenderer positions to GameObjects?

Discussion in '2D' started by GrayLightGames, Aug 20, 2019.

  1. GrayLightGames

    GrayLightGames

    Joined:
    Jan 14, 2015
    Posts:
    30
    I'm creating a 2D game and I have a number of game objects connected by lines. It would be really helpful if I could use LineRenderers to connect them. Meaning, I link a position of a line renderer to a game object instead of manually defining a vector, and when I move the object, the line position follows it and the line is adjusted.

    Is this currently possible using out-of-the-box Unity functionality? I don't believe so but I'd happy to be shown wrong. I'm sure there is an editor scripting solution, but it seems like adding it to the core functionality would double the usefulness of LineRenderer for a small effort.

    Thanks!
     
  2. Sluggy

    Sluggy

    Joined:
    Nov 27, 2012
    Posts:
    989
    As you suggest, the effort is minimal. And it can be done using scripts.

    However, the cost of adding such a functionality directly to the renderer itself would be incalcuable. It means that extra information would have to be carried around for every line renderer used in every project forever. So in general, it is usually the case that the minimum information needed to get the job done is what's used so as not to force potentially costly extras on to everyone else that doesn't require it.

    Just figured I'd explain the reasoning behind such descions. :)
     
  3. GrayLightGames

    GrayLightGames

    Joined:
    Jan 14, 2015
    Posts:
    30
    Thanks for the reply, nice to have some extra context and your point is well taken... at the same time, how much extra information are we talking? A flag that specifies vectors or gameobjects doesn't seem cumbersome to add to the line renderer... even at position level granularity seems reasonable to me. Could even separate it out into its own inheriting child object, Attachable Line Renderer. That would insulate all the other Line Renderers that don't need the functionality. The lighting functionality on the renderer is irrelevant to me, and there's a ton of stuff in the particle systems that I'll never use. This makes me think the Unity devs have a way of including functionality without burdening projects that don't use it.

    That said, if I'm the only person looking for this, you're definitely right... no need to bloat the editor if there isn't demand. My project is pretty small scale, which may be narrowing my perspective to not consider that other projects are using mass quantities of line renderers/positions... just seems like folks making more basic 2D games like myself could benefit from a simpler Line Renderer object with this feature on it.

    Just to clarify, the objects I'm talking about don't move at runtime. It's a level select screen for a puzzle game. I'm just looking for something to allow me to move objects around my scene and not have to manually update the lines after moving them. So what I'm looking for wouldn't need to impact runtime performance or anything like that.

    Guess if I have time I'll try my hand at some editor scripting... I've been avoiding learning about that for too long perhaps :)
     
  4. GrayLightGames

    GrayLightGames

    Joined:
    Jan 14, 2015
    Posts:
    30
    This was actually quite easy to do... just add the following script to your line renderer object (or its own object for that matter as long as you link the line renderer properly). Any position on your line renderer will follow a corresponding game object that you link in the attachedObjects list. If you want one of the positions on your line to be fixed to a manual vector, leave the corresponding gameobject null.

    To be extra efficient, you can disable the component when you're not using it. Simple enough.

    Code (CSharp):
    1. //Anchors Line Renderer positions to corresponding GameObjects in the Unity Editor
    2. [ExecuteInEditMode]
    3. public class LineAnchorer : MonoBehaviour
    4. {
    5.     public List<GameObject> attachedObjects;
    6.     public LineRenderer lineRenderer;
    7.  
    8. #if UNITY_EDITOR
    9.     void Update()
    10.     {
    11.         if (Application.isEditor && !Application.isPlaying)
    12.         {
    13.             for (int i = 0; i < attachedObjects.Count; i++)
    14.             {
    15.                 if (i < lineRenderer.positionCount && attachedObjects != null)
    16.                 { lineRenderer.SetPosition(i, attachedObjects.transform.localPosition); }
    17.             }
    18.         }
    19.     }
    20. #endif
    21. }
     
    emredesu and Sluggy like this.
  5. GrayLightGames

    GrayLightGames

    Joined:
    Jan 14, 2015
    Posts:
    30
    PS If your Line Renderer and anchor objects have different parents, then the set position line should be:
    Code (CSharp):
    1. { lineRenderer.SetPosition(i, transform.InverseTransformPoint(attachedObjects[i].transform.position)); }
     
  6. Sluggy

    Sluggy

    Joined:
    Nov 27, 2012
    Posts:
    989
    Glad you got it working! :D

    The thing is, when designing systems that can be used in a large variety of ways by a large user-base every piece of data has to be very carefully considered. It might not seem like much to add that extra array of Transforms to the component, but what happens when someone needs to use this at scale? What if they need one-hundred LineRenderers. One-thousand? One-million? That info adds up very quickly.

    For example, eight extra bytes for the array pointer, and then eight more for each entry in that array to reference a Transform component might not seem like a lot. But what happens when we have 1000 active entities in our game that need this? Well, that's at least eight kilobytes of ram just for the array pointer itself. That doesn't even include the actual data in the arrays or the extra padding that might be placed on the object to get it to the next 64-bit boundary. Now, this day and age it's pretty easy to overlook 8k of memory as being irrelevant when we have gigs of it sitting around. But in terms of performance, memory access time is the biggest bottleneck on modern consumer computers. The trick to avoiding issues is to make your data as cache friendly as you can. Which means you want your data to be as small and sequential as you can possibly make it. Using pointers to random locations in memory and using generally bloated objects are exactly the opposite of cache friendly. Level 1 cache is usually only around 1 meg and your data sets usually needs to be *much* smaller than that to work effectively with it.

    Now to be fair, not all, or even most games will likely run into issues with this. But as developers of a general purpose engine that needs to perform well in any imaginable scenario, it's important for the devs at Unity to think very carefully about how they design their systems and the data they rely on. And as you've seen, it's not much extra work for a game dev that needs such specific behaviour to add it themselves.
     
    abdullah17053 likes this.