0

I wrote some code to add a button to my custom editor in Unity. What I'd like is the following. When I click the button once, a component is added, and when I click again the component is removed. In the simple code below, I just try to print "Add" or "Remove" when clicking the button. I noticed that the variable toggleRigidBody takes the value true but then take the value false right after. It doesn't stay "true" even though I never explicitly change it in the code. The "else if" is never fired. I'm not sure why.

using UnityEditor;
using UnityEngine;
using SS3D.Engine.Inventory;

[CustomEditor(typeof(ContainerController))]
public class ContainerControllerEditor : Editor
{
    private bool toggleRigidBody = false;

    public override void OnInspectorGUI()
    {
        DrawDefaultInspector();
        ContainerController containerController = (ContainerController)target;
        Debug.Log(toggleRigidBody);

        bool buttonPressed = GUILayout.Button("AddAttachedContainer");

        if (buttonPressed && toggleRigidBody == false)
        {
            Debug.Log("Add");
            toggleRigidBody = true;         
        }

        else if (buttonPressed && toggleRigidBody == true)
        {
            Debug.Log("Remove");
            toggleRigidBody = false;        
        }
    }
}

My code only print "Add" when I click the button. What's happening here ?

3
  • Can you clarify what you mean by "What I noticed is that somehow the change of value of the variable toggleRigidBody doesn't change is reset. I'm not sure why" Commented Jul 12, 2021 at 9:02
  • @SeanPowell thanks, I edited my post to make it clearer Commented Jul 12, 2021 at 9:07
  • Please add your code of ContainerController! Commented Jul 12, 2021 at 17:07

2 Answers 2

1

The main problem here is that the editor instance is created when the object is clicked and the Inspector loaded. And then it is destroyed as soon as the object loses focus and the Inspector not shown for this object anymore.

=> Your flag toggleRigidBody is not persistent!

What you rather want to do is serialize the flag inside your object or even better: Serialize the reference itself.

This way you

  • Have already access to the reference in your script in case you need it on runtime
  • Have the reference in the editor for a) checking if it exists and b) being able to remove it directly

So having your class like

public class ContainerController : MonoBehaviour
{
    // Store the reference in a field
    [SerializeField] private Rigidbody _rigidbody;

    ...
}

The editor could look like

[CustomEditor(typeof(ContainerController))]
public class ContainerControllerEditor : Editor
{
    private SerializedProperty _rigidbody;

    ContainerController containerController;

    private void OnEnable()
    {
        _rigidbody = serializedObject.FindProperty("_rigidbody");
        containerController = (ContainerController)target;
    }

    public override void OnInspectorGUI()
    {
        DrawDefaultInspector();
        
        // Loads all current serialized values from the target into the serialized properties
        serializedObject.Update();

        // If the _rigidbody field is not assigned
        // try GetComponent as fallback
        if(!_rigidbody.objectReferenceValue) _rigidbody.objectReferenceValue = containerController.GetComponent<Rigidbody>();

        // simply put everything that belongs to one button click inside one if block
        // this is easier to maintain and read
        // Of course alternatively you could also simply have two completely different buttons to display 
        // depending on the value of "_rigidbody.objectReferenceValue"
        if(GUILayout.Button(_rigidbody.objectReferenceValue ? "Remove Rigidbody" : "Add Rigidbody")
        {
            // Is there a Rigidbody?
            if(_rigidbody.objectReferenceValue)
            {
                // Yes -> destroy it
                // There are two different destroy methods depending whether you are 
                // in Play mode or Edit mode
                if(Application.isPlaying)
                {
                    Destroy(_rigidbody.objectReferenceValue);
                }
                else
                {
                    DestroyImmediate(_rigidbody.objectReferenceValue);
                }
            }
            // Otherwise the field is currently not set and no component was found using GetComponent
            else
            {
                // Add the component via the ObjectFactory
                // this enabled undo/redo and marks the scene dirty etc
                // and assign it to the serialized property
                _rigidbody.objectReferenceValue = ObjectFactory.AddComponent<Rigidbody>(target.gameObject);
            }
        }

        // Writes back all modified properties to the target and takes care of Undo/Redo and marking dirty
        serializedObject.ApplyModifiedProperties ();
    }
}
Sign up to request clarification or add additional context in comments.

Comments

0

The editor object is created when it's being displayed, and destroyed when it's not, so for your data to persist you will need to store the values somewhere else. So that's definitely what is happening. The easiest way to have a value of a variable to be persistent between sessions you would use EditorPrefs to save the variable values. Thats the easiest way you can go about it, so you would use this to save the toggleRigidBody value.

https://docs.unity3d.com/ScriptReference/EditorPrefs.SetBool.html

1 Comment

Yeah I wouldn't use the EditorPrefs for this ... rather simply serialize that one field into the according object instance

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.