【问题标题】:Unity editor scripting : how to execute two different actions with the same button?Unity 编辑器脚本:如何使用同一个按钮执行两个不同的操作?
【发布时间】:2021-07-12 06:51:59
【问题描述】:

我编写了一些代码来向我在 Unity 中的自定义编辑器中添加一个按钮。我想要的是以下内容。当我单击一次按钮时,会添加一个组件,当我再次单击时,会删除该组件。在下面的简单代码中,我只是在单击按钮时尝试打印“添加”或“删除”。我注意到变量 toggleRigidBody 取值为 true,但之后立即取值为 false。即使我从未在代码中明确更改它,它也不会保持“真实”。 “else if”永远不会被解雇。我不知道为什么。

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;        
        }
    }
}

当我单击按钮时,我的代码只会打印“添加”。这里发生了什么?

【问题讨论】:

  • 你能澄清一下“我注意到的是,变量toggleRigidBody的值的变化不会改变被重置。我不知道为什么”
  • @SeanPowell 谢谢,我编辑了我的帖子以使其更清晰
  • 请添加ContainerController的代码!

标签: unity3d button unity-editor unity3d-editor


【解决方案1】:

这里的主要问题是编辑器实例是在单击对象并加载 Inspector 时创建的。然后在对象失去焦点并且不再显示该对象的 Inspector 时将其销毁。

=> 您的标志 toggleRigidBody 不持久!

您更愿意做的是序列化对象内部的标志,甚至更好:序列化引用本身。

这样你

  • 已经可以访问脚本中的引用,以防您在运行时需要它
  • 在编辑器中有参考,用于 a) 检查它是否存在 b) 能够直接删除它

所以让你的课喜欢

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

    ...
}

编辑器可能看起来像

[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 ();
    }
}

【讨论】:

    【解决方案2】:

    编辑器对象在显示时创建,不显示时销毁,因此为了使您的数据持久保存,您需要将值存储在其他位置。所以这绝对是正在发生的事情。让变量值在会话之间保持不变的最简单方法是使用EditorPrefs 来保存变量值。这是最简单的方法,因此您可以使用它来保存 toggleRigidBody 值。

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

    【讨论】:

    • 是的,我不会为此使用EditorPrefs ...而是简单地将一个字段序列化到相应的对象实例中
    猜你喜欢
    • 2013-06-02
    • 2018-06-27
    • 1970-01-01
    • 1970-01-01
    • 2015-08-04
    • 1970-01-01
    • 2012-06-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多