0
\$\begingroup\$

In unity we can have different instances of a prefab with different properties. Unity represents the overridden property with bold characters. This works fine when manually change the value of prefab instance. But when I do it using a editor script, it do not turn bold and the property value changes to the source prefab when I play the game.

Here is an example of the code:

using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(testScript))]
public class editor : Editor {
    public override void OnInspectorGUI(){
        DrawDefaultInspector ();
        testScript scrt= (testScript)target;
        if (GUILayout.Button ("button")) {
            scrt.test();
        }
    }
}

.

using UnityEngine;
public class testScript: MonoBehaviour {
   test(){
       gameManager  =GameObject.Find("GameManager");
       gameManager.GetComponent<gameManager>().arr = new GameObject[3];
   }
}

.

using UnityEngine;
public class gameManger:MonoBehaviour{
    public GameObject[] arr;
}

The arr array in gamemanager class is not overridden and it changes to the source prefab value on play.

EDIT:

actual function called from editor script

    public void assignPortalPass(){
    GameObject gameManagerObj = GameObject.Find ("Game Manager");
    gameManager gameManagerScript = gameManagerObj.GetComponent<gameManager> (); 
    Transform passed = GameObject.Find ("passed").transform;
    int noOfChild = passed.childCount;
    if (noOfChild != gameManagerScript.noOfPortals) {
        Debug.LogError ("Check passed objects and noOfPortals (class gameManager) because both values are different");
        return;
    }
    Undo.RecordObject(gameManagerObj, "Made some changes to gameManager");
    //as suggested by the answer

    gameManagerScript.portalPass = new GameObject[noOfChild];
    for (int i = 0; i < noOfChild; i++) {
        gameManagerScript.portalPass [i] = passed.GetChild (i).gameObject;

    }
}

}

\$\endgroup\$
1
  • \$\begingroup\$ You're telling the engine "I'm going to make some changes to gameManagerObj" but then proceed to modify gameManagerScript instead. These are two different objects, even if they're referenced from one another. You have to call RecordObject with the same UnityEngine Object that you're modifying - in this case, the component. \$\endgroup\$
    – DMGregory
    Commented Nov 25, 2017 at 7:48

1 Answer 1

1
\$\begingroup\$

Unity doesn't get any notification when you change properties through script, so you have to tell it you've changed something using methods like Undo.RecordObject(). This logs the change so your script's work can...

  • Display the same as manual changes in the Inspector UI
  • Work correctly with Undo/Redo in the Editor
  • Persist into game when you hit Play, and restore itself back to the value you set in Edit Mode after you exit Play Mode
  • Save into your scene file / assets folder so your changes aren't lost when you close Unity

Here's what the Unity docs have to say about this method:

Records any changes done on the object after the RecordObject function.

Almost all property changes can be recorded with this function. The transform parent, AddComponent, object destruction can not be recorded with this function, for that you should use the dedicated functions.

Internally this will create a temporary copy of the object's state and at the end of the frame Unity will diff the state and thus detect what exactly has changed. The changed properties are then recorded on the undo stack. If nothing has actually changed (Binary exact comparison is used for all properties), no undo operation will be stored on the stack

It's pretty simple to use:

void ThisIsMyMethodThatChangesAnObject(GameObject myObject) {

    // Tell Unity we're going to modify this object.
    // Leave a text description so we know what the change was.
    Undo.RecordObject(myObject, "Made some changes to myObject");

    // Okay, now make those changes...
    // Code that changes the object goes here.
    // eg. myObject.name = "Bob";

    //---------------------------

    // Oh, I also want to change a component on the object.
    var component = myObject.GetComponent<SomeKindaComponent>();

    // We need to tell Unity we're changing the component object too.
    Undo.RecordObject(component, "Changing the component on myObject");

    // Now we change the component.
    // Code to change the component goes here.
    // eg. component.SetFloofiness(11.0);
}
\$\endgroup\$
5
  • \$\begingroup\$ How to use this method? Can you please explain ? \$\endgroup\$
    – coder_86
    Commented Nov 25, 2017 at 6:30
  • \$\begingroup\$ And why this works fine when I remove the prefab? \$\endgroup\$
    – coder_86
    Commented Nov 25, 2017 at 6:33
  • \$\begingroup\$ Thanks for your answer but I don't know why this is not working \$\endgroup\$
    – coder_86
    Commented Nov 25, 2017 at 6:54
  • \$\begingroup\$ It would be helpful to understand why changes work fine if they are being made to behaviors that are not part of a prefab instance. But somehow prefab instances do not recognize the changes. That is really confusing. \$\endgroup\$ Commented Apr 27, 2022 at 22:42
  • \$\begingroup\$ If you'd like to ask a question about that, the "Ask Question" button is prominently displayed at the top of the page. \$\endgroup\$
    – DMGregory
    Commented Apr 28, 2022 at 3:25

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .