【问题标题】:Unity, editor-time script, On GameObject Added to Scene EventUnity,编辑器时脚本,在 GameObject 上添加到场景事件
【发布时间】:2023-03-20 05:16:01
【问题描述】:

假设您有一个微不足道的预制件“盒子”,我们会说它只不过是一个标准米立方体。

  • 1 - 预制框位于您的项目面板中

  • 2 - 将其拖到场景中

  • 3 - 显然它现在也出现在 Hierarchy 面板中,并且可能被选中并显示在 Inspector 中

需要明确的是,当你这样做时,游戏不是 Play,你只是处于普通的编辑器模式。

是否可以制作一个脚本(“编辑器脚本”?),

  • 当您在上面执行“1”和“2”时,(同样是在编辑器模式下,而不是在游戏期间)

  • 当 3 发生时,我们可以影响场景中的新 Box 项目

  • 所以,简单的例子:无论你把它放在哪里,我们都会将 Z 位置设置为“2”。

简而言之:编辑代码,这样每次您将预制件 P 拖到场景中时,它会将位置 z 设置为 2.0。

这在 Unity 中可行吗?我对“编辑脚本”一无所知。

这似乎很明显应该是可能的。

【问题讨论】:

  • 这不太正确,Jin ... 否则,您必须向我展示您在整个代码中的意思??
  • 我不认为有一个 Unity API 可以解决这个问题,但我认为你应该在问题中添加你尝试过的代码。我这么说是因为您之前的最后 3 个问题,包括这个问题。
  • 我已经对此进行了研究,可以做到但很复杂。这不仅仅是使用Selection.activeGameObject 和大量代码。您需要一种方法来区分对象实际拖到层次结构的时间和对象在层次结构中重新排列的时间。这两者都会触发一个回调函数。您还需要实现变量的保存和加载,因为这是一个编辑器插件,只要您点击“播放”按钮导致错误,它们就会重置
  • Unity 应该为此添加功能。有EditorApplication.hierarchyChanged,但在场景中重新排列对象时也会调用它。实际上,这里的Selection.activeGameObject 并不是不相关的,因为当您将对象从 Project 拖到 Hierarchy 选项卡时,会自动选择对象,因此在Selection.activeGameObject 中。可以和EditorApplication.hierarchyChanged一起使用
  • 为什么在场景编辑器中如此重要?

标签: c# unity3d unity3d-editor


【解决方案1】:

您可以添加一个实现OnHierarchyChange 的自定义窗口编辑器来处理层次结构窗口中的所有更改。此脚本必须位于 Editor 文件夹中。要使其自动工作,请确保先打开此窗口。

using System.Linq;
using UnityEditor;
using UnityEngine;

public class HierarchyMonitorWindow : EditorWindow
{
    [MenuItem("Window/Hierarchy Monitor")]
    static void CreateWindow()
    {
        EditorWindow.GetWindow<HierarchyMonitorWindow>();
    }

    void OnHierarchyChange()
    {
        var addedObjects = Resources.FindObjectsOfTypeAll<MyScript>()
                                    .Where(x => x.isAdded < 2);

        foreach (var item in addedObjects)
        {
            //if (item.isAdded == 0) early setup
            
            if (item.isAdded == 1) {
                
                // do setup here,
                // will happen just after user releases mouse
                // will only happen once
                Vector3 p = transform.position;
                item.transform.position = new Vector3(p.x, 2f, p.z);
            }

            // finish with this:
            item.isAdded++;
        }
    }
}

我在盒子上附加了以下脚本:

public class MyScript : MonoBehaviour {
    public int isAdded { get; set; }
}

请注意,OnHierarchyChange 被调用了两次(一次是在您开始将框拖到场景中时,一次是在您释放鼠标按钮时),因此 isAdded 被定义为 int 以便与 @987654327 进行比较@。所以x.isAdded &lt; 1时也可以有初始化逻辑

【讨论】:

  • 这是正确答案!万岁!好吧,也许还有另一种方法,但这很有效。请注意,您应该在进行设置之前检查if(item.isAdded == 1),否则,它会执行两次(这可能是无害的,也可能不是无害的)。
  • 万岁!发送赏金!
  • @Fattie 感谢您的更正和丰厚的赏金 =)
  • 还要注意@Bizhan ikkentim 的回答部分有效,我猜在某些情况下这是一个有用的快速解决方案
【解决方案2】:

你可以这样:

using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

[ExecuteInEditMode]
public class PrintAwake : MonoBehaviour
{
    #if UNITY_EDITOR
    void Awake()  .. Start() also works perfectly
    {
        if(!EditorApplication.isPlaying)
            Debug.Log("Editor causes this Awake");
    }
    #endif
}

见https://docs.unity3d.com/ScriptReference/ExecuteInEditMode.html


分析:

  1. 这确实有效!

  2. 一个问题!它发生在对象开始存在时,因此,当您将它拖到场景中时,但之前你放手了。所以事实上,如果你特别想以某种方式调整位置(捕捉到网格 - 无论如何),使用这种技术是不可能的!

因此,例如,这将完美地工作:

using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

[ExecuteInEditMode]
public class PrintAwake : MonoBehaviour
{
    #if UNITY_EDITOR
    void Start() {
        if(!EditorApplication.isPlaying) {
            Debug.Log("Editor causes this START!!");
            RandomSpinSetup();
            }
    }
    #endif
    private void RandomSpinSetup() {
        float r = Random.Range(3,8) * 10f;
        transform.eulerAngles = new Vector3(0f, r, 0f);
        name = "Cube: " + r + "°";
    }
}

请注意,这可以正常工作,也就是说,当您实际玩游戏时,它不会“运行”。如果您点击“播放”,它将不会再次设置随机旋转:)

好东西

【讨论】:

    【解决方案3】:

    Monobehaviours 有一个 Reset 方法,只有在编辑器模式下才会被调用,只要你重置或第一次实例化一个对象。

    public class Example : MonoBehaviour
    {
        void Reset()
        {
            transform.position =
               new Vector3(transform.position.x, 2.22f, transform.position.z);
            Debug.Log("Hi ...");
        }
    }
    

    【讨论】:

    • 嗯 - 不错,但是……几乎可以工作。不幸的是,当您将预制件添加到场景中时,它不会调用脚本。它仅在您 将该组件添加 到现有游戏对象时调用脚本(或者,显式单击小的“重置”按钮...)
    • (因此来自手册... “当用户点击 Inspector 上下文菜单中的重置按钮或第一次添加组件时会调用重置。”可悲的是,这与您所说的不同,“...或首先实例化”)
    • 哦,好点,那不是解决您的问题的方法!我会把这个(错误的)答案留给其他人作为警告。
    猜你喜欢
    • 2015-08-17
    • 2019-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    相关资源
    最近更新 更多