在很多游戏中,脚本语言是不可或缺的一部分,很多游戏都使用到了Lua,js,python一类的脚本,脚本语言可以在很多方面给开发进程带来帮助。脚本语言可以作为初始化文件读入变量和游戏数据的一个快速而方便的方法。它们通常因为具有节省编译时间提高生产效率、提高创造性和拓展性的有点而受到众多游戏开发厂商的青睐。在本篇博客中,马三将和大家一起学习一下Lua这门脚本语言。
一、搭建Lua运行环境
学习任何一门编程语言恐怕都是要先搭建起来它的开发环境,这样才能多写代码多练习。Lua有一个交互的解释程序(lua.exe),你可以用它来验证一些小的代码片段,但是对于比较长和复杂的代码,最好是使用C/C++的Lua API来运行,下面的代码就是从C/C++程序中运行一个Lua脚本所需的代码块:
extern "C"
{
#include <Lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
第一步要做的就是包含相关的头文件,因为Lua是一个纯C的库,所以必须显式地让编译器知道这一点,不然就会遇到问题。通过将#include 和 extern "C"一起使用就可以解决了。
//包含lua库。如果你的编译器不支持这个指令的话,那么别忘了在你的项目设置中加入这些库
#pragma comment(lib,"lua.lib")
#pragma comment(lib,"lualib.lib)
#include <iostream>
int main(){
//创建一个lua state
lua_State *pL=lua_open();
}
每一个运行的脚本文件都在一个动态分配的叫做lua_State的数据结构中运行。Lua库中的每一个函数的调用都需要把lua_State的指针作为一个参数传递给那个函数,因此在运行一个Lua脚本文件之前,必须通过lua_open来创建一个Lua State。
//开启lua中的标准库
lua_open_base(pL);
luaopen_string(pL);
luaopen_table(pL);
luaopen_math(pL);
luaopen_io(pL);
Lua中有几个标准库,它们提供了输入输出、算术计算、字符串操作等一系列的功能函数。上面的几行代码可以让你在脚本里调用这些库命令,就像C++#include响应的库一样。
if(int error=lua_dofile(pL,"lua_script.lua") !=0 ){
std::cout<<"error!"<<endl;
return -1;
}
使用lua_dofile命令可以装入、编译、运行Lua脚本。如果运行的时候报错了,那么它会返回一个错误的代码。
二、Lua的变量、类型、操作符和条件结构
搭建好环境终于可以写些Lua代码练练手了。但是在这之前我们还是先来熟悉一下Lua的变量、类型、操作符和条件结构(如果你之前有任何一门编程语言的基础,那么这些内容学起来将会十分轻松)。
1.Lua变量
Lua是一门动态语言,它和C++/Java不同,变量是可以被赋予任何类型的值(这点和js,python等脚本一样),比如:
--lua脚本开始啦!
name="masanxiaohuoer"
print("Name="..name);
pi=3.1415926
name=pi
pi=false
在Lua中,注释通常是以“--”开始的,如果要写多行的注释,可以这样的结构:--[[这是一段注释内容]]。在lua中,每句代码后面的分号可写可不写,但是当你的代码跨行的时候分号是必不可少的。同时在lua中可以同时给多个变量赋予多个值。
a,b,c,d = 1,2,3,4
如果左侧的变量个数比右侧的多的话,那么多余出来的变量就会被赋予nil值,nil在lua中表示没有意义,空值(类似于C++中的NULL)。如果右侧的值多的话,那么多余的值就会被丢弃掉了。在Lua中,有3中不同的变量:global(全局)、local(局部)、table fields(表)。如果一个变量没有用local修饰的话,那么它默认就是global的。在一个变量被赋值之前,它的值是nil。
2.Lua类型
Lua中有以下的8种基本数据类型:
(1)Nil空
nil和其他的类型都不同,她用来表示没有意义,空值。一旦给一个值赋予了nil,它就消失了,好像从来没有存在过一样。
(2)Number数值
number类型用来表示浮点数。在lua内部,这个值被处理为double。因此,当传递number类型的变量给C/C++程序的时候,要记得将它们映射成对应的正确类型。
(3)String字符串
string类型是字符串类型,你可以使用“..”来链接两个字符串。如果有一边的类型不是string的话,那么它会被转型为string类型,然后连接。
(4)Boolean布尔
用来表示true或者false的值类型,false或者nil都是假,其余的为真。
(5)Function函数
和C/C++不同,在Lua中,函数也是一种类型,也可以赋值给一个变量。因此通过使用那个变量的名字,你就可以调用那个函数。因为Lua是弱类型的语言,参数列表和返回值都不需要指定类型。下面是一个简单的例子,求两个数之和。在Lua中,函数块通过end关键字来结束。
add=function(a,b)
return a+b
end
如果你习惯用的是java或者C++一类的语言的话,可能会对这个语法感觉有点陌生。Lua提供了另外一个定义一个函数的方式,这样看起来更像C++/java了:
function add(a,b)
return a+b
end
和C++不同的是,lua的函数可以一次返回多个变量,比如下面这样写是完全没有问题的:
function Increse(a,b)
return a+1,b+1
end
a=2,b=4;
a,b=Increase(a,b)
print(a,b)
(5)Table表
table是Lua中一种非常重要也非常强大的数据类型,你可以把表看成一种关联数组或者哈希表。这意味着你不但可以用整数来索引一个表,也可以使用任何类型的键值来索引一个表,而且lua的表是混合类型的,它们可以包含不同的数据类型。
--创建一个table
my_table={}
--添加一些数据到表中
my_table[1]=2333
my_table[2]=666
my_table[3]="HelloWorld"
--或者你也可以一次性的初始化一个表
my_table={2333,666,"HelloWorld"}
--关联索引
my_table["one"]=2333
my_table[6]="Study"
--除了使用[]以外,我们还可以使用.来存取一个值
my_table.one =2333
--函数也可以赋值给表
function add(a,b)
return a+b
end
my_table={}
my_table["add"]=add
print(my_table.add(2,3))
(6)UserData用户数据
userdata类型允许Lua变量存储定制的C/C++数据。一个userdata类型的变量不能在Lua中创建和修改,只有通过C/C++接口才可以(下篇我们会介绍这种方法)。
(7)Thread线程
通过这种类型,我们可以产生并运行新的线程
3.逻辑操作符
Lua中有三种逻辑操作符,分别是:and,or,和not。他们和C++中的&&、||和!很像,并且和C++一样,只有在必要的情况下,他们才会检查第二个条件。nil和false为假,其他都为真。
4.条件结构
Lua中提供了if\while\repeat\for几种条件结构。lua的几个版本的if和while控制结构和C++很类似,只不过lua中条件不需要写在小括号中。
if a==4 then
print("four")
else
print("other")
end
--while循环
while a<=100 then
a=a+1
end
print(a)
--while和if语句都已end关键字结束
--repeat和until关键字一起联用,就像这样:
repeat
a=a+1
print(a)
until a==100
--for结构有两个版本,一个用于数字,一个用于表
--用于数字的for循环的语法:
for var=low_value,high_value,step do
xxxxxx
end
--举例
for a=10,20,2 do
print(a)
end
和C/C++一样,你也可以使用break来退出循环。
另外还有一种for循环用来遍历表
--语法
for key,value in table do
xxxxx
end
key和value分别代表键和值,table就是我们要遍历的表。
--举例
my_table={a=1,b=2,c=3}
for k,v in my_table do
print(k,v)
end
到现在,我们已经稍微对Lua有了一些了解,但是我们还不能用它来为我们的游戏程序服务。下篇我们将共同学习Lua和C/C++的接口,以及Lua如何应用在Cocos2d-X和Unity引擎中。
作者:马三小伙儿