c# - 自定义检查器将值恢复为 Unity 中 Play 上之前的值

标签 c# unity-game-engine unity-editor unity3d-editor

因此,在我的游戏中,我有一个对象需要以 float speed 的速度从 Vector3 fromPosition 平滑移动到 Vector3 toPosition,并且然后回到开始的地方。一切都非常简单,但是为了在设置关卡时尝试让生活变得更轻松,我决定为此脚本创建一个自定义检查器,其中的按钮允许我将目标位置设置为对象的当前位置,这样我就可以将其移动到到需要的位置并单击按钮,而不是输入所有坐标。我以为我已经一切正常,但后来开始看到一些非常奇怪的行为,经过一番尝试后,似乎如下所示: 第一次使用按钮时一切都很好。此后每次使用该按钮时,检查器中的值都会正确更改,但点击“播放”后,toPositionfromPosition 的值将恢复为第一次的值该按钮已被使用。 (他们不会在停止时再次恢复)。但是,如果我手动输入这些值,它就可以正常工作。很奇怪,有人知道这里会发生什么吗?脚本和自定义检查器的代码如下。

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class MovingGrapple : MonoBehaviour
{
    public Vector3 fromPosition;
    public Vector3 toPosition;
    public float speed;

    Rigidbody thisBody;
    Grapple player;
    // Start is called before the first frame update
    void Start()
    {
        thisBody = GetComponent<Rigidbody>();
        player = GameObject.Find("Head").GetComponent<Grapple>();
    }


    private void FixedUpdate()
    {
        thisBody.MovePosition(Vector3.MoveTowards(transform.position, toPosition, Time.fixedDeltaTime * speed));
        if(transform.position == toPosition)
        {
            transform.position = fromPosition;
            if (player.activeTarget != null && GetComponentsInChildren<Transform>().Contains(player.activeTarget.transform))
            {
                player.BreakGrapple();
                GameObject.Destroy(player.activeTarget);
            }
        }
    }

    public void SetFromPosition()
    {
        fromPosition = transform.position;
    }

    public void SetToPosition()
    {
        toPosition = transform.position;
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(MovingGrapple))]
public class MovingGrappleInspector : Editor
{
    public override void OnInspectorGUI()
    {
        DrawDefaultInspector();

        MovingGrapple myTarget = (MovingGrapple)target;

        if (GUILayout.Button("Set From position."))
        {
            myTarget.SetFromPosition();
        }
        if (GUILayout.Button("Set To position."))
        {
            myTarget.SetToPosition();
        }
    }
}

谢谢。

最佳答案

这不仅会在您按下播放键时发生。您的更改永远不会保存!

如果可能的话,除非您确切知道自己在做什么,否则永远不要将编辑器脚本与直接访问目标混合在一起!

您特别需要“手动”将更改的对象标记为。否则,更改只是暂时的,直到您的对象再次反序列化(进入/退出 PlayMode 或重新加载场景或 Assets )。

您可以更改之前添加 Undo.RecordObject

if (GUILayout.Button("Set From position."))
{
    Undo.RecordObject(myTarget, "SetFromPosition");
    myTarget.SetFromPosition();      
}
if (GUILayout.Button("Set To position."))
{
     Undo.RecordObject(myTarget, "SetToPosition");
     myTarget.SetToPosition();
}

另外(在您的用例中听起来不太可能,但是)

Important: To correctly handle instances where objectToUndo is an instance of a Prefab, PrefabUtility.RecordPrefabInstancePropertyModifications must be called after RecordObject.


一般来说,总是通过 SerializedProperty在可能的情况下,例如

[CustomEditor(typeof(MovingGrapple))]
public class MovingGrappleInspector : Editor
{
    private SerializedProperty fromPosition;
    private SerializedProperty toPosition;

    private MovingGrapple myTarget

    private void OnEnable()
    {
        fromPosition = serializedObject.FindProperty("fromPosition");
        toPosition = serializedObject.FindProperty("toPosition");

        myTarget = (MovingGrapple)target;
    }


    public override void OnInspectorGUI()
    {
        DrawDefaultInspector();

        // This loads the current real values into the serialized properties
        serializedObject.Update();

        if (GUILayout.Button("Set From position."))
        {
            // Now go through the SerializedProperty
            fromPosition.vector3Value = myTarget.transform.position;
        }
        if (GUILayout.Button("Set To position."))
        {
            toPosition.vector3Value = myTarget.transform.position;
        }

        // This writes back any changes properties into the actual component
        // This also automatically handles all marking the scene and assets dirty -> saving
        // And also handles proper Undo/Redo
        serializedObject.ApplyModifiedProperties();
    }
}

关于c# - 自定义检查器将值恢复为 Unity 中 Play 上之前的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66588861/

相关文章:

c# - 有人使用 CLI 后端为 gcc 编译器编译 lib x264 吗?

c# - 使用 javascript 获取 Windows 用户名

c# - UnityEvent 未在检查器中显示动态方法调用(其他 Unity 事件也部分损坏)

android - 8th Wall XR 相机位置没有改变

unity3d - unity 条件字段自定义编辑器

c# - 在同一 SSIS 项目中的两个包之间共享脚本组件类

c# - 从集合 (MembershipUserCollection) 中删除项目 - 枚举操作可能无法执行

c# - 将对象放置在 Raycast 指向的位置,但在 Unity3D 中考虑碰撞

c# - 在 Unity Inspector 窗口中获取选定的组件

c# - 我可以在 CreateAssetMenu 中设置子文件夹的排序顺序吗?