Search Unity

Custom Inspector resets ObjectField-data when play the scene, but Default Inspector doesn't

Discussion in 'Immediate Mode GUI (IMGUI)' started by blacksheepwall, May 1, 2015.

  1. blacksheepwall

    blacksheepwall

    Joined:
    Mar 19, 2015
    Posts:
    3
    So far I've searched out some solution about this issue:
    1,Make the Object Serializable.
    2,Use the SetDirty method.

    But I'm still confused because the Default Inspector can set any GameObject with a single line in Script :"public GameObject xxx;"

    Any difference between the ObjectField in Default Inspector and Custom Inspector?

    How I can make a Custom Inspect Object field that can set any GameObject on it without reset when playing?
     
    CloudyVR likes this.
  2. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,689
  3. blacksheepwall

    blacksheepwall

    Joined:
    Mar 19, 2015
    Posts:
    3
    yeah, I've picked up the key part of the code, the ObjectField "noteProto" is reset when playing, and the noteProto is just a prefab Object with nothing special.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. [CustomEditor(typeof(NoteSpawner))]
    7. public class NoteSpawnerEditor : Editor
    8. {
    9.     NoteSpawner spawner;
    10.  
    11.     GameObject noteProto;
    12.  
    13.  
    14.     // Use this for initialization
    15.     void Start()
    16.     {
    17.     }
    18.  
    19.     // Update is called once per frame
    20.     void Update()
    21.     {
    22.  
    23.     }
    24.  
    25.     void OnEnable()
    26.     {
    27.         spawner = (NoteSpawner)target;
    28.     }
    29.  
    30.     public override void OnInspectorGUI()
    31.     {
    32.         noteProto = (GameObject)EditorGUILayout.ObjectField("Note proto", noteProto, typeof(GameObject), false);
    33.         if (noteProto != null)
    34.             spawner.noteProto = noteProto;
    35.     }
    36. }
    37.  
     
  4. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,689
    Try changing line 32 of the code above to:
    Code (csharp):
    1. noteProto =(GameObject)EditorGUILayout.ObjectField("Note proto", spawner.noteProto, typeof(GameObject), false);
    Better yet, I would consider getting rid of "GameObject noteProto;" (line 11) and use this:
    Code (csharp):
    1. spawner.noteProto =(GameObject)EditorGUILayout.ObjectField("Note proto", spawner.noteProto, typeof(GameObject), false);
    This will let you assign null to spawner.noteProto, for example if you want to clear the field.

    The original problem is that the editor script's noteProto starts null. You could always set "noteProto = spawner.noteProto" in OnEnable(), but it's probably better to omit it entirely.
     
    ElTeby likes this.
  5. blacksheepwall

    blacksheepwall

    Joined:
    Mar 19, 2015
    Posts:
    3
    Yeah it works, and i've learned sth form this issue. Thank you TonyLi
     
  6. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,689
    Happy to help!
     
  7. AlexTemina

    AlexTemina

    Joined:
    Feb 19, 2014
    Posts:
    44
    Sorry to bump this, but I'm having the same problem and I use the direct variable:
    Code (CSharp):
    1.     private void OnGUI( )
    2.     {
    3.         minSize = new Vector2( 300, 150 );
    4.  
    5.         _MakeSpaces( 3 );
    6.  
    7.         _bake_brush = EditorGUILayout.Toggle( "Bake brush", _bake_brush );
    8.         _bake_fog = EditorGUILayout.Toggle( "Bake fog", _bake_fog );
    9.         _auto_update = EditorGUILayout.Toggle( "auro update", _auto_update);
    10.         TextureBaker.fogBakerMaterial = (Material)EditorGUILayout.ObjectField( "FogBaker material", TextureBaker.fogBakerMaterial, typeof( Material ), false );
    11.  
    12. ...
    Why TextureBaker.fogBakerMaterial goes to none when building the project or pressing "play" ?
    The other 3 toggle variable keeps state, so only this material objct is reseted.
     
  8. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,689
    When Unity switches to play mode, it serializes your window, destroys it, and creates a new window with the serialized data. Only public fields, and private fields marked [SerializeField], are serialized. Everything else is reset to their default values. In addition, scene objects will be different in play mode because Unity serializes the scene and creates it new in play mode. So if your editor window has a reference to something in the scene, that reference will no longer be valid in play mode.

    See Unity Serialization for more info.
     
  9. AlexTemina

    AlexTemina

    Joined:
    Feb 19, 2014
    Posts:
    44
    that material is a material that exists in my project, outside. And it+s a public static material. So given your comments it should work.
    anyway I tried putting Serialiable and SerializeField, but it doesn't work.
     
  10. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,689
    Can you post more code? What's TextureBaker? Could another part of the script be assigning a value to TextureBaker.forBakerMaterial that is no longer valid? Also make sure to read through the Unity Serialization link above. It probably contains an answer to your question. Or check this post and keep a reference to the material's instance ID.
     
  11. pokelocos

    pokelocos

    Joined:
    Nov 9, 2015
    Posts:
    54
    Hello I have the same problema (apparently), but I use UI buider and UI toolkit, this is a bit of my code
    Code (CSharp):
    1. var grassField = root.Q<ObjectField>("GrassField");
    2.         grassField.objectType = typeof(RuleTile);
    3.         sizeField.RegisterCallback<ChangeEvent<RuleTile>>(v => {
    4.             comp.grass = v.newValue;
    5.         });
    I don't know how to solve this from ui bulder, when starting playmode the values of the cmaps are reset, I don't know if it's an error in how I'm building the object or it's a RuleTile error that can't be used (I don't think so), I'm using the unity tilemap2d package ruletile.