在 Unity 中播放时自定义检查器将值恢复为以前的值 [英] Custom inspector reverting values back to previous values on Play in Unity

查看:26
本文介绍了在 Unity 中播放时自定义检查器将值恢复为以前的值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

So in my game I have an object that I need to move smoothly from Vector3 fromPosition to Vector3 toPosition at speed float speed, and then go back to where it started. All very simple, but to try and make life easier when setting up levels I decided to make a custom inspector for this script with buttons that allow me to set the target positions to the current position of the object, so I can just move it to where it needs to be and click a button, rather that typing in all the coordinates. Thought I had it all working but then started seeing some very strange behaviour, after playing around it seems to be as follows: The first time a button is used all is well. Every time the button is used after that, the values change properly in the inspector, but upon hitting Play the values of toPosition and fromPosition are reverted to what they were the first time the button was used. (They don't revert back again on Stop). However if I type the values in manually, it works perfectly. Very strange, does anyone have any idea what might be happening here? The code for the script and custom inspector are bellow.

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

谢谢.

推荐答案

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

This will not only happen if you press play .. your changes are never saved!

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

If possible you should never mix editor scripts with direct access to the target except you know exactly what you're doing!

您尤其需要手动"将更改的对象标记为.否则,更改只是暂时的,直到您的对象再次反序列化(进入/退出 PlayMode 或重新加载场景或资产).

You would especially need to "manually" mark your changed object as dirty. Otherwise the changes are only temporary until your object is deserialized again (Enter/Exit PlayMode or reload of the Scene or asset).

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

You could before the changes add a 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();
}

还有(在您的用例中听起来不太可能)

Also (sounds unlikely in your use-case but)

重要提示:要正确处理 objectToUndo 是预制件实例的实例,PrefabUtility.RecordPrefabInstancePropertyModifications 必须在 RecordObject 之后调用.

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


一般来说,总是通过 SerializedProperty 其中可能像例如


In general rather always go through SerializedProperty where possible like e.g.

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

这篇关于在 Unity 中播放时自定义检查器将值恢复为以前的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆