Search Unity

Prefab Mode changes only one of several prefab copies until the others are manually selected

Discussion in 'Prefabs' started by kalahario, Jan 16, 2019.

  1. kalahario

    kalahario

    Joined:
    Jun 13, 2017
    Posts:
    31
    I am creating bezier curves with the following code and made a prefab of my Bezier curve game object.
    I added a few copies of the prefab to my scene. When I open the original prefab in prefab mode (I am using Unity 2019.1.0a8) and adjust any of the points it only affects one of the prefabs, the changes are not recognised in the scene view till I select the other objects manually.

    I added 'SceneView.RepaintAll();' after calling 'path.MovePoint(i, newPos);' in the 'Draw()' method but it still doesn't update the others.
    Could it be that I haven't serialised by variables correctly? How can I solve this?

    Path

    Code (CSharp):
    1. [System.Serializable]
    2. public class Path {
    3.  
    4. [SerializeField, HideInInspector]
    5. List<Vector2> points;
    6.  
    7. [SerializeField, HideInInspector]
    8. public bool isContinuous;
    9.  
    10. public Path(Vector2 centre)
    11. {
    12.     points = new List<Vector2>
    13.     {
    14.         centre+Vector2.left,
    15.         centre+(Vector2.left+Vector2.up)*.5f,
    16.         centre + (Vector2.right+Vector2.down)*.5f,
    17.         centre + Vector2.right
    18.     };
    19. }
    20.  
    21. public Vector2 this[int i]
    22. {
    23.     get
    24.     {
    25.         return points[i];
    26.     }
    27. }
    28.  
    29. public int NumPoints
    30. {
    31.     get
    32.     {
    33.         return points.Count;
    34.     }
    35. }
    36.  
    37. public int NumSegments
    38. {
    39.     get
    40.     {
    41.         return (points.Count - 4) / 3 + 1;
    42.     }
    43. }
    44.  
    45. public void AddSegment(Vector2 anchorPos)
    46. {
    47.     points.Add(points[points.Count - 1] * 2 - points[points.Count - 2]);
    48.     points.Add((points[points.Count - 1] + anchorPos) * .5f);
    49.     points.Add(anchorPos);
    50. }
    51.  
    52. public Vector2[] GetPointsInSegment(int i)
    53. {
    54.     return new Vector2[] { points[i * 3], points[i * 3 + 1], points[i * 3 + 2], points[i * 3 + 3] };
    55. }
    56.  
    57. public void MovePoint(int i, Vector2 pos)
    58. {
    59.  
    60.     if (isContinuous)
    61.     {
    62.  
    63.         Vector2 deltaMove = pos - points[i];
    64.         points[i] = pos;
    65.  
    66.         if (i % 3 == 0)
    67.         {
    68.             if (i + 1 < points.Count)
    69.             {
    70.                 points[i + 1] += deltaMove;
    71.             }
    72.             if (i - 1 >= 0)
    73.             {
    74.                 points[i - 1] += deltaMove;
    75.             }
    76.         }
    77.         else
    78.         {
    79.             bool nextPointIsAnchor = (i + 1) % 3 == 0;
    80.             int correspondingControlIndex = (nextPointIsAnchor) ? i + 2 : i - 2;
    81.             int anchorIndex = (nextPointIsAnchor) ? i + 1 : i - 1;
    82.  
    83.             if (correspondingControlIndex >= 0 && correspondingControlIndex < points.Count)
    84.             {
    85.                 float dst = (points[anchorIndex] - points[correspondingControlIndex]).magnitude;
    86.                 Vector2 dir = (points[anchorIndex] - pos).normalized;
    87.             points[correspondingControlIndex] = points[anchorIndex] + dir * dst;
    88.                 }
    89.             }
    90.         }
    91.     }
    92.  
    93.     else {
    94.          points[i] = pos;
    95.     }
    96. }

    PathCreator

    Code (CSharp):
    1. public class PathCreator : MonoBehaviour {
    2.  
    3. [HideInInspector]
    4. public Path path;
    5.  
    6.  
    7. public void CreatePath()
    8. {
    9.     path = new Path(transform.position);
    10. }
    11. }  

    PathEditor

    Code (CSharp):
    1. [CustomEditor(typeof(PathCreator))]
    2. public class PathEditor : Editor {
    3.  
    4. PathCreator creator;
    5. Path path;
    6.  
    7. public override void OnInspectorGUI()
    8. {
    9.     base.OnInspectorGUI();
    10.     EditorGUI.BeginChangeCheck();
    11.  
    12.     bool continuousControlPoints = GUILayout.Toggle(path.isContinuous, "Set Continuous Control Points");
    13.     if (continuousControlPoints != path.isContinuous)
    14.     {
    15.         Undo.RecordObject(creator, "Toggle set continuous controls");
    16.         path.isContinuous = continuousControlPoints;
    17.     }
    18.  
    19.     if (EditorGUI.EndChangeCheck())
    20.     {
    21.         SceneView.RepaintAll();
    22.     }
    23. }
    24.  
    25. void OnSceneGUI()
    26. {
    27.     Input();
    28.     Draw();
    29. }
    30.  
    31. void Input()
    32. {
    33.     Event guiEvent = Event.current;
    34.     Vector2 mousePos = HandleUtility.GUIPointToWorldRay(guiEvent.mousePosition).origin;
    35.  
    36.     if (guiEvent.type == EventType.MouseDown && guiEvent.button == 0 && guiEvent.shift)
    37.     {
    38.         Undo.RecordObject(creator, "Add segment");
    39.         path.AddSegment(mousePos);
    40.     }
    41. }
    42.  
    43. void Draw()
    44. {
    45.  
    46.     for (int i = 0; i < path.NumSegments; i++)
    47.     {
    48.         Vector2[] points = path.GetPointsInSegment(i);
    49.         Handles.color = Color.black;
    50.         Handles.DrawLine(points[1], points[0]);
    51.         Handles.DrawLine(points[2], points[3]);
    52.         Handles.DrawBezier(points[0], points[3], points[1], points[2], Color.green, null, 2);
    53.     }
    54.  
    55.     Handles.color = Color.red;
    56.     for (int i = 0; i < path.NumPoints; i++)
    57.     {
    58.         Vector2 newPos = Handles.FreeMoveHandle(path[i], Quaternion.identity, .1f, Vector2.zero, Handles.CylinderHandleCap);
    59.         if (path[i] != newPos)
    60.         {
    61.             Undo.RecordObject(creator, "Move point");
    62.             path.MovePoint(i, newPos);
    63.         }
    64.     }
    65. }
    66.  
    67. void OnEnable()
    68. {
    69.     creator = (PathCreator)target;
    70.     if (creator.path == null)
    71.     {
    72.         creator.CreatePath();
    73.     }
    74.     path = creator.path;
    75. }
    76. }
     
    Last edited: Jan 17, 2019
  2. kalahario

    kalahario

    Joined:
    Jun 13, 2017
    Posts:
    31
    I would really appreciate some help
     
  3. MatthieuPr

    MatthieuPr

    Joined:
    May 4, 2017
    Posts:
    56
  4. SteenLund

    SteenLund

    Unity Technologies

    Joined:
    Jan 20, 2011
    Posts:
    639
    I think you simply need to recalculate the spline in Awake.

    When you have multiple instances of a prefab in the scene and you then modify the prefab asset, all instances are merged with the asset and will get Awake called.
     
  5. kalahario

    kalahario

    Joined:
    Jun 13, 2017
    Posts:
    31
    I added an Awake method that recalculates the curve, but it didn't solve my issue.

    Code (CSharp):
    1. void Awake()
    2.     {
    3.         DrawBezierCurve();
    4.     }

    After giving it some further thought, I realised that I forgot to mention that I am rotating all but one of the prefab instances in the scene before trying to adjust the prefab. So I deleted and them and recopied them without rotation and realised that all of the copies are updating. That basically means the rotation is causing the issue. How can I resolve this?
     
  6. SteenLund

    SteenLund

    Unity Technologies

    Joined:
    Jan 20, 2011
    Posts:
    639
    It is hard to say, not sure where things are failing. Could you please file a bug report and attach a small project with steps to reproduce.
     
  7. kalahario

    kalahario

    Joined:
    Jun 13, 2017
    Posts:
    31
    Okay, I'll file the bug report. I was just wondering, how long it could possibly take to get a reply or the issue addressed.

    Also is there a prefabUtility function that can "manually" force instances to update (because when I select the instances in hierarchy window they update)? If there is, where should I place it in my code?
     
  8. SteenLund

    SteenLund

    Unity Technologies

    Joined:
    Jan 20, 2011
    Posts:
    639
    Instances are force updated in the scene when you save the prefab asset.
    Without a project it is hard for me to actually see what is happening, it is hard to tell what is going wrong.
    I am confident that the instances are updated, but your are missing something in your script that recalculates/redraws the spline.
    You can verify this by changing some other property in the prefab. e.g try to disable a GameObject or component.
     
  9. kalahario

    kalahario

    Joined:
    Jun 13, 2017
    Posts:
    31
    I just sent a bug report with a sample project reproducing my issue.
     
  10. kalahario

    kalahario

    Joined:
    Jun 13, 2017
    Posts:
    31
    Still trying to get this solved, will appreciate some help
     
  11. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    If you post the case number of the bug report you made, it will be easier for us to find it.
     
    kalahario likes this.
  12. kalahario

    kalahario

    Joined:
    Jun 13, 2017
    Posts:
    31
    The bug report Case Number is 1118349
     
  13. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    I took a quick look and could see that your Prefab instances don't update at all if the Inspector is set to Debug mode. So something in your custom editor is causing the splines to be updated upon selection.

    I also tried having some Prefabs that are just LineRenderers without your script, and then all instances are synced with the Prefab immediately.

    You'll have to figure out your own scripts yourself. It's not trivial for us to see exactly what those scripts are doing.
     
  14. kalahario

    kalahario

    Joined:
    Jun 13, 2017
    Posts:
    31
    Thanks. I'll keep at it.