{Unity} WebGL版本不能使用反射机制以及解决方法

我们的项目导出WebGL后运行不了,因为我们使用了System.Reflection.Assembly.GetExecutingAssembly().CreateInstance
来根据类名创建对象。解决方法是创建一个工厂类,根据类名调用不同的代码new对象。而然这样很麻烦,并且每次都需要修改这个工厂。我想了一个方法就是使用一个编辑器脚本自动生成工厂类,思路是利用反射机制获取一个assembly内部所有要用工厂创建的类的名字,然后生成代码。因为我们所有要用工厂创建的类都有共同的基类,所以可以通过System.Type类的IsSubclassOf方法进行判断。基本的代码如下:

List<string> sceneClassNames = new List<string>();
        string assemblyPath = Application.dataPath.Replace ("Assets", "Library/ScriptAssemblies");
        Debug.Log (assemblyPath);
        //System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly ();

        System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFrom (assemblyPath+"/Assembly-CSharp.dll");
        System.Type sceneType = assembly.GetType ("Scene");//获取基类type
        System.Type[] types = assembly.GetTypes ();
        foreach (System.Type type in types) {
            if(type.IsSubclassOf(sceneType))
                sceneClassNames.Add(type.Name);
        }

注意:这儿唯一有些小麻烦的地方是获取项目的assembly,如果是游戏内部代码在游戏运行时获取,就可以使用GetExecutingAssembly ()获取。但是我想在编辑器中运行就必须手动载入游戏项目的assembly,方法是使用LoadFrom(),但需要获取到assembly的路径,使用Application.dataPath.Replace (“Assets”, “Library/ScriptAssemblies”);即可获取。
获取到所有需要工厂创建的类的名字后,生成工厂类的代码就很容易了:

//output SceneFactory code
        string codePath = Application.dataPath +"/_scripts/Game/SceneFactory.cs";

        StreamWriter writer;
        writer = File.CreateText(codePath);

        writer.WriteLine ("// This file is auto created by ExportSceneFactory tool.");
        writer.WriteLine ("public class SceneFactory {");
        writer.WriteLine ("    public static Scene CreateScene(string sceneClassName) {");

        for (int i=0; i<sceneClassNames.Count; i++) {
            string name = sceneClassNames[i];
            string tmp = (i==0)?"":"else ";
            string code = string.Format("        {0}if (sceneClassName == \"{1}\") ", tmp, name);
            writer.WriteLine(code);
            writer.WriteLine("        {");
            code = string.Format("            return new {0}();",name);
            writer.WriteLine(code);
            writer.WriteLine("        }");    
        }
        writer.WriteLine ("        return null;");
        writer.WriteLine ("    }");
        writer.WriteLine ("}");
        writer.Close();

虽然用if/else比较效率不那么高,但是也够用了,如果不嫌麻烦可以改成面向对象的方法用一个map+若干独立工厂实现。
然后把这个脚本集成在我们的持续集成框架中,在build webgl版本之前调用一下就可以了,完美~
当然别忘了创建对象的地方,根据是否webgl版本选择不同的创建方式:

#if UNITY_WEBGL
                Scene scene = SceneFactory.CreateScene(sceneClassName);
#else
                Scene scene = System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(sceneClassName) as Scene;
#endif
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值