跳转到内容

BlitzMax/Modules/Axe/Lua

来自维基教科书,开放世界中的开放书籍

初始化和反初始化

[编辑 | 编辑源代码]

Lua脚本通常在VM(虚拟机)中运行。因此,我们首先启动一个VM,然后加载基本的Lua库

Local LuaState:byte ptr = luaL_newstate()
luaL_openlibs(LuaState)

luaL_newstate() 返回的字节指针在每次Lua函数调用时都需要。现在你已经完成了初始化,可以开始运行脚本了。

之后关闭Lua VM可以通过一个函数完成

lua_close(LuaState)

运行一个简单的脚本

[编辑 | 编辑源代码]

Lua脚本可以直接从Blitzmax字符串中执行。

Local Script:String = "print(~qHello World!~q)"
luaL_loadString(LuaState,Script)

这段代码加载并编译了脚本。如果出现问题,luaL_loadString() 会返回一个 <> 0 的值。

lua_getfield(LuaState, LUA_GLOBALSINDEX, "debug")' get global "debug" 
lua_getfield(LuaState, -1, "traceback")          ' get "debug.traceback" 
lua_remove (LuaState, -2)                        ' remove "debug" table from stack 

这些命令现在不重要,它们只是为了获得正确的错误信息。

lua_pcall(LuaState,1,-1,-1)' use "debug.traceback" as err.hdlr

这行代码实际上执行了脚本。同样,如果它的返回值是 <> 0,则发生了错误。如果一切都正常,程序将按照预期显示一个“Hello World!”。

从Lua调用BlitzMax函数

[编辑 | 编辑源代码]

基础知识

[编辑 | 编辑源代码]

你可能已经注意到,仅仅能够运行脚本而不能与BlitzMax交互并没有什么用。因此,下一步就是学习如何从Lua脚本调用BlitzMax函数。不幸的是,我们不能直接使用任意函数,因为函数必须遵循特定的布局

Function BMXName:int (LuaState:Byte Ptr)   
   ...      ' handling of parameters passed from Lua (if required)     
      ...   ' actual function body   
   ...      ' passing results back to Lua (if required)   
   return 0 ' number of values returned to Lua function  
End Function

显然,在Lua脚本中使用函数提交的参数不会直接传输到BlitzMax函数。我们必须手动处理它们,但不要急于求成。首先,我们需要将函数注册到Lua

lua_register(LuaState, "luaname", BMXName)

现在可以在Lua(全局)中以luaname() 的形式调用BMXName()。你可能选择将函数命名与BlitzMax中相同,但你没有必要这样做。

处理来自Lua的参数

[编辑 | 编辑源代码]

假设我们尝试从Lua调用

luaname(810, "Hallo!")

使用上面的示例函数。Lua没有抱怨额外的参数,但我们也无法从函数内部访问它们。它们到哪里去了?Lua将它们放置在参数堆栈上。每个参数都被分配了一个索引,可以通过该索引识别。索引按顺序编号,从1开始。因此,810 可以在索引1处找到,“Hallo!”可以在索引2处找到。现在我们只需要知道从参数堆栈读取值的相应命令,我们就完成了

Function BMXName:Int (LuaState:Byte Ptr)   
   Local int_value:Int    = luaL_checkinteger(LuaState, 1)
   Local str_value:String = luaL_checkstring(LuaState, 2)
   Print int_value
   Print str_value
   Return 0 ' number of values returned to Lua function  
End Function 

返回值给Lua

[编辑 | 编辑源代码]

返回一个或多个值到Lua脚本的操作类似,但你不必指定索引,因为值会自动追加到堆栈。以下是一个示例

Function BMXName:Int (LuaState:Byte Ptr)   
   lua_pushnumber(LuaState, 810)
   lua_pushstring(LuaState, "Hallo!")
   Return 2 ' number of values returned to Lua function  
End Function 

在大多数情况下,你只会返回一个值或根本不返回值,但如你所见,也可以返回更多值。

从BlitzMax调用单个Lua函数

[编辑 | 编辑源代码]

我们知道如何执行完整的Lua脚本,但如果我们只需要一个函数呢?在这种情况下,你首先必须将要调用的函数放在堆栈上,然后是参数。以下是一个示例。Lua脚本

function luafunc(para, str)
   print(para, str)
end

BlitzMax代码

lua_getfield(LuaState, LUA_GLOBALSINDEX, "luafunc") 'Puts the function onto the stack
lua_pushinteger(LuaState, 810)                'First Argument
lua_pushstring(LuaState, "Hallo!")            'Second Argument
lua_call(LuaState, 2, 0)                      'Call the function with 2 arguments and no result 

如果有返回值,它们会在函数执行后被放置到堆栈上。

从BlitzMax访问Lua全局变量

[编辑 | 编辑源代码]

定义或更改全局变量

[编辑 | 编辑源代码]
lua_pushstring(LuaState, "Hallo!")
lua_setglobal (LuaState, "luaglobal") 

第一个命令将“Hallo!”写入堆栈,第二个命令将它放入全局luaglobal。

读取全局变量

[编辑 | 编辑源代码]
lua_getglobal(LuaState, "luaglobal")
Local str:String = lua_tostring(LuaState, -1)

第一个命令将值放入堆栈,第二个命令将它放入BlitzMax变量。

访问所有全局变量

[编辑 | 编辑源代码]

如果你想保存当前Lua VM的状态,你需要找到一种方法来获取所有全局变量。一种方法是使用lua_next函数

lua_pushnil(LuaState)                                         ' first key 
While (lua_next(LuaState, LUA_GLOBALSINDEX) <> 0)             ' iterate through all values of the global environment table
   ' uses 'key' (at index -2) and 'value' (at index -1) 
   Print(lua_typename(LuaState,lua_type(LuaState , - 1))+" - "+lua_tostring(LuaState,-2)+"-"+lua_tostring(LuaState,-1))
   ' removes 'value'; keeps 'key' for next iteration 
   lua_pop(LuaState, 1);
Wend

请注意,这种方法不仅返回全局变量,还返回函数、表等,你需要使用lua_type命令来进行分类。

华夏公益教科书