返回

脚本语言编程:Lua 脚本编程入门

Lua 是一门简单而强大的语言,其本身强大的扩展性使得这门语言在游戏设计等领域发挥着重要的作用。博主曾在 Unity3D 中使用过这门语言,并且针对 Lua 和 Unity、C++等方面的内容进行了学习和讨论。最近因为在【游戏脚本高级编程】这本书中详细介绍了 Lua 脚本的相关内容,因此在这里记录下博主的读书心得,方便以后在需要的时候查阅。

Lua 系统构成

Lua 系统由 Lua 链接库、Luac 编译器、Lua 解释器三部分构成。

  • Lua 链接库主要由 lua.lib 和 lua.h 这两个文件组成。Lua 链接库主要负责对自身进行初始化及关闭操作、装载脚本与执行脚本、提 供可调用交互接口。
  • Luac 编译器是一个由命令行驱动的编译器,其名称为 Luac。当我们需要使用 Luac 编译器来编译一个脚本时,只需输入
1>luac <FileName>    //FileName为脚本名称

我们可以直接通过 Lua 链接库来装载脚本并在装载的过程中实现动态编译,可是这样会造成两个问题,即无法在动态编译过程中获取错误信息和动态编译使脚本加载速度变慢,在使用的时候应该注意到这个问题。

  • Lua 解释器是一个由命令行驱动的代码运行环境,我们可以直接在这个环境中运行和测试脚本代码。

Lua 脚本语法

  • 注释:Lua 脚本的注释以–开始,如
1> --这是一句注释

当我们需要对多行脚本进行注释的时候,可以采取手动换行的方式进行多个单行的注释。

  • 变量:Lua 脚本中的变量是无类型的、隐式声明、首个字符必须是非数字字符、对大小写敏感。Lua 脚本中变量的一个重要特性生支持多重赋值,即允许在赋值运算符的左边同时写下多个变量。如
1-- 变量个数等于数值个数
2x,y,z=1,2,3
3-- 变量个数大于数值个数,z的值为nil
4x,y,z=1,2
5-- 变量个数小于数值个数,3这个数值将被忽略
6x,y=1,2,3
  • 数据类型:在 Lua 中支持 6 种数据类型,即数字(number)、字符串(string)、函数(function)、表(table)、用户数据(userdata)、空值(nil)。
 1数字(number)指整型和浮点型的数据。
 2字符串(string)指字符串类型的数据。
 3函数(function)指一个正式声明的函数的引用。如:
 4function fib(n)
 5  if(n<2) then 
 6  	return n
 7  else
 8    return fib(n-1)+fib(n-2)
 9  end
10end
11-- 在Lua中函数可以赋值给变量
12fib2=fib
13-- 调用fib函数
14print(fib2(5))
15(table)Lua语言中最简单同时是最复杂的数据结构:简单如普通数组,复杂如链表、字典、类等。
16-- 我们在构造一个数据集合时,不需要指定数据类型和数据大小
17-- 完成初始化后的数据集合默认索引从1开始,除非显示地声明索引0处的数值
18-- 构造一个数字类型的数组
19IntArray={1,2,3,4,5}
20-- 构造一个字符串类型的数组
21StringArray={"A","B","C","D"}
22-- 打印IntArray的第一个元素,输出为1
23print(IntArray[1])
24-- 显示声明StringArray索引0处的数值
25StringArray[0]="E"
26-- 打印StringArray的第一个元素和第二个元素,输出为E,A
27print(StringArray[0],StringArray[1])
28-- 打印一个越界的数组值,输出为nil
29print(IntArray[10])
30-- 在Lua中表的数据类型可以是不同的
31table[0]="table"
32table[1]=1
33-- 在Lua中表的索引可以是任意类型,因为表是基于键-值原理来工作的
34Enemy={}
35Enemy["Name"]="Enemy"
36Enemy["HP"]=100
37Enemy["Speed"]=30
38-- 特别地,如果Key是一个合法的字符串类型,那么Table[Key]与Table.Key是等价的。
39Enemy={}
40Enemy.Name="Enemy"
41Enemy.HP=100
42Enemy.Speed=30
43用户数据(userdata)Lua语言中一个特殊的数据类型,它允许在Lua脚本的变量中存放C语言中的指针
44空值(nil)是各种语言中通用的一种数据类型,在此不再赘述。
45Lua脚本中我们可以使用type()函数来获取任意数据的类型
  • 逻辑与表达式:Lua 和大部分的编程类似支持加减乘除等运算,不同的是在 Lua 中使用~=来表示不等关系。 Lua 支持的条件逻辑主要有 if-then-else 以及嵌套的 if-then-else,Lua 不支持 switch 结构。Lua 支持的循环结构主要有 while、for、repea 三种结构,如:
 1-- 这是一个while循环
 2i=0
 3while(i<10) do
 4  i++
 5  print(i)
 6end
 7
 8-- 这是一个for循环
 9for i=0,10 do
10  print(i)
11end 
12
13-- 这是一个repeat循环
14repeat 
15  print(i)
16  i++
17until(i>10)
18
19-- 这是一个扩展的for循环,类似于Foreach结构,主要用来遍历表(table)
20for key,value in tables do
21  print(k,value)
22end

Lua 与 C/C++交互

Lua 与 C/C++交互主要通过 Lua 提供的 C API 来完成,其核心是 Lua 堆栈,一个简单的 C++代码调用 Lua 脚本的示例代码如下:

 1#include <iostream>
 2
 3using namespace std;
 4
 5#include <iostream>
 6
 7extern "C" {
 8#include "lua.h"
 9#include "lualib.h"
10#include "lauxlib.h"
11}
12
13using namespace std;
14
15int main()
16{
17    //创建Lua环境
18    lua_State* L=luaL_newstate();
19    //打开Lua标准库,常用的标准库有luaopen_baseluaopen_packageluaopen_tableluaopen_io
20    //luaopen_osluaopen_stringluaopen_mathluaopen_debug
21    luaL_openlibs(L);
22
23    //下面的代码可以用luaL_dofile()来代替
24    //加载Lua脚本
25    luaL_loadfile(L,"script.lua");
26    //运行Lua脚本
27    lua_pcall(L,0,0,0);
28
29    //将变量arg1压入栈顶
30    lua_getglobal(L,"arg1");
31    //将变量arg2压入栈顶
32    lua_getglobal(L,"arg2");
33
34    //读取arg1arg2的值
35    int arg1=lua_tonumber(L,-1);
36    int arg2=lua_tonumber(L,-2);
37
38    //输出Lua脚本中的两个变量
39    cout <<"arg1="<<arg1<<endl;
40    cout <<"arg2="<<arg2<<endl;
41
42    //将函数printf压入栈顶
43    lua_getglobal(L,"printf");
44    //调用printf()方法
45    lua_pcall(L,0,0,0);
46
47    //将函数sum压入栈顶
48    lua_getglobal(L,"sum");
49    //传入参数
50    lua_pushinteger(L,15);
51    lua_pushinteger(L,25);
52    //调用printf()方法
53    lua_pcall(L,2,1,0);//这里有2个参数、1个返回值
54    //输出求和结果
55    cout <<"sum="<<lua_tonumber(L,-1)<<endl;
56
57    //将表table压入栈顶
58    lua_getglobal(L,"table");
59    //获取表
60    lua_gettable(L,-1);
61    //输出表中第一个元素
62    cout <<"table.a="<<lua_tonumber(L,-2)<<endl;
63
64    //调用C++方法首先需要注册该方法
65    lua_register(L, "AverageAndSum", AverageAndSum);
66}
67
68static int AverageAndSum(lua_State *L)
69{
70  //返回栈中元素的个数
71  int n = lua_gettop(L);
72  //存储各元素之和
73  double sum = 0;
74  for (int i = 1; i <= n; i++)
75  {
76      //参数类型处理
77    if (!lua_isnumber(L, i))
78    {
79        //传入错误信息
80      lua_pushstring(L, "Incorrect argument to 'average'");
81      lua_error(L);
82    }
83    sum += lua_tonumber(L, i);
84  }
85  //传入平均值
86  lua_pushnumber(L, sum / n);
87  //传入和
88  lua_pushnumber(L, sum);
89
90  //返回值的个数,这里为2
91  return 2;
92}

请确保在计算机中安装了 Lua 环境,并在 VC++目录中添加相关的头文件引用和库文件引用。相应的 Lua 脚本代码定义如下:

 1--在Lua中定义两个变量
 2arg1=15
 3arg2=20
 4
 5--在Lua中定义一个表
 6table=
 7{
 8  a=25,
 9    b=30
10}
11
12--在Lua中定义一个求和的方法
13function sum(a,b)
14  return a+b
15end
16
17--在Lua中定义一个输出的方法
18function printf()
19  print("This is a function declared in Lua")
20end
21
22--在Lua中调用C++中定义并且注册的方法
23average,sum=AverageAndSum(20,52,75,14)
24print("Average=".average)
25print("Sum=".sum)
Built with Hugo
Theme Stack designed by Jimmy