Unity:如何将未知脚本动态附加到游戏对象(自定义编辑器) [英] Unity: How to dynamically attach an unknown script to a GameObject (custom editor)

查看:24
本文介绍了Unity:如何将未知脚本动态附加到游戏对象(自定义编辑器)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在为 Unity 编辑器(自定义检查器和自定义窗口)制作一个系统,该系统将自动化并使我们正在制作的游戏的美术师的工作更轻松,但我遇到了障碍.

I'm currently making a system for the Unity Editor (custom inspector and custom windows) that will automate and make things easier for the artists working on the game we're making, but I've hit a brick wall.

我正在尝试找到一种方法,通过编辑器文本字段输入和 GUI 按钮向场景中的游戏对象动态添加未知脚本.艺术家/程序员将在文本字段中键入脚本的名称,它将搜索并添加到游戏对象中,但我不知道如何进行此操作,特别是因为 gameObject.AddComponent()<的某些函数/code> 自 Unity 5.3 起已弃用

I'm trying to find a way to dynamically add, through an editor Textfield input and a GUI button, an unknown script to a gameobject in the scene. The artist/programmer will type the name of the script in the textfield and it will search and add to a gameobject, but I don't know how to proceed with this, specially since some functions of gameObject.AddComponent() are deprecated as of Unity 5.3

这是我尝试做的:

public string scriptname;
GameObject obj = null;
scriptname = EditorGUILayout.TextField("Script name:", scriptname, GUILayout.MaxHeight(25));
if (GUILayout.Button("Attach script"))
{
    //search for the script to check if it exists, using DirectoryInfo
    DirectoryInfo dir = new DirectoryInfo(Application.dataPath);
    FileInfo[] info = dir.GetFiles("*.*", SearchOption.AllDirectories);
    foreach (FileInfo f in info) // cycles through all the files
    {
        if(f.Name == scriptname)
        {
            //attaches to the gameobject (NOT WORKING)
            System.Type MyScriptType = System.Type.GetType(scriptname + ",Assembly-CSharp"); 
            obj.AddComponent(MyScriptType);
        }
    }
}

(当然,这是一个总结版,我从脚本的不同部分复制了相关的行).

(Of course, this is a summed up version, I copied the relevant lines from different parts of the script).

但它不起作用.有什么想法吗?

But it doesn't work. Any ideas?

推荐答案

经过广泛的实验,我得到了这个.这也涵盖了所有 Unity 组件.只是使它成为一种使生活更轻松的扩展方法.

After extensive experiment I was able get this. This covers all the Unity components too. Just made it an extension method to make life easier.

public static class ExtensionMethod
{
    public static Component AddComponentExt(this GameObject obj, string scriptName)
    {
        Component cmpnt = null;


        for (int i = 0; i < 10; i++)
        {
            //If call is null, make another call
            cmpnt = _AddComponentExt(obj, scriptName, i);

            //Exit if we are successful
            if (cmpnt != null)
            {
                break;
            }
        }


        //If still null then let user know an exception
        if (cmpnt == null)
        {
            Debug.LogError("Failed to Add Component");
            return null;
        }
        return cmpnt;
    }

    private static Component _AddComponentExt(GameObject obj, string className, int trials)
    {
        //Any script created by user(you)
        const string userMadeScript = "Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null";
        //Any script/component that comes with Unity such as "Rigidbody"
        const string builtInScript = "UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null";

        //Any script/component that comes with Unity such as "Image"
        const string builtInScriptUI = "UnityEngine.UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";

        //Any script/component that comes with Unity such as "Networking"
        const string builtInScriptNetwork = "UnityEngine.Networking, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";

        //Any script/component that comes with Unity such as "AnalyticsTracker"
        const string builtInScriptAnalytics = "UnityEngine.Analytics, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null";

        //Any script/component that comes with Unity such as "AnalyticsTracker"
        const string builtInScriptHoloLens = "UnityEngine.HoloLens, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null";

        Assembly asm = null;

        try
        {
            //Decide if to get user script or built-in component
            switch (trials)
            {
                case 0:

                    asm = Assembly.Load(userMadeScript);
                    break;

                case 1:
                    //Get UnityEngine.Component Typical component format
                    className = "UnityEngine." + className;
                    asm = Assembly.Load(builtInScript);
                    break;
                case 2:
                    //Get UnityEngine.Component UI format
                    className = "UnityEngine.UI." + className;
                    asm = Assembly.Load(builtInScriptUI);
                    break;

                case 3:
                    //Get UnityEngine.Component Video format
                    className = "UnityEngine.Video." + className;
                    asm = Assembly.Load(builtInScript);
                    break;

                case 4:
                    //Get UnityEngine.Component Networking format
                    className = "UnityEngine.Networking." + className;
                    asm = Assembly.Load(builtInScriptNetwork);
                    break;
                case 5:
                    //Get UnityEngine.Component Analytics format
                    className = "UnityEngine.Analytics." + className;
                    asm = Assembly.Load(builtInScriptAnalytics);
                    break;

                case 6:
                    //Get UnityEngine.Component EventSystems format
                    className = "UnityEngine.EventSystems." + className;
                    asm = Assembly.Load(builtInScriptUI);
                    break;

                case 7:
                    //Get UnityEngine.Component Audio format
                    className = "UnityEngine.Audio." + className;
                    asm = Assembly.Load(builtInScriptHoloLens);
                    break;

                case 8:
                    //Get UnityEngine.Component SpatialMapping format
                    className = "UnityEngine.VR.WSA." + className;
                    asm = Assembly.Load(builtInScriptHoloLens);
                    break;

                case 9:
                    //Get UnityEngine.Component AI format
                    className = "UnityEngine.AI." + className;
                    asm = Assembly.Load(builtInScript);
                    break;
            }
        }
        catch (Exception e)
        {
            //Debug.Log("Failed to Load Assembly" + e.Message);
        }

        //Return if Assembly is null
        if (asm == null)
        {
            return null;
        }

        //Get type then return if it is null
        Type type = asm.GetType(className);
        if (type == null)
            return null;

        //Finally Add component since nothing is null
        Component cmpnt = obj.AddComponent(type);
        return cmpnt;
    }
}

用法:

gameObject.AddComponentExt("YourScriptOrComponentName");

<小时>

了解我是如何做到的很重要,这样您就可以在未来的任何 Unity 更新中添加对新组件的支持.


It is important to understand how I did it so that you can add support for new components in any future Unity updates.

对于用户创建的任何脚本:

1.找出Assembly.Load 函数的??? 中需要什么.

1.Find out what needs to be in the ??? in the Assembly.Load function.

Assembly asm = Assembly.Load("???");

你可以通过把它放在你的脚本中来做到这一点:

You can do that by putting this in your script:

Debug.Log("Info: " + this.GetType().Assembly);

我得到:Assembly-CSharp,Version=0.0.0.0,Culture=neutral,PublicKeyToken=null

我们现在应该用它替换 ???.

We should now replace ??? with that.

Assembly asm = Assembly.Load("Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null");

2.找出asm.GetType 函数的??? 中需要什么.

2.Find out what needs to be in the ??? in the asm.GetType function.

Assembly asm = Assembly.Load("Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null");
Type type = asm.GetType(???); 

在这种情况下,它只是您要添加到游戏对象的脚本的名称.

In this case, it is simply the name of the script you want to add to the GameObject.

假设您的脚本名称是 NathanScript:

Let's say that your script name is NathanScript:

Assembly asm = Assembly.Load("Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null");
Type type = asm.GetType("NathanScript"); 
gameObject.AddComponent(type);

<小时>

对于非用户创建的 Unity 内置脚本/组件脚本:

例如RigidbodyLinerendererImage 组件.任何不是由用户创建的组件.

Example of this is the Rigidbody, Linerenderer, Image components. Just any component not created by the user.

1.找出Assembly.Load 函数的??? 中需要什么.

1.Find out what needs to be in the ??? in the Assembly.Load function.

Assembly asm = Assembly.Load("???");

你可以通过把它放在你的脚本中来做到这一点:

You can do that by putting this in your script:

ParticleSystem pt = gameObject.AddComponent<ParticleSystem>();
Debug.Log("Info11: " + pt.GetType().Assembly);

我得到:UnityEngine,Version=0.0.0.0,Culture=neutral,PublicKeyToken=null

我们现在应该用它替换 ???.

We should now replace ??? with that.

Assembly asm = Assembly.Load("UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null");

2.找出asm.GetType 函数的??? 中需要什么.

2.Find out what needs to be in the ??? in the asm.GetType function.

Assembly asm = Assembly.Load("UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null");
Type type = asm.GetType(???); 

你可以通过把它放在你的脚本中来做到这一点:

You can do that by putting this in your script:

ParticleSystem pt = gameObject.AddComponent<ParticleSystem>();
Debug.Log("Info: " + pt.GetType());

我得到:UnityEngine.ParticleSystem

请记住,这里以 ParticleSystem 为例.因此,进入 asm.GetType 函数的最终字符串将按如下方式计算:

Remember that ParticleSystem is used as an example here. So the final string that will go to the asm.GetType function will be calculated like this:

string typeString = "UnityEngine." + componentName;

假设您要添加的组件是 LineRenderer:

Let's say that the Component you want to add is LineRenderer:

Assembly asm = Assembly.Load("UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null");
string typeString = "UnityEngine." + "LineRenderer";
Type type = asm.GetType(typeString); 
gameObject.AddComponent(type);

<小时>

将其放在一个扩展方法中:

如您所见,添加您创建的脚本和 Unity 附带的脚本/组件需要完全不同的过程.您可以通过检查类型是否为 null 来解决此问题.如果类型为null,则执行其他步骤.如果另一步也是 null,那么脚本只会退出.

As you can see, adding scripts you created and the script/components that comes with Unity requires totally different process. You can fix this by checking if the type if null. If the type is null, perform the other step. If the other step is null too then the script simply does not exit.

这篇关于Unity:如何将未知脚本动态附加到游戏对象(自定义编辑器)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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