Unity 使用Editor工具查找 Prefab 中的指定脚本

news2025/2/23 13:13:47

在 Unity 项目中,随着项目规模的扩大和 Prefab 数量的增加,管理和定位 Prefab 中的脚本变得更加复杂。为了提高开发效率,所以需要编写一个自定义的 Unity Editor 工具,帮助查找某个 Prefab 中是否使用了指定的脚本。本文将介绍如何通过 Unity Editor API 来实现一个 "Prefab Script Finder" 工具,该工具可以在 Prefab 模式下帮助查找附带特定脚本的对象,并直接在编辑器中进行选择和高亮。

一、工具实现目标

在本次实现中,我们的目标是构建一个简单且实用的 Unity Editor 工具,通过以下几个步骤实现:

  • 允许用户从编辑器中选择某个 MonoScript,即一个脚本文件。
  • 查找当前正在编辑的 Prefab 中是否有 GameObject 附带这个脚本。
  • 将找到的对象列出来,并允许开发者在结果列表中点击对象以高亮和定位到该对象。

这个工具非常适合于 Prefab 数量庞大、对象和脚本复杂度较高的项目,有助于快速定位特定组件,提高开发效率。

二、效果

三、代码实现

首先,可以使用 Unity 的 EditorWindow 创建一个自定义的编辑器窗口。在该窗口中,用户可以选择一个脚本文件并点击按钮来查找 Prefab 中附带该脚本的对象。接下来,我们通过递归的方式遍历 Prefab 的所有子对象,检查是否附带指定的脚本。如果找到了,便将这些对象显示在结果列表中。以下是完整的代码实现:

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using UnityEditor.SceneManagement;

public class PrefabScriptFinder : EditorWindow
{
    private MonoScript selectedScript;
    private string scriptTypeName = "";
    private List<(GameObject obj, string prefabPath)> foundObjects = new List<(GameObject, string)>();
    private Vector2 scrollPos;

    [MenuItem("GameObject/ZYT ASSETS/Prefab Script Finder", false, 100)]
    public static void ShowWindow()
    {
        GetWindow<PrefabScriptFinder>("Prefab Script Finder");
    }

    private void OnGUI()
    {
        selectedScript = (MonoScript)EditorGUILayout.ObjectField("Script Type", selectedScript, typeof(MonoScript), false);

        if (selectedScript != null)
        {
            if (selectedScript.GetClass() != null)
            {
                scriptTypeName = selectedScript.GetClass().FullName;
            }
            else
            {
                scriptTypeName = "";
            }
        }
        else
        {
            scriptTypeName = "";
        }

        if (GUILayout.Button("Find in Prefab"))
        {
            if (string.IsNullOrEmpty(scriptTypeName))
            {
                EditorUtility.DisplayDialog("No Script Selected", "Please select a valid script type.", "OK");
                return;
            }
            FindInPrefab();
        }

        if (foundObjects.Count > 0)
        {
            GUILayout.Space(10);
            GUILayout.Label("Found Objects:", EditorStyles.boldLabel);

            scrollPos = GUILayout.BeginScrollView(scrollPos);
            EditorGUILayout.BeginVertical();

            // 显示找到的对象列表
            foreach (var (obj, prefabPath) in foundObjects)
            {
                // 对象点击可以选中
                EditorGUI.BeginChangeCheck();
                GameObject selectedObj = (GameObject)EditorGUILayout.ObjectField(obj, typeof(GameObject), true);
                if (EditorGUI.EndChangeCheck())
                {
                    SelectObjectInOpenedPrefab(obj, prefabPath);
                }
            }

            EditorGUILayout.EndVertical();
            GUILayout.EndScrollView();
        }
    }

    // 在Prefab中查找
    private void FindInPrefab()
    {
        foundObjects.Clear();

        // 获取当前打开的Prefab场景
        PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
        if (prefabStage == null)
        {
            EditorUtility.DisplayDialog("No Opened Prefab", "Please open a prefab in Prefab Mode.", "OK");
            return;
        }

        GameObject prefabInstance = prefabStage.prefabContentsRoot;

        if (prefabInstance == null)
        {
            EditorUtility.DisplayDialog("Error", "Failed to get the prefab contents.", "OK");
            return;
        }

        // 遍历Prefab中的对象
        FindObjectsWithScript(prefabInstance.transform, prefabStage.assetPath);

        if (foundObjects.Count > 0)
        {
            Repaint();
        }
        else
        {
            EditorUtility.DisplayDialog("No Results", $"No objects with script '{scriptTypeName}' found in the opened prefab.", "OK");
        }
    }

    // 递归查找带有指定脚本的对象
    private void FindObjectsWithScript(Transform parent, string prefabPath)
    {
        foreach (Transform child in parent)
        {
            Component[] components = child.GetComponents<Component>();

            foreach (Component comp in components)
            {
                if (comp != null && comp.GetType().FullName == scriptTypeName)
                {
                    // 将找到的对象和Prefab路径保存
                    foundObjects.Add((child.gameObject, prefabPath));
                    break;
                }
            }

            // 递归检查子对象
            FindObjectsWithScript(child, prefabPath);
        }
    }

    // 选中Prefab中的对象
    private void SelectObjectInOpenedPrefab(GameObject obj, string prefabPath)
    {
        PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
        if (prefabStage == null)
        {
            prefabStage = PrefabStageUtility.OpenPrefab(prefabPath);
        }

        if (prefabStage != null)
        {
            // 选中并高亮对象
            Selection.activeGameObject = obj;
            EditorGUIUtility.PingObject(obj);
        }
        else
        {
            Debug.LogError("Failed to open Prefab in Prefab Mode.");
        }
    }
}

四、主要功能解读

  1. 脚本选择: 用户通过 EditorGUILayout.ObjectField 来选择一个脚本MonoScript,当脚本被选择后,我们使用 GetClass() 方法来获取该脚本所对应的 C# 类类型,并获取其全名。

  2. Prefab 搜索: 我们使用 PrefabStageUtility.GetCurrentPrefabStage() 获取当前正在编辑的 Prefab 场景。如果 Prefab 场景未打开,我们提示用户打开 Prefab 模式。然后我们通过递归遍历 Prefab 中的每一个子对象,检查对象上是否附带了指定的脚本。

  3. 结果显示: 找到的对象会被列出,并且用户可以点击每一个对象,工具将自动高亮并选中该对象,方便用户进行进一步操作。

  4. 递归查找: 通过递归遍历 Prefab 的子节点,确保我们不会遗漏任何对象。每一个带有指定脚本的对象都会被保存到结果列表中。

五、工具的优势

  • 快速查找: 在复杂的项目中,Prefab 中的对象可能非常多,手动查找是低效的。这个工具能快速帮助开发者找到指定脚本。
  • 结果交互: 找到的对象直接在编辑器中展示,点击即可选中,并进行定位,非常方便。

六、总结

本文介绍的 "Prefab Script Finder" 是一个实用的 Unity Editor 工具,能够帮助开发者快速在 Prefab 中查找附带特定脚本的对象。通过这种方式,我们可以减少开发过程中的重复劳动,快速定位问题所在,并提高整体开发效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2146437.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LIN总线CAPL函数——干扰LIN帧响应段(linInvertRespBit )

&#x1f345; 我是蚂蚁小兵&#xff0c;专注于车载诊断领域&#xff0c;尤其擅长于对CANoe工具的使用&#x1f345; 寻找组织 &#xff0c;答疑解惑&#xff0c;摸鱼聊天&#xff0c;博客源码&#xff0c;点击加入&#x1f449;【相亲相爱一家人】&#x1f345; 玩转CANoe&…

目标检测:滑块验证

最近在做一些爬虫相关的任务&#xff0c;有时候在登录时候需要去做滑块验证&#xff0c;刚好自己是做AI这一块得&#xff0c;就想着使用目标检测去做检测&#xff0c;然后绕过滑块。

AI 时代,大模型产业落地的八大思考

引言 在人工智能领域&#xff0c;大模型技术正逐渐成为推动行业进步的关键力量。随着技术的发展&#xff0c;大模型不仅在学术界引起了广泛的关注&#xff0c;也在产业界展现出巨大的应用潜力。然而&#xff0c;如何将这些强大的模型有效地应用到实际产业中&#xff0c;仍然是…

什么软件可以远程控制电脑?好用的电脑远程控制软件有哪些?这6款可以帮到你!

在如今的数字化办公环境中&#xff0c;远程控制电脑已成为解决问题、协作工作的必备技能。 无论是技术支持、远程办公&#xff0c;还是简单的文件传输&#xff0c;远程控制软件都能让我们随时随地连接其他电脑&#xff0c;省时省力。 那么&#xff0c;有哪些好用的远程控制软…

大数据和代理:揭示它们之间的微妙联系

大数据&#xff0c;顾名思义&#xff0c;是指使用传统数据处理应用程序无法有效处理的极其庞大而复杂的数据集。这些数据集的特点是数量庞大、速度快、种类繁多&#xff0c;有可能提供有价值的见解并支持各个行业的决策过程。 这些数据可能来自各种来源&#xff0c;例如社交媒体…

一文速通calcite结合flink理解SQL从文本变成执行计划详细过程

文章目录 你可以学到啥测试代码背景知识SQL转变流程图问题 你可以学到啥 SQL如何一步步变成执行计划的有哪些优化器&#xff0c;哪些优化规则calcite 和flink 如何结合的 测试代码 EnvironmentSettings settings EnvironmentSettings.inBatchMode(); TableEnvironment tabl…

Shein西班牙开放平台模式广受市场欢迎,Shein适合卖什么产品?

Shein是一家专注于女性快时尚的跨境B2C互联网企业&#xff0c;主要面向欧美、中东等消费市场。经过海外十余年的发展&#xff0c;Shein在全球积累了数量庞大且仍在高速增长的广泛用户基础。目前Shein已开放自营商家及平台卖家两大合作模式&#xff0c;通过入驻Shein平台&#x…

23ai DGPDB,Oracle资源池战略的最后一块拼图

Oracle对资源池是有执念的&#xff01; 在我看来&#xff0c;这种执念一方面是应用架构的微服务化&#xff0c;数据库被拆分的越来越小&#xff0c;而服务器的硬件能力是不断提升的&#xff0c;CPU核心数、内存和存储的容量都按照摩尔定律在不断增加&#xff0c;这就使得数据库…

QTAndroid编译环境配置

开始 QT 官网的安装教程安装&#xff0c;经过测试有部分小错误。以下是结合教程和网上搜集的一些材料最后安装成功的步骤。 SDK和JDKhttp://链接: https://pan.baidu.com/s/13CImHLAoUFAdecF2BVsBlQ?pwd627g 提取码: 627ghttp://链接: https://pan.baidu.com/s/13CImHLAoUFAd…

Git 代码撤销、回滚到任意版本(当误提代码到本地或master分支时)

两种情况&#xff08;场景&#xff09; 情况一 代码还只在本地&#xff0c;未push到运程仓库&#xff0c;想把代码还原到上一次commit的代码&#xff0c;此时操作为代码撤销 解决方案&#xff1a; git reset [--hard|soft|mixed|merge|keep] [commit|HEAD] 情况二 …

Axure设计之表格列冻结(动态面板+中继器)

在Web端产品设计中&#xff0c;复杂的表格展示是常见需求&#xff0c;尤其当表格包含大量列时&#xff0c;如何在有限的屏幕空间内优雅地展示所有信息成为了一个挑战。用户通常需要滚动查看隐藏列&#xff0c;但关键信息列&#xff08;如ID、操作按钮等&#xff09;在滚动时保持…

十三 系统架构设计(考点篇)

1 软件架构的概念 一个程序和计算系统软件体系结构是指系统的一个或者多个结构。结构中包括软件的构件&#xff0c;构件 的外部可见属性以及它们之间的相互关系。 体系结构并非可运行软件。确切地说&#xff0c;它是一种表达&#xff0c;使软件工程师能够&#xff1a; (1)分…

VMware vSphere 8.0 Update 3b 发布下载,新增功能概览

VMware vSphere 8.0 Update 3b 发布下载&#xff0c;新增功能概览 vSphere 8.0U3 | ESXi 8.0U3 & vCenter Server 8.0U3 请访问原文链接&#xff1a;https://sysin.org/blog/vmware-vsphere-8-u3/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页…

汽车软件开发之敏捷开发

一、前言 目前汽车电子产品&#xff0c;特别是汽车几大域控&#xff08;如&#xff1a;智能座舱、智能驾驶、智能网联、车身控制&#xff09;市场竞争激烈&#xff0c;消费者对汽车的需求逐渐多元化和个性化&#xff0c;用户对座舱和智驾产品的要求也越来越高。他们不仅要求产…

人工智能时代,我们依旧有无限的选择权!

人工智能时代&#xff0c;即有人两眼放光&#xff0c;又有人忧心忡忡。前者看到大量的机遇、蓝海&#xff0c;后者看到了失业和糟糕的未来&#xff0c;亦或是有人有喜有忧。但是只要你知晓一个真谛&#xff1a;凡事皆有利有弊&#xff0c;那便不用内耗了。或是选择当前的生活节…

SAP B1 - 新账套设置密码不过期

背景 建立新账套后&#xff0c;每隔一段时间就会自动弹出以下要求更改密码的提示窗口&#xff0c;最讨厌的是系统会记住你的所有历史密码&#xff0c;新设置密码不能与所有曾用密码相同。找到终止该自动更换密码的设置&#xff0c;遂总结为经验帖。 操作 点击位于顶栏的小人图…

示例:WPF中Grid显示网格线的几种方式

一、目的&#xff1a;介绍一下WPF中Grid显示网格线的几种方式 二、几种方式 1、重写OnRender绘制网格线&#xff08;推荐&#xff09; 效果如下&#xff1a; 实现方式如下&#xff1a; public class LineGrid : Grid{private readonly Pen _pen;public LineGrid(){_pen new P…

C#实战|大乐透选号器[11]:确认选号功能的实现

哈喽,你好啊,我是雷工! 接着练习大乐透选号器的功能,这里练习实现确认选号功能; 以下为实现笔记; 01 效果演示 实现点击确认选号,将机选或手动选出的号码,添加到列表中显示; 02 设置DataGridView 首先设置控件GataGridView的属性; 2.1、编辑列 选中控件,点击右上角的…

最新Kali Linux超详细安装教程(附镜像包)

一、镜像下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1BfiyAMW6E1u9fhfyv8oH5Q 提取码&#xff1a;tft5 二、配置虚拟机 这里我们以最新的vm17.5为例。进行配置 1.创建新的虚拟机&#xff1a;选择自定义 2.下一步 3.选择稍后安装操作系统 4.选择Debian版本 因…

AI绘画实操 Stable Diffusion 到底怎么玩儿,新手必看的AI绘画入门安装使用教程

大家好&#xff0c;我是灵魂画师向阳 2024年&#xff0c;是AI绘画技术飞速发展的一年&#xff0c;各种AI绘画工具层出不穷&#xff0c;为了让大家在了解和学习AI绘画的过程中少走弯路&#xff0c;今天我将详细介绍目前世界上使用用户最多&#xff0c;社区最大&#xff0c;生态…