元宇宙技术在传统互联网的基础上,元宇宙在沉浸感、参与度、永续性等多方面提出了更高的要求,因此将会由许多独立工具、平台、基础设施、协议等来支持其运行。随着AR、VR、5G、云计算等技术成熟度提升,元宇宙有望逐步从概念走向现实。
元宇宙的发展模式
(1)循序渐进是元宇宙的主要过程,其中在技术端、内容端、载体端都随着时代的发展而在不断演变。关于将区块链应用变得如何丰富化这个问题以太坊正在努力改进中,同样的Coinbase、Uniswap以及Opesea为代表的交易所也在为区块链经济提供更好的交易能力,他们的发展始终在遵循自然规律,循序渐进的发展。
(2)内容端,元宇宙这一概念在游戏中不断增加,其生态形式也不断加强,当然用户数也随之增长。尤其是以Roblox、Sandbox为代表的UGC元宇宙概念,确保游戏得益于玩家的参与而不断丰富自己游戏的内容。
(3)载体端,比较明显的表现是在通信技术、虚拟现实以及芯片等底层技术的改进和升级中。
Metauniverse emphasizes digital space and virtual world,but it does not mean that it is just digital space and virtual world.It can realize the interaction between virtual world,real world and real society,and can strengthen reality with emptiness.Therefore,metauniverse is an important new track to drive digital technology innovation and enable the real economy.Our government,scientific research institutions,enterprises and individuals need to actively participate in promoting the rapid development of metauniverse.
Do a good job in the top-level design at the macro level,and establish the basic concept and main objectives of the meta universe;Supporting technologies for building the meta universe,especially promoting the research and development of some key technologies;Establish relevant standards of metauniverse,from national standards to international standards,so as to gain a voice in the international science and technology field,avoid wasting financial and material resources and energy,improve R&D efficiency,I35模式7O98开发O7I8.and realize automation and intelligent interoperability;Formulate relevant laws and regulations,standardize in development,develop in standardization,and promote the healthy development of meta universe industry and industrial meta universe.
c#执行lua代码
这里将分三个步骤:
加载lua代码到vm中,对应api-luaL_loadbuffer
luaL_loadbuffer会同时在栈上压入代码块的指针
执行lua代码,对应api-lua_pcall
lua_pcall会从栈上依次弹出{nargs}个数据作为函数参数,再弹出函数进行执行,并将结果压入栈
如果lua代码有返回值,那么通过lua_toXXX相关api从栈上获取结果
完整的代码如下:
private bool DoLuaCode(System.IntPtr L,string luaCode){
//加载lua代码
if(Lua.luaL_loadbuffer(L,luaCode,"")==0){
//执行栈顶的函数
if(Lua.lua_pcall(L,0,1,0)==0){
//函数执行完成后,返回值会依次依次押入栈
return true;
}else{
Debug.LogError("pcall failed!");
return false;
}
}else{
Debug.LogError("load buffer failed");
return false;
}
}
假如我们有一段lua代码:
return'hello,i am from lua'
这段lua仅仅返回一段字符串,那么利用DoLuaCode去执行就是:
//lua代码
string luaCode="return'hello,i am from lua'";
if(DoLuaCode(L,luaCode)){
Debug.Log(Lua.lua_tostring(L,-1));
//lua_toXXX不会出栈,需要lua_pop才能出栈
Lua.lua_pop(L,1);
}
由于此处lua代码返回的是字符串,因此使用lua_tostring(L,-1)来将栈顶的元素转为字符串并返回,相应的我们还能看到有lua_tonumber,lua_toboolean等等.
4.c#调用lua全局函数
接下来的例子将说明一下c#端如何执行lua中的全局函数。
假设现在我们有一段lua代码如下:
function addSub(a,b)
return a+b,a-b;
end
通过DoLuaCode来运行以上的lua代码,就得到了一个全局的addSub函数,这个函数会返回a,b相加和相减的结果。
为了在c#端执行以上的lua函数,需要按以下步骤进行:
将全局函数压入栈中,对应api-lua_getglobal
将函数所需的参数依次压入栈中,对应api-lua_pushnumber
执行栈中函数,对应api-lua_pcall
获取函数返回结果,对应api-lua_tonumber
完整c#代码如下:
//从全局表里读取addSub函数,并压入栈
Lua.lua_getglobal(L,"addSub");
//压入参数a
Lua.lua_pushnumber(L,101);
//压入参数b
Lua.lua_pushnumber(L,202);
//2个参数,2个返回值
Lua.lua_pcall(L,2,2,0);
//pcall会让参数和函数指针都出栈
//pcall执行完毕后,会将结果压入栈
Debug.Log(Lua.lua_tonumber(L,-2));
Debug.Log(Lua.lua_tonumber(L,-1));
Lua.lua_pop(L,2);
5.lua注册并调用c#静态函数
首先,想要被Lua调用的c#函数,都必须满足以下的格式:
public delegate int LuaCSFunction(System.IntPtr luaState);
同时需要加上特性:
MonoPInvokeCallback(typeof(LuaCSFunction))
我们可以通过以下方式,将一个LuaCSFunction注册到lua中:
static void RegisterCSFunctionGlobal(System.IntPtr L,string funcName,LuaCSFunction func){
//将LuaCSFunction压入栈中
Lua.lua_pushcfunction(L,func);
//lua_setglobal会弹出栈顶元素,并按给定的名字作为key将其加入到全局表
Lua.lua_setglobal(L,funcName);
}
那么,当我们在lua中执行c#注册的函数时,其交互过程如下:
LuaVM会临时分配一个局部栈结构(这里要区分开始通过luaL_newstate创建的全局栈,两者是独立的)
LuaVM会将lua侧的函数参数压入这个临时栈,然后将栈指针传给LuaCSFunction
LuaCSFunction在实现上需要从这个栈中读取lua侧压入的参数,然后执行真正的相关逻辑,并将最终结果压入栈中
LuaCSFunction需要返回一个int值,表示往栈中压入了多少个返回值
Lua从栈中获取C#侧压入的0/1/多个返回值
官方说明文档可以参考-Calling C from Lua
接下来要将演示如何将一个c#静态函数Print注入到lua中,实现lua中调用c#端的日志输出功能。
我们定义一个c#静态函数如下:
[MonoPInvokeCallback(typeof(LuaCSFunction))]
private static int Print(System.IntPtr localL){
//获取栈中元素个数
var count=Lua.lua_gettop(localL);
System.Text.StringBuilder s=new System.Text.StringBuilder();
for(var i=1;i<=count;i++){
//依次读取print的每个参数,合并成一个string
s.Append(Lua.lua_tostring(localL,i));
s.Append('');
}
Debug.Log(s);
//print函数没有返回值
return 0;
}
lua_gettop可以获取栈中的元素个数,此处代表了lua端压入栈中的函数参数个数
然后我们通过以下方式将这个c#侧的Print注册到lua中,命名为print。
//将LuaCSFunction压入栈中
Lua.lua_pushcfunction(L,Print);
//lua_setglobal会弹出栈顶元素,并按给定的名字作为key将其加入到全局表
Lua.lua_setglobal(L,"print");
接下来我们执行以下的lua代码:
print('hello','csharp')
就能看到编辑器中输出
hello csharp
6.lua注册c#类型
通常我们使用lua中的table来模拟c#中的类。一般类的注册思路如下:
在lua中创建一个与c#类同名的表
将c#类的静态函数都注册到lua的这个同名表里
下面演示一下如何将Unity中的Debug类注册到lua中:
Lua.lua_createtable(L,0,1);
Lua.lua_setglobal(L,"Debug");
其实很简单:
lua_createtable会创建一个table,压入栈顶
lua_setglobal会弹出栈顶元素,并将其加到全局表里
这样我们在lua里就有了一个名为Debug的表可供全局访问。但目前这个表是空空如也的,我们还需要为其添加静态函数。(tips:实际上完整的设计中,还需要为class table设置metatable,增加一些限制性,但这里先不表)
6.1注入类的静态函数
首先我们定义一个符合LuaCSFunction形式的c#函数如下:
[MonoPInvokeCallback(typeof(LuaCSFunction))]
private static int Debug_Log(System.IntPtr L){
string msg=Lua.lua_tostring(L,1);
Debug.Log(msg);
return 0;
}
这个c#函数是对Debug.Log的一个封装。
然后可以通过以下方式将这个c#函数注册到lua中的Debug表中:
Lua.lua_createtable(L,0,1);
//往栈中压入字符串'Log'
Lua.lua_pushstring(L,"Log");
//往栈中压入函数Debug_Log
Lua.lua_pushcfunction(L,Debug_Log);
//从栈中弹出一个元素作为key,再弹出一个元素作为value,作为pair赋值到index指定的table
Lua.lua_settable(L,1);
Lua.lua_setglobal(L,"Debug");
审核编辑:符乾江
-
互联网
+关注
关注
54文章
11167浏览量
103480 -
元宇宙
+关注
关注
13文章
1397浏览量
11490
发布评论请先 登录
相关推荐
评论