第27讲|如何使用脚本语言编写周边工具?
文章目录
上一节,我们讲了脚本语言在游戏开发中的应用,我列举了很多 C 语言代码,这些代码做了这样一些事情:
- 使用 C 语言和 Lua 语言进行沟通;
- 在 C 语言代码里,使用了宏和结构,方便批量注册和导入 C 语言函数;
- Lua 代码如何传输内容给 C 语言;
- Lua 虚拟机堆栈的使用。
这一节,我们要用 Lua 脚本来编写一个游戏周边工具 Makefile。游戏周边工具有很多种,并没有一个统一的说法,比如在线更新工具、补丁打包工具、人物模型编辑工具、游戏环境设置工具等等。
你或许就会问了,那我为什么选择 Makefile 工具来编写,而不选择别的周边工具来编写呢?
因为这个工具简单、小巧,我们可以将 Lua 脚本语句直接拿来用作 Makefile 语句,而在这个过程中,我们同时还可以通过 Lua 语句来了解 Lua 的工作机理。而且这个编写过程我们一篇文章差不多就可以说清楚。
而别的周边工具编写起来可能会比较复杂,比如如果要编写类似 Awk 的工具的话,就要编写文本解析和文件查找功能;如果编写游戏更新工具的话,就必须涉及网络基础以及压缩解压缩的功能。
简单直白地说,Makefile 是一种编译器的配置脚本文件。这个文件被 GNU Make 命令读取,并且解析其中的意义,调用 C/C++(绝大部分时候)或者别的编译器(小部分)来将源代码编译成为执行文件或者动态、静态链接库。
我们可以自己定义一系列的规则,然后通过顺利地运行 gcc、cl 等命令来进行源代码编译。
我们先定义一系列函数,来固定我们在 Lua 中所使用的函数。
|
|
这些都是注册到 Lua 内部的 C/C++ 函数。我们现在要将这些函数封装给 Lua 使用,但是在这之前,我们要将大部分的功能都在 C/C++ 里编写好。
随后,我们来看一下,在 Lua 脚本里面,具体是怎么实现 Make 命令操作的。
|
|
首先,第一行对应的就是目标文件 target 函数,后续的每一个 Lua 函数都能在最初的函数定义里找到。
在这个例子当中,我们使用的是 DigitalMars 的 C/C++ 编译器,执行文件叫 dmc.exe。我们可以看到,在 linker 和 compiler 函数里都填写了 dmc.exe,说明编译器和链接器都是 dmc.exe 文件。
现在来看一下在 C/C++ 里面是如何定义这个类的。
|
|
为了便于理解,我将 C++ 类声明改成了 struct,也就是把成员变量改为公有变量,你可以通过一个对象直接访问到。
随后,我们来看一下如何将 target、compiler 和 linker 传入到 C 函数里面。
|
|
在这三个函数里面,我们看到,get_my_make 函数就是返回一个 my_make 类的对象。这个具体就不进行说明了,因为返回对象有多种方式,比如 new 一个对象并且 return,或者直接返回一个静态对象。
随后,我们直接使用了 Lua 函数 lua_tostring,来得到 Lua 传入的参数,比如如果是 target 的话,我们就会得到”test.exe”,并且将这个字符串传给 my_make 对象的 string target 变量。后续的 compiler、linker 也是一样的道理。
我们接着看下面两行。
|
|
这两行填入了 cpp 源文件以及 obj 中间文件,这些填入的参数并没有一个固定值,可能是 1 个,也可能是 100 个,那在 C/C++ 和 Lua 的结合里面,我们应该怎么做呢?
我们看到一个函数 lua_gettop。这个函数是取得在当前函数中,虚拟机中堆栈的大小,所以返回的值,就是堆栈的大小值,比如我们传入 3 个参数,那么返回的就是 3。
接下来可以看到,使用 Lua 的计数方式,从 1 开始计数,并且循环结束的条件是和堆栈大小一样大,然后就在循环内,将传入的参数字符串,压入到 C++ 的 vector 中。
随后的 source_object、compile_param 和 link_param 都是相同的方法,将传入的参数压入到 vector 中。
你可能要问了,我在 Lua 的代码中看到了 TARGET、TARGET、
文章作者 anonymous
上次更新 2024-02-23