unity生成c代码:unity动态执行C代码
unity生成c代码:unity动态执行C代码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(5
好久没写文章了,主要还是之前公司项目时间紧,任务重,导致下班了就没心情开电脑了,到家倒头就睡了,今天趁稍微空闲就赶紧把最近写的一个小功能记录下,以便以后能用上。
公司项目由于以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脚本如下。
类名:DynamicCodeEditor
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);
}
}
这样就能在输入框中写代码,并动态执行了。