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 值赋给它并进行转换(即便在代码中看起来像是合理的类型转换写法)。
    示例代码及分析:
相关推荐
鲤籽鲲2 小时前
C# _ 数字分隔符的使用
开发语言·c#
鲤籽鲲6 小时前
C# 内置值类型
android·java·c#
幽兰的天空11 小时前
在C#中,如何使用委托实现事件处理?
前端·数据库·c#
山语山11 小时前
C#多线程精解
开发语言·数据库·后端·c#
pchmi11 小时前
C# OpenCV机器视觉:霍夫变换
opencv·c#·机器视觉·霍夫变换·上位机开发
我是唐青枫11 小时前
C# Lambda 表达式详解
开发语言·c#·.net
互联网打工人no112 小时前
反射机制学习
c#
花仙子16613 小时前
C#运动控制系统:雷赛控制卡实用完整例子 C#雷赛开发快速入门 C#雷赛运动控制系统实战例子 C#快速开发雷赛控制卡
开发语言·算法·c#
AmosCloud201313 小时前
3.5 字典树(Trie)与后缀树
开发语言·数据结构·链表·c#
玉面小君14 小时前
C#设计模式(行为型模式):备忘录模式,时光倒流的魔法
设计模式·c#·备忘录模式