unity动态执行C#代码(仅编辑模式)

好久没写博客了,主要还是之前公司项目时间紧,任务重,导致下班了就没心情开电脑了,到家倒头就睡了,今天趁稍微空闲就赶紧把最近写的一个小功能记录下,以便以后能用上。

公司项目由于以lua为主,所以很容易实现动态执行代码,举个例子,游戏运行中,某个数据显示不对,这个时候就能在不关闭游戏运行的情况下,直接将写好的代码粘贴进输入框执行,就能知道是服务器传的数据问题还是客户端的问题。再举个例子,在播放新手动画时,策划说某个角色的点的位置不好,得换个位置,虽然我们能直接把角色拖到某个位置上来看效果,但如果有寻路的话,就没法知道这个点是不是能通过寻路来走到了,这个时候就可以写一段代码让角色自己走到想要去的点来看效果,而不用关闭游戏,然后写完代码再走一堆流程到需要测试的地方看效果。个人觉得能节省一点时间。那么问题来了,lua能这么做,C#能不能呢?于是我搜索了很多网页,终于让我找到了方法,不过还是有一些小问题,比如UnityEngine.dll文件加载不了,自己编写的脚本的所在的dll名字,还有就是像上图一样有输入框的地方等。以下就是实现动态执行C#代码的脚本。

类名:DynamicCodeHelper

using System;
using System.Reflection;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Text;
using UnityEngine;

public class DynamicCodeHelper : MonoBehaviour
{
    public void ExcuteDynamicCode(string codeStr="") {
        string[] strList = codeStr.Split(';');
        // 1.CSharpCodePrivoder
        CSharpCodeProvider objCSharpCodePrivoder =new CSharpCodeProvider();

        // 2.ICodeComplier
        ICodeCompiler objICodeCompiler = objCSharpCodePrivoder.CreateCompiler();

        // 3.CompilerParameters
        CompilerParameters objCompilerParameters =new CompilerParameters();
        objCompilerParameters.ReferencedAssemblies.Add("System.dll");
        objCompilerParameters.ReferencedAssemblies.Add(Application.dataPath.Replace("Assets", "Library") + "/ScriptAssemblies/Assembly-CSharp.dll");
        objCompilerParameters.ReferencedAssemblies.Add(Application.dataPath.Replace("Assets", "MyDll") + "/UnityEngine.CoreModule.dll");//尝试过通过写文本配置来加载,结果不行会报错,如果有大佬解决了请留言告诉我,万分感谢
        objCompilerParameters.GenerateExecutable =false;
        objCompilerParameters.GenerateInMemory =true;

        // 4.CompilerResults
        CompilerResults cr = objICodeCompiler.CompileAssemblyFromSource(objCompilerParameters, GenerateCode(strList));

        if (cr.Errors.HasErrors)
        {
            Debug.LogError("编译错误:");
            foreach (CompilerError err in cr.Errors)
            {
                Debug.LogError(err.ErrorText);
            }
        }
        else
        {
            // 通过反射,调用DynamicCode的实例
            Assembly objAssembly = cr.CompiledAssembly;
            object objDynamicCode = objAssembly.CreateInstance("DynamicCodeGenerate.DynamicCode");
            MethodInfo objMI = objDynamicCode.GetType().GetMethod("CodeExecute");
            objMI.Invoke(objDynamicCode, null);
        }
    }

    static string GenerateCode(string[] strList)
    {
        StringBuilder sb =new StringBuilder();
        sb.Append("using System;");
        sb.Append(Environment.NewLine);
        sb.Append("using UnityEngine;");
        sb.Append(Environment.NewLine);
        sb.Append("namespace DynamicCodeGenerate");
        sb.Append(Environment.NewLine);
        sb.Append("{");
        sb.Append(Environment.NewLine);
        sb.Append("      public class DynamicCode");
        sb.Append(Environment.NewLine);
        sb.Append("      {");
        sb.Append(Environment.NewLine);
        sb.Append("          public void CodeExecute()");
        sb.Append(Environment.NewLine);
        sb.Append("          {");
        sb.Append(Environment.NewLine);
        foreach (string str in strList)
        {
            if (str != "")
            {
                sb.Append(string.Format("               {0};", str.Replace("\n", "")));
                sb.Append(Environment.NewLine);
            }
        }
        sb.Append("          }");
        sb.Append(Environment.NewLine);
        sb.Append("      }");
        sb.Append(Environment.NewLine);
        sb.Append("}");

        string code = sb.ToString();
        Debug.LogError(code);

        return code;
    }
}

简单说明:1.UnityEngine.dll已经被分割了,所以这里加载的是UnityEngine.CoreModule.dll,我的路径在E:\Unity 2019.2.4f1\Unity\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll,也就是在编辑器安装路径的Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll。我是创建了和Assets同级的一个文件夹,命名为MyDll,这样一些需要加载的dll我就全放这里了,

2.我们在unity新增的C#脚本都是在Assembly-CSharp.dll这个程序集里,而这个程序集的路径就是在和Assets同级的Library底下的ScriptAssemblies文件夹里。

3.Editor脚本如下。

using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(DynamicCodeHelper))]
public class DynamicCodeEditor : Editor
{
    string runCode = @"Debug.LogError(""test your code here!"");";

    public override void OnInspectorGUI()
    {
        GUILayout.Label("DynamicC#Code", GUILayout.Width(100));
        runCode = GUILayout.TextArea(runCode,GUILayout.Height(500));
        if (GUILayout.Button("RunAnyCode"))
        {
            RunAnyCode(runCode);
        }
        base.OnInspectorGUI();
    }

    public void RunAnyCode(string code)
    {
        var t = target as DynamicTest;
        t.ExcuteDynamicCode(code);
    }
}

这样就能在输入框中写代码,并动态执行了。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值