【游戏开发】小白学Lua(上)

  在很多游戏中,脚本语言是不可或缺的一部分,很多游戏都使用到了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的值类型,0或者nil都是false,其余的为真。

  (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引擎中。

作者:马三小伙儿 出处:http://www.cnblogs.com/msxh/p/6033679.html 请尊重别人的劳动成果,让分享成为一种美德,欢迎转载。另外,文章在表述和代码方面如有不妥之处,欢迎批评指正。留下你的脚印,欢迎评论! 

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏IT可乐

JVM 运行时的内存分配

  首先我们必须要知道的是 Java 是跨平台的。而它之所以跨平台就是因为 JVM 不是跨平台的。JVM 建立了 Java 程序和操作系统之间的桥梁,JVM 是...

21580
来自专栏xcywt

关于delete 和 new

关于new和delete,有如下代码 // new_test.cpp #include<iostream> using namespace std; cl...

20460
来自专栏欧阳大哥的轮子

深入解构iOS系统下的全局对象和初始化函数

事件源于接入了一个第三方库导致应用出现了大量的crash记录,很奇怪的是这么多的crash居然没有收到用户的反馈信息! 在这个过程中每个崩溃栈的信息都明确的指向...

24320
来自专栏前端真相

为什么数组下标是从0开始?

数组寻址——arr[i] = base_address + i * type_size(1)

31960
来自专栏Android 研究

Java虚拟机基础——3类加载机制

在这个框架图很容易大体上了解Java程序工作原理。首先当程序员写好.java文件后,需要先运行(假设该文件为demo.java)

13040
来自专栏Java架构沉思录

Redis进阶不得不了解的内存优化细节

Redis所有的数据都在内存中,而内存又是非常宝贵的资源。对于如何优化内存使用一直是Redis用户非常关注的问题。本文让我们深入到Redis细节中,学习内存优化...

67720
来自专栏沈唁志

在PHP中strpos函数的正确使用方式

18030
来自专栏宋凯伦的技术小栈

分享调用Java private方法

上周在修复bug时,发现Java类中某方法是private,且类中没有用到,第一感觉是方法多余。其实通过分析,发现原来Native Code会通过JNI调到此方...

24350
来自专栏云霄雨霁

在现有线程安全类中添加功能

18340
来自专栏Java学习网

java开发中代码级别的优化方法总结,有效提高程序性能

负载测试和应用程序监控对于确定应用程序的一些关键性能瓶颈非常有用。但同时,我们需要遵循良好的编码习惯,以避免在对应用程序进行监控的时候出现过多的性能问题。

17720

扫码关注云+社区

领取腾讯云代金券