Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Question How to force a deep copy of lineRenderer.GetPositions ?

Discussion in 'Scripting' started by exitshadow, Mar 23, 2023.

  1. exitshadow

    exitshadow

    Joined:
    Nov 28, 2020
    Posts:
    7
    Hi there. Here it is: I have a game with snakes represented by lines, rendered by a lineRenderer. So far, so good.

    My problem comes with the fact that, in the editor, I set up their positions with a SmoothDamp that runs in Edit mode. I want to be able to able to correctly position each snake in a way that is pleasant aesthetically, save them in a Scriptable Object, and then use and reuse those positions to initialize the snake before it starts to use its nav mesh.

    However: the positions are always reset (because my script works in Edit mode), and that reset does extend to the scriptable... because the variables of the lineRenderer are apparently passed by reference and not value!

    I tried to force a deep copy by instancing a buffer new Vector3, but it’s just the same.

    I guess I will have to store the lineRenderer as a prefab... Then instantiate that prefab and operate on it at runtime, so the reference hassle doesn’t happen. However, I find it a bit surprising and annoying.

    Which makes me think: is there a way that I’m not aware of that would allow to deep copy these values?
     
  2. Adrian

    Adrian

    Joined:
    Apr 5, 2008
    Posts:
    1,051
    The positions are copied to the array you pass to GetPositions, it's impossible for the positions themselves to be passed by reference. If you reuse the same array and share it between different scripts, then one call to GetPositions can overwrite the values another script is expecting to stay the same. However, if you set this array on a scriptable object and you get a domain reload in the editor, the array will be serialized and then recreated from the serialized data – the connection of the data to the line renderer is long lost at that point.

    Maybe what you're seeing is the changes to the scriptable object not being saved properly? You either need to use the SerializedObject API for Unity to handle everything automatically, or you need to handle it yourself, calling the necessary Undo methods (recommended) / EditorUtility.SetDirty.
     
    Bunny83 and Kurt-Dekker like this.
  3. exitshadow

    exitshadow

    Joined:
    Nov 28, 2020
    Posts:
    7
    Yes! In fact, this is exactly what happened. I ended up making a buffer copy and was certain everything was being passed by value yet still not being written to disk. However, I still am very confused about how SetDirty does effectively work. The API reference really doesn’t state anything more than the fact that it exists. :rolleyes:

    Since I am quite in a hurry I ended up splitting the script in two, one that takes care of the snake’s positioning by just keeping the positions inside of the Line Renderer itself, and another one that will instantiate that GameObject and deactivating the original, then proceed on all real-time operations. It is actually a bit cleaner to have persistent data and runtime data being treated by two different objects rather than a mega script that works both in the editor and in game mode.

    Yet I should investigate SetDirty more because I guess not all situations will have a workaround.
     
  4. Adrian

    Adrian

    Joined:
    Apr 5, 2008
    Posts:
    1,051
    SetDirty is really the last resort. In most cases, you should use Undo or SerializedObject, which will handle the dirty state but also other cases (e.g. changing values on prefabs is especially complex and you'd definitely want to use SerializedObject).

    The dirty state is an optimization in the editor. Since you're working with the editor objects directly and can e.g. change fields on any object you want, Unity has no way of knowing when an object has been modified and needs to be saved to disk. Saving everything or checking all objects for changes every tick would take too long, so instead Unity relies on modified objects to be marked dirty.