16.更多跨域调用-热更工程中使用MonoBehaviour
16.1 知识点
复制之前的主入口调用
ILRuntimeManager.Instance.StartILRuntime(() =>
{
// 执行ILRuntime当中的一个静态函数
// 静态函数中就是热更工程自己处理的逻辑了
ILRuntimeManager.Instance.appDomain.Invoke("HotFix_Project.ILRuntimeMain", "Start", null, null);
});
ILRuntime不推荐直接使用MonoBehaviour
ILRuntime中支持在热更工程中跨域继承MonoBehaviour
。
- 注册跨域继承适配器。
- 对泛型方法
AddComponent
进行重定向(较为复杂)。
但是,ILRuntime并不推荐通过跨域继承直接使用MonoBehaviour
。推荐大家类似Lua中一样使用MonoBehaviour
,在主工程中通过委托或事件的形式派发生命周期函数到热更中。
主要原因:MonoBehaviour
是一个很特殊的类,很多底层逻辑是在C++中处理的,比如其中public字段的序列化,在Inspector窗口中显示的功能。如果在热更工程中去写,底层C++逻辑无法获取到热更工程中C#相关的信息。
派发生命周期函数的形式使用MonoBehaviour
思路
在主工程中实现一个脚本,该脚本的主要目的就是派发MonoBehaviour
的生命周期函数供热更工程中使用。
Unity工程中声明ILRuntimeMono类,定义各个生命周期的事件
public class ILRuntimeMono : MonoBehaviour
{
// Awake相当于构造函数,在脚本添加的时候就会自动执行
// 所以它不能使用这种事件分发的形式去触发它
// public event Action awakeEvent;
public event Action startEvent;
public event Action updateEvent;
// private void Awake()
// {
// awakeEvent?.Invoke();
// }
void Start()
{
startEvent?.Invoke();
}
void Update()
{
updateEvent?.Invoke();
}
}
在ILRuntime工程直接添加ILRuntimeMono组件并添加事件函数。注意Awake函数添加委托没意义,因为不会执行。
GameObject obj = new GameObject();
ILRuntimeMono mono = obj.AddComponent<ILRuntimeMono>();
// 由于Awake执行时机的特殊性,Awake会在脚本添加时自动执行,我们可以在添加了对应脚本后直接执行初始化相关逻辑即可
// 无需通过事件或者委托的形式去触发它
Debug.Log("Awake");
// mono.awakeEvent += () =>
// {
// Debug.Log("Awake");
// };
mono.startEvent += () =>
{
Debug.Log("Start");
};
mono.updateEvent += () =>
{
Debug.Log("Update");
};
总结
ILRuntime中虽然支持跨域继承MonoBehaviour
,但是作者并不建议大家这样做。我们可以通过类似Lua热更中那样,在主工程中实现用于派发生命周期函数的公共脚本,通过委托或事件达到生命周期函数的调用。
16.2 知识点代码
Lesson16_更多跨域调用_热更工程中使用MonoBehaviour
using System.Collections;
using System.Collections.Generic;
using BaseFramework;
using UnityEngine;
public class Lesson16_更多跨域调用_热更工程中使用MonoBehaviour : MonoBehaviour
{
void Start()
{
#region 复制之前的主入口调用
ILRuntimeManager.Instance.StartILRuntime(() =>
{
//执行ILRuntime当中的一个静态函数
//静态函数中 就是热更工程自己处理的逻辑了
ILRuntimeManager.Instance.appDomain.Invoke("HotFix_Project.ILRuntimeMain", "Start", null, null);
});
#endregion
#region 知识点一 ILRuntime不推荐直接使用MonoBehaviour
//ILRuntime中支持在热更工程中跨域继承MonoBehaviour
//1.注册跨域继承适配器
//2.对泛型方法AddComponent进行重定向(较为复杂)
//但是
//ILRuntime并不推荐通过跨域继承直接使用MonoBehaviour
//推荐大家类似Lua中一样使用MonoBehaviour
//在主工程中通过委托或事件的形式派发生命周期函数 到 热更中
//主要原因:
//MonoBehaviour是一个很特殊的类,很多底层逻辑是在C++中处理的
//比如其中public字段的序列化,在Inspector窗口中显示的功能
//如果在热更工程中去写,底层C++逻辑无法获取到热更工程中C#相关的信息
#endregion
#region 知识点二 派发生命周期函数的形式使用MonoBehaviour
//在主工程中实现一个脚本
//该脚本的主要目的就是派发MonoBehaviour的声明周期函数供热更工程中使用
#endregion
#region 总结
//ILRuntime中虽然支持跨域继承MonoBehaviour
//但是作者并不建议大家这样做
//我们可以通过类似Lua热更中那样
//在主工程中实现用于派发生命周期函数的的公共脚本
//通过委托或事件达到生命周期函数的调用
#endregion
}
}
ILRuntimeMono
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ILRuntimeMono : MonoBehaviour
{
//Awake相当于构造函数 在脚本添加的时候就会自动执行
//所以它不能使用这种事件分发的形式去触发它
//public event Action awakeEvent;
public event Action startEvent;
public event Action updateEvent;
//private void Awake()
//{
// awakeEvent?.Invoke();
//}
void Start()
{
startEvent?.Invoke();
}
void Update()
{
updateEvent?.Invoke();
}
}
ILRuntimeMain
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace HotFix_Project
{
#region 委托调用
public delegate void MyILRuntimeDel1();
public delegate int MyILRuntimeDel2(int i, int j);
#endregion
class ILRuntimeMain
{
/// <summary>
/// 把逻辑处理权交给热更工程
/// 它是一个启动函数
/// </summary>
public static void Start()
{
#region ILRuntime调用Unity
////使用ILRuntime创建的空物体
//GameObject obj = new GameObject("ILRuntime创建的空物体");
//obj.transform.position = new Vector3(10, 10, 10);
////Debug.Log(obj.transform.position);//(10.00, 10.00, 10.00)
////添加物理的dll后 可以正常使用Rigidbody了
//Rigidbody rigidBody = obj.AddComponent<Rigidbody>();
//rigidBody.mass = 9999;
//// 可以直接添加Unity自己写的脚本
//obj.AddComponent<Lesson10_Test>();
#endregion
#region 委托调用
////在ILRuntime中 申明 Unity中自定义委托变量 装载 ILRuntime的函数 正常使用
//MyUnityDel1 fun = Fun1;
//fun();//IL_Fun1
//MyUnityDel2 fun2 = Fun2;
//int result = fun2(5, 6);//IL_Fun2
//Debug.Log(result);//11
////在Unity中 申明 Unity中自定义委托变量 关联ILRuntime工程中的函数
////找到我们在Unity的脚本
//Lesson11_更多跨域调用_委托调用 lesson11 = GameObject.FindObjectOfType<Lesson11_更多跨域调用_委托调用>();
////直接设置Unity中自定义委托变量为ILRuntime工程中的函数会报错
////报错信息:KeyNotFoundException: Cannot find convertor for global::MyUnityDel1
////使用自定义委托
////注册MyUnityDel1和MyUnityDel2的委托和委托转换器后才能正常执行
//lesson11.fun = Fun1;
//lesson11.fun();//IL_Fun1
//lesson11.fun2 = Fun2;
//result = lesson11.fun2(7, 7);//IL_Fun2
//Debug.Log(result);//14
////使用Action或者Func
////因为使用的是Action或者Func 不需要注册委托转换器
//lesson11.funAction = Fun1;
//lesson11.funAction();//IL_Fun1
//lesson11.funFunc = Fun2;
//result = lesson11.funFunc(8, 8);//IL_Fun2
//Debug.Log(result);//16
////在ILRuntime中自定义委托后使用 直接使用
//MyILRuntimeDel1 funIL = Fun1;
//funIL();//IL_Fun1
//MyILRuntimeDel2 funIL2 = Fun2;
//result = fun2(1, 1);//IL_Fun2
//Debug.Log(result);//2
#endregion
#region 跨域继承Unity中的类
//Lesson12_Son lesson12_Son = new Lesson12_Son();
//lesson12_Son.TestFun("哈哈哈");
//lesson12_Son.TestAbstract(99);
//lesson12_Son.valuePublic = 100;
#endregion
#region 跨域继承Unity中的类的注意事项
//Lesson13_Son lesson13_Son = new Lesson13_Son();
//lesson13_Son.TestAbstract(666);
//lesson13_Son.TestInterface();
//Lesson13_InheritAllSon lesson13_InheritAll = new Lesson13_InheritAllSon();
//lesson13_InheritAll.TestAbstract(666);
//lesson13_InheritAll.TestInterface();
#endregion
#region CLR重定向和CLR绑定
////得到当前系统时间
//System.DateTime currentTime = System.DateTime.Now;
//for (int i = 0; i < 100000; i++)
//{
// Lesson14_更多跨域调用_CLR重定向和CLR绑定.TestFun(i, i);
//}
//Debug.Log("十万次循环花费的时间:" + (System.DateTime.Now - currentTime).TotalMilliseconds + "ms");
#endregion
#region 值类型绑定
//System.DateTime currentTime = System.DateTime.Now;
//Vector3 v1 = new Vector3(123, 54, 567);
//Vector3 v2 = new Vector3(342, 678, 123);
//float dot = 0;
//for (int i = 0; i < 1000000; i++)
//{
// dot += Vector3.Dot(v1, v2);
//}
//Vector2 v3 = new Vector2(12, 56);
//Vector2 v4 = new Vector2(123123, 45345);
//for (int i = 0; i < 1000000; i++)
//{
// dot += Vector3.Dot(v3, v4);
//}
//Debug.Log("值类型计算花费的时间:" + (System.DateTime.Now - currentTime).TotalMilliseconds + "ms");
#endregion
#region 热更工程中使用MonoBehaviour
GameObject obj = new GameObject();
ILRuntimeMono mono = obj.AddComponent<ILRuntimeMono>();
//由于Awake执行时机的特殊性 Awake会在脚本添加时自动执行 我们可以在添加了对应脚本后直接执行初始化相关逻辑即可
//无需通过事件或者委托的形式去触发它
Debug.Log("Awake");
//mono.awakeEvent += () =>
//{
// Debug.Log("Awake");
//};
mono.startEvent += () =>
{
Debug.Log("Start");
};
mono.updateEvent += () =>
{
Debug.Log("Update");
};
#endregion
}
#region 委托调用
public static void Fun1()
{
Debug.Log("IL_Fun1");
}
public static int Fun2(int a, int b)
{
Debug.Log("IL_Fun2");
return a + b;
}
#endregion
}
}
16.3 练习题
完善对ILRuntimeMono脚本的封装,提供一个添加事件和移除事件的方法,供外部使用,请将完善后的代码作为答案回答
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com