前言
计算机语言有动态和静态之分,静态语言主要是像C和C++之类的语言。
特点:需要预先编译为目标机器代码,CPU才能正确执行其指令。
动态语言,通常称为脚本。
特点:运行在其他语言实现的程序中,不需要预先编译,而是在程序运行的过程中实时编译,因此具有很强的灵活性
C#和Java是比较特殊的语言,需要编译,但不是编译成机器代码,而是一种中间语言,在程序运行时,再由运行时程序将其编译成为目标代码。
特点:性能上略有一定损失,但更加高效、安全,相比动态语言性能卓越,语法健壮,无法真正实时编译
动态语言的最大优势:热更新,也就是不重新编译程序,只更新某一部分实现对内容的更新。游戏公司对游戏留了一些接口,能让玩家对发布的游戏内容进行自行修改,类似于创意工坊,就比如说人气游戏《饥荒》联机版的Mod层出不穷,一定程度上来说,这些Mod也成为了游戏的一部分,让《饥荒》这一款游戏做到了时时新,难以过时。这方面使用比较多的技术就是Lua,可以看到饥荒的很多Mod文件都是.Lua 结尾的。
Lua是一门很小巧的语言,真正做到了动态实时编译,可以运行在其他语言之中,因此Lua也被称为嵌入式语言。
动态读取程序集实现热更新
通俗来说,也就是动态调用编译好的程序集,也就是**.dll文件**,这样在程序发布后,只需要更新.dll文件,即可实现对程序内容的更新。
(ps:IOS平台不支持)
创建.dll文件
//在解决方案管理器中右键引用,添加引用,选择浏览,添加入整个UnityEngine文件夹
using UntiyEngine;
namespace UntiyDll{
public class Myplugin:MonoBehaviour
{
//release生成.dll文件后,只需要放入Unity工程项目的Assets文件夹下的Plugins文件夹中,具体再放哪个文件夹看这个网址
//https://blog.csdn.net/linxinfa/article/details/102978005
}
}
在Untiy中测试热更新.dll文件
void Start()
{
//运行时,会自动生成一个脚本挂载到物体上
this.gameObject.AddComponent<UnityDll.MyPlugin>();
}
通过反射访问.dll文件
using System.Reflection;
//在untiy中做热更新,通常会把需要更新的内容放到Untiy的StreamingAssets路径下,此时必须用文件读取的方式读取.dll,然后通过反射执行.dll文件提供的功能
void Start()
{
byte[] bs=System.IO.File.ReadAllBytes(Application.streamingAssetsPath+"/UnityDLL.dll");
Assembly ass=Assembly.Load(bs);
System.Type t =ass.GetType("UntiyDll.MyPlugin");//通过反射获取MyPlugin类
//多出来的步骤就是,通过文件读取程序集,然后再通过反射获取类
Component myPlugin=this.gameObject.AddComponent(t);
}
//实现热更新,主要是通过网络下载需要更新的文件,保存到API中的一个可写的路径中,程序先访问Application.dataPath指向的路径,如果目标文件不存在,再到StreamingAssets中读取默认文件
Lua和Untiy的交互
新建Unity工程,在Untiy store中下载MoonSharp插件并导入
新建lua脚本,保存在StreamingAssets路径下
function fun()
print("hello,lua");
return "hello,lua";
end
在Untiy工程中创建脚本LuaManager.cs
using MoonSharp.Interpreter;
void Start()
{
Script luaScript=new Script();//创建lua解释器
string luaPath=System.IO.Path.Combine(Application.streamingAssetsPath,"test.lua");//获取文件路径
string luatxt=System.IO.File.ReadAllText(luaPath);//读取脚本
DynValue dyn=luaScript.DoString(luatxt);//用解释器运行Lua脚本
DynValue lua_fuc=luaScript.Globals.Get("fun");//查找函数
DynValue result=luaScript.Call(lua_fuc);//调用函数
Debug.Log(result.ToObject<string>());//输出lua函数返回值
}
将Untiy功能导入lua
static GameObject CreateGameObject(string name)
{
return new GameObject(string);
}
UserData.RegisterType<Debug>();//注册静态类Debug
UserData.RegisterType<GameObject>();
UserData.RegisterType<Transform>();
UserData.RegisterType<Vector3>();
luaScript.Globals["Debug"]=typeof(Debug);
luaScript.Globals["GameObject"]=(System.Func<string,GameObject>)CreateGameObject;
Lua脚本的热更新
- 将Lua脚本或AssetBundle数据包存放在HTTP服务器上
- 在客户端,将lua脚本存放到StreamingAssets路径下
- 客户端运行后,先比对本地和服务器的版本是否一致,如果相同,到Application.dataPath指向的路径下查找Lua脚本,如果不存在,则使用StreamingAssets中默认的脚本
- 如果版本号不一致,则下载服务器最新的lua脚本,存储到Application.dataPath指向的路径下,读取最新的Lua脚本
WWW www=new WWW("http://xxxxx/test.lua");//使用HTTP协议下载lua
string luatxt=www.text;//获取Lua脚本的字符串
//代替上面获取文件路径和读取脚本
|