UI优化时保留原预制体 新预制体和新脚本的绑定引用关系的快速引用

适用场景

优化功能时 保留老预制体且老预制体的脚本公共变量引用绑定很多 ,

新脚本需要重新绑定时

原因

  1. 不能在UI初始化写查找代码 查找的代码其实都是一样的 且毫无意义 从性能上说 代码里查找差一点点,所以预制体挂在了大量脚本
  2. 如果结合MVC思想,这种绑定只是纯View的代码
  3. 引用关系大量 且需要更换脚本

实现

首先,获取Mark脚本中指定的组件类型type,并调用FnmGetNameField方法获取一个字典dicNameField,该字典存储了需要绑定的成员变量名及其对应的子物体名(这里假设子物体名与成员变量名存在某种关联)。接着,为目标组件创建SerializedObject,用于在编辑器环境下操作组件的序列化数据。然后遍历字典,对于每个成员变量:

通过FindProperty方法找到对应的SerializedProperty。虽然有部分条件判断被注释掉,但原本的意图可能是进一步确保属性类型为可引用对象类型(如GameObject或其他组件)。

使用targetCompo.gameObject.transform.Find(pair.Value).gameObject在目标组件所在的游戏对象下,根据子物体名查找对应的子物体。如果找到,就将该子物体赋值给成员变量对应的SerializedProperty的objectReferenceValue,完成绑定。最后,通过ApplyModifiedProperties将修改应用到组件,使其在编辑器中显示的绑定关系得到更新。

csharp 复制代码
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System;
using UnityEditor;
using UnityEngine;
using static UnityEngine.InputManagerEntry;

public class ComponentBinder : MonoBehaviour
{
    /// <summary>
    /// 对象
    /// </summary>
    private static Component targetCompo;
    [MenuItem("GameObject/ForBind", priority = 29)]
    public static void CreateUICode()
    {
        GameObject obj = Selection.activeGameObject;

        if (!obj) return;

        //获取标记的脚本
        Mark mark = obj.GetComponent<Mark>();

        if (!mark)
        {
            Debug.Log("请挂载Mark脚本");
            return;
        }

        targetCompo = obj.GetComponent(mark.CompoClass.GetType().Name);
        try
        {
            Type type = mark.CompoClass.GetType();
            Dictionary<string, string> dicNameField = FnmGetNameField(type);
            SerializedObject serializedObject = new SerializedObject(obj.GetComponent(mark.targetCompoClass.GetType().Name));
            foreach (var pair in dicNameField)
            {
                SerializedProperty property = serializedObject.FindProperty(pair.Key);
                //if (property != null && property.propertyType == SerializedPropertyType.ObjectReference)
                //{
                    GameObject referencedGameObject = targetCompo.gameObject.transform.Find(pair.Value).gameObject;
                    if (referencedGameObject != null)
                    {
                        property.objectReferenceValue = referencedGameObject;
                    }
                //}
            }
            serializedObject.ApplyModifiedProperties();

            if (dicNameField.Count > 0)
            {
                StringBuilder msg = new StringBuilder("==>成员 : ");

                foreach (string name in dicNameField.Keys)
                {
                    msg.Append(name + "、");
                }

                Debug.LogError(msg + " 无法绑定,请确认物体绑定了Bind脚本或名字与成员名是否一致。");

                return;
            }

        }
        catch (Exception e)
        {
            Debug.LogError("绑定对应物体出错了\n" + e.Message);
            return;
        }

        Debug.Log("=====>获取物体" + obj.name + "上的脚本" + mark.CompoClass.name + "的成员成功了。");
    }

    /// <summary>
    /// 查找脚本中所有需要绑定成员的名字、数据
    /// </summary>
    /// <param name="type">脚本类型</param>
    /// <returns></returns>
    private static Dictionary<string, string> FnmGetNameField(Type type)
    {
        Dictionary<string, string> dicNameField = new Dictionary<string, string>();
        SerializedObject serializedObject = new SerializedObject(targetCompo);
       
        foreach (FieldInfo field in type.GetFields())
        {
            if (!field.IsNotSerialized)
            {
                dicNameField[field.Name] = (serializedObject.FindProperty(field.Name).objectReferenceValue).name;
                Debug.Log("=====>获取物体" + field.Name + "|||" + (serializedObject.FindProperty(field.Name).objectReferenceValue).name + "");
            }
        }
        return dicNameField;

    }

}

遇到的问题

1.提示了Scene mismatch (cross scene references not supported)

当在 Unity 中遇到 "Scene mismatch (cross scene references not supported)" 这个提示时,意味着你正在尝试进行跨场景的引用操作,但 Unity 默认是不支持这种跨场景引用的,以下是可能导致该问题出现的原因以及对应的解决办法:

一、原因分析

  1. 通过 GameObject.Find 查找其他场景中的物体
    在你之前的代码中,如果使用了 GameObject.Find 函数去查找物体,并且期望找到的物体位于当前场景之外的其他场景中,就会触发这个错误。例如,在场景 A 的脚本代码里,尝试通过 GameObject.Find 去获取场景 B 中的某个游戏对象来绑定到变量上,像这样:
csharp 复制代码
public class MyScript : MonoBehaviour
{
    void Start()
    {
        GameObject otherSceneObject = GameObject.Find("ObjectNameInAnotherScene");
        // 后续尝试使用这个对象进行赋值等操作,就可能触发错误
    }
}

因为 GameObject.Find 只会在当前激活的场景中查找符合条件的对象,无法跨越场景去查找。

  1. 在序列化属性中设置了跨场景的对象引用

在 Unity 编辑器环境下,通过 Inspector 面板或者自定义编辑器脚本设置序列化公共变量(比如 GameObject 类型的变量)的引用时,如果不小心将一个来自其他场景的对象拖放到变量引用位置,同样会出现此问题。例如,在场景 A 中的脚本组件的 Inspector 中,想要为一个 public GameObject myObject; 变量指定引用,却错误地拖放了场景 B 里的游戏对象。

2.pecified cast is not valid.

在 Unity 中遇到 "Specified cast is not valid." 这个错误提示,通常意味着你正在进行一个类型转换操作,但实际的数据类型与期望转换的类型不匹配,以下是几种可能导致该错误出现的情况以及相应的解决办法:

  1. 变量赋值时类型不匹配
    情况描述:
    当你试图将一个不兼容类型的值赋给某个变量,并且进行了显式或隐式的类型转换时,就可能出现此错误。例如,你有一个变量声明为 int 类型,却试图将一个 string 值赋给它并进行转换(即便在代码中看起来像是合理的类型转换写法)。
    示例代码及分析:
相关推荐
电商api接口开发15 分钟前
ASP.NET MVC 入门指南二
前端·c#·html·mvc
偶尔微微一笑2 小时前
AI网络渗透kali应用(gptshell)
linux·人工智能·python·自然语言处理·编辑器
timing9943 小时前
LVGL在VScode的WSL2中仿真
ide·vscode·编辑器
Thomas_YXQ3 小时前
Unity3D IK解算器技术分析
开发语言·搜索引擎·unity·全文检索·unity3d·lucene
o0向阳而生0o3 小时前
28、.NET 中元数据是什么?
microsoft·c#·.net
niuTaylor4 小时前
Linux驱动开发快速上手指南:从理论到实战
linux·运维·开发语言·驱动开发·c#
军训猫猫头5 小时前
89.WPF 中实现便捷的数字输入框:DecimalUpDown 控件的使用 WPF例子 C#例子.
开发语言·c#·wpf
冰茶_6 小时前
.NET MAUI 发展历程:从 Xamarin 到现代跨平台应用开发框架
学习·microsoft·微软·c#·.net·xamarin
The Future is mine7 小时前
C# new Bitmap(32043, 32043, PixelFormat.Format32bppArgb)报错:参数无效,如何将图像分块化处理?
开发语言·c#
kooboo china.8 小时前
Tailwind CSS 实战:基于 Kooboo 构建企业官网页面(一)
前端·css·编辑器