Lua学习笔记

Lua学习笔记

 

目录

Lua学习笔记    1

需求    2

选型    2

Python    2

Lua    3

分析    4

环境    4

下载所需依赖    4

环境配置    4

代码    5

代码结构如下    5

Monster.java    5

LuaDemo.java    7

MyMonsterThread.java    8

LuaTest.java    9

demo.lua    13

问题    18

总结    19

 

 

 

 

需求

在游戏开发过程中,由于需要支持不同的手机平台,如winPhone、android、iphone等,这样,一套游戏逻辑就需要重新开发多次,而这部分游戏逻辑是与平台无关的,可以单独实现,如果这部分逻辑提炼出来,嵌入到不同的语言中,将会使得维护起来更加方便;

另外,服务器后台在处理游戏逻辑的时候,同样会出现游戏逻辑经常出现变化的情况,比如任务系统的更新等,这样,如果游戏逻辑直接写到code中,会造成每次更新都需要重启服务的情况,我们希望实现热更新,尤其是业务逻辑模块方面的变化,当出现多服的情况下,这部分的更新会更麻烦;

还有就是游戏设计师与程序员沟通的问题,当设计师设计出一套场景后,需要程序员去实现才能看到具体的结果,沟通费时费力还不一定达到预期的效果,如果出现一种脚本语言使得设计师不需要依赖程序员即可独立设计并表现出游戏场景,同时设计师与程序员都熟悉这种脚本语言,则对双方都受益。

选型

市面上出现的适合于游戏开发的脚本语言主要有Python与Lua,因为这两种脚本语言都可以直接调用C++功能(虽然我是一个java程序员,但不得不承认,绝大部分的好玩的大型游戏都是基于C++实现的),事实上,这两种脚本语言的兼容性与扩展性都非常好(都可以集成到Java中)

关于Python与Lua的对比(http://lua-users.org/wiki/LuaVersusPython)

Python

扩展模块更加完善。含有大量的有用的函数库,非常利于线下工作,如作为工具脚本。另外还有大量的教程。

通过附加模块可实现极为出色的多维数组数值计算能力(个人认为在做机器学习算法等数学模型应用中可能会更合适),严格的说,Lua并没有数组的概念,所有的数据结构都是以table形式存储的。

自带ctypes数据类型。可以访问动态链接库(.so文件或.dll文件),无需对C进行扩展。、

支持远程调试。

Lua有一个简约的不能再简单的语法,这点上与Python没有较大差别。

Python对string与list做了较大层度的扩展,我建议如果想要在Lua中更有成效,就去使用扩展库

Python对Unicode编码的支持更好些

Python对空白字符敏感

Python内置了按位操作,Lua可通过扩展库实现

Python具有错误检测能力,而在这方面,Lua更易出错

Python有更为详细的初学者文档,目前尚缺乏对Lua介绍的入门教程

 

Lua

Lua比Python小巧的多,python22.dll 824KB,而一个基本的lua引擎仅在100KB以下

占用内存更少

看起来没有任何的指针使用

编译器与解释器执行起来更快

在脚本与C语言中,仅用少量的"胶水代码"即可实现较为优雅且简单的API交互

不适用可以得到复杂而易出错对象的引用计数

Lua以作为一门配置语言开始,在需要创建与配置文件的时候(尤其是在游戏中),他是非常了不起的

Lua有一个非常漂亮且简单强大的语法,与Python相比,可以用更少的代码

Lua有一个小巧简单稳定的代码库,如果需要,查看与修改很容易,但可能文档不如Python完善

Lua很少有扩展组件使之更易为一个专门的需要做绑定,Python则需要众多的模块

Lua支持多线程操作,多个解释器可以同存于一个进程中,每一个解释器都可以在自己的线程中独立运行,因此,Lua更适合在多线程程序中嵌入

Lua对空白字符不敏感

Lua支持多线程开箱即用,可在一个单独的线程或进程中有多个解释器,而Python不支持多线程,多线程可以访问解释器,但需要每个线程都必须持有全局锁

 

分析

通过以上分析,在做独立的运行程序或脚本时候,采用Python是一个不错的选择(如线下分析等任务),而作为脚本嵌入到另外一种语言中,更推荐使用Lua

环境

下载所需依赖

Win32:

Win64 :

 

其他环境:下载地址:http://www.keplerproject.org/luajava/index.html#download

 

源码以及文档:

教程:

 

环境配置

将luajava-1.1.dll加入到jre的bin目录下

将luajava-1.1.jar引入到工程的环境变量中

下载lua的eclipse插件Lua Development Tools

如需单独调试Lua,则需要单独安装LuaForWindows 编译器

代码

代码结构如下

 

Monster.java

 

package com.chilijoy.bean;

 

import org.apache.commons.lang3.builder.ReflectionToStringBuilder;

 

/*******************************************************************************

*

* Monster.java Created on 2014728

*

* Author: linfenliang

*

* Description:

*

* Version: 1.0

******************************************************************************/

 

public class Monster {

    private String race;//种族

    private int defense;//防御值

    private int attack;//攻击值

    private int life;//生命值

 

    public String getRace() {

        return race;

    }

 

    public void setRace(String race) {

        this.race = race;

    }

 

    public int getDefense() {

        return defense;

    }

 

    public void setDefense(int defense) {

        this.defense = defense;

    }

 

    public int getAttack() {

        return attack;

    }

 

    public void setAttack(int attack) {

        this.attack = attack;

    }

 

    public int getLife() {

        return life;

    }

 

    public void setLife(int life) {

        this.life = life;

    }

    @Override

    public String toString() {

        return ReflectionToStringBuilder.toString(this);

    }

}

 

LuaDemo.java

 

package com.chilijoy.lua;

 

import java.io.File;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

 

/*******************************************************************************

*

* LuaDemo.java Created on 2014年7月28日

*

* Author: linfenliang

*

* Description:

*

* Version: 1.0

******************************************************************************/

 

public class LuaDemo {

    public static final String luaPath = "." + File.separator + "conf" + File.separator ;

    public static void main(String[] args) {

        ExecutorService service = Executors.newSingleThreadExecutor();

        for(int i=0;i<500000;i++){

            service.execute(new MyMonsterThread());

        }

        service.shutdown();

    }

    

}

 

 

MyMonsterThread.java

 

package com.chilijoy.lua;

 

import java.io.File;

 

import org.keplerproject.luajava.LuaState;

import org.keplerproject.luajava.LuaStateFactory;

 

import com.chilijoy.bean.Monster;

 

/*******************************************************************************

*

* MyMonster.java Created on 2014年7月28日

*

* Author: linfenliang

*

* Description:设计存在多次打开关闭问题,弃用

*

* Version: 1.0

******************************************************************************/

 

public class MyMonsterThread extends Thread {

    static final String luaPath = "." + File.separator + "conf" + File.separator + "demo.lua";

 

    @Override

    public void run() {

        LuaState lua = null;

        try {

            Monster m = new Monster();

            // System.out.println("monster_before:" + m);

            lua = LuaStateFactory.newLuaState();

            lua.openLibs();

            lua.LdoFile(luaPath);

            lua.getField(LuaState.LUA_GLOBALSINDEX, "create");

            // lua.pushObjectValue(monster);

            lua.pushJavaObject(m);

            lua.call(1, 0);

            // System.out.println("monster_after:" + m);

        } catch (Exception e) {

            e.printStackTrace();

        } finally {

            if (lua != null) {

                lua.close();

            }

            System.out.println(this.getName());

        }

    }

}

 

 

LuaTest.java

 

 

package com.chilejoy.lua;

 

 

import java.util.ArrayList;

import java.util.Iterator;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

 

import org.junit.Assert;

import org.junit.Test;

import org.keplerproject.luajava.LuaException;

import org.keplerproject.luajava.LuaObject;

import org.keplerproject.luajava.LuaState;

import org.keplerproject.luajava.LuaStateFactory;

 

import com.chilijoy.bean.Monster;

import com.chilijoy.lua.LuaDemo;

import com.chilijoy.lua.MyMonsterThread;

 

/*******************************************************************************

 

* LuaTest.java Created on 2014728

 

* Author: linfenliang

 

* Description:

 

* Version: 1.0

 

******************************************************************************/

 

public class LuaTest {

    static final int cycleTimes = 1000;

    @Test

    public void test() throws LuaException {

        System.out.println("-------input object test-------");

        LuaState lua = null;

        Monster m = new Monster();

        System.out.println("monster_before:" + m);

        lua = LuaStateFactory.newLuaState();

        lua.openLibs();

        lua.LdoFile(LuaDemo.luaPath + "demo.lua");

        lua.getField(LuaState.LUA_GLOBALSINDEX, "create");

        // lua.pushObjectValue(monster);

        lua.pushJavaObject(m);

        lua.call(1, 1);//传入一个参数,传出1个参数

        lua.setField(LuaState.LUA_GLOBALSINDEX, "monster");

        LuaObject obj = lua.getLuaObject("monster");

        System.out.println("monster_lua:"+obj.getObject());

        System.out.println("monster_after:" + m);

        Assert.assertEquals(obj.getObject(), m);

        lua.close();

    }

    @Test

    public void testHelloWorld(){

        System.out.println("-------hello ,world test-------");

        LuaState lua = LuaStateFactory.newLuaState();

        lua.openLibs();

        lua.LdoFile(LuaDemo.luaPath + "demo.lua");

        lua.getField(LuaState.LUA_GLOBALSINDEX, "hello");

        lua.call(0, 0);

        lua.close();

    }

    @Test

    public void calculateTest(){

        

        System.out.println("--------calculate---------");

        LuaState lua = null;

        lua = LuaStateFactory.newLuaState();

        lua.openLibs();

        lua.LdoFile(LuaDemo.luaPath + "demo.lua");

        lua.getField(LuaState.LUA_GLOBALSINDEX, "calculate");

        lua.pushNumber(3);

        lua.pushNumber(5);

        lua.pushNumber(8);

        lua.call(3, 1);

//        lua.setField(LuaState.LUA_GLOBALSINDEX, "result");

//        LuaObject obj = lua.getLuaObject("result");

        LuaObject obj = lua.getLuaObject(1);

        System.out.println("calculate result:"+obj.getNumber());

        lua.close();

    }

    @Test

    public void multipleReturnValueTest(){

        System.out.println("--------multipleReturnValue---------");

        LuaState lua = null;

        lua = LuaStateFactory.newLuaState();

        lua.openLibs();

        lua.LdoFile(LuaDemo.luaPath + "demo.lua");

        

        lua.getField(LuaState.LUA_GLOBALSINDEX, "getValues");

        lua.pushNumber(3);

        lua.pushNumber(5);

        lua.pushNumber(8);

        lua.call(3, 3);

        for(int i=1;i<=3;i++){

            LuaObject o1 = lua.getLuaObject(i);

            System.out.println("获取第"+i+"个返回值:"+o1.getNumber());

        }

        

        lua.close();

    }

    @Test

    public void nestedFuncTest(){

        System.out.println("------------nestedFunc-----------");

        LuaState state = LuaStateFactory.newLuaState();

        state.openLibs();

        state.LdoFile(LuaDemo.luaPath+"demo.lua");

        

        state.getField(LuaState.LUA_GLOBALSINDEX, "nestedFunc");

        state.pushNumber(3);

        state.pushNumber(5);

        state.pushNumber(8);

        state.call(3, 1);

        LuaObject obj = state.getLuaObject(1);

        System.out.println("nestedFunc 返回值:"+obj.getNumber());

        state.close();

    }

    

    @Test

    public void cycleTest(){

        System.out.println("--------cycle(for(){}) ---------");

        LuaState state = LuaStateFactory.newLuaState();

        state.openLibs();

        state.LdoFile(LuaDemo.luaPath + "demo.lua");

        double a,b,c;

        for(int i=0;i<cycleTimes;i++){

            a= Math.random();

            b = Math.random();

            c = Math.random();

            state.getField(LuaState.LUA_GLOBALSINDEX, "calculate");

            state.pushNumber(a);

            state.pushNumber(b);

            state.pushNumber(c);

            state.call(3, 1);

//            state.setField(LuaState.LUA_GLOBALSINDEX, "result");

//            LuaObject obj = state.getLuaObject("result");

            LuaObject obj = state.getLuaObject(1);

            state.pop(1);

            System.out.println(String.format(" a=%6f,b=%6f,c=%6f sum=>%6f", a,b,c,obj.getNumber()));

        }

        state.close();

    }

//    @Test

    public void concurrentTest() throws InterruptedException {

        System.out.println("--------concurrent ---------");

        ExecutorService service = Executors.newFixedThreadPool(5);

        for(int i=0;i<cycleTimes;i++){

            service.execute(new MyMonsterThread());

        }

        Thread.sleep(5000);

        service.shutdown();

    }

//    @Test

    public void concurrentSingleThreadTest() throws InterruptedException {

        System.out.println("--------concurrentSingleThread ---------");

        ExecutorService service = Executors.newSingleThreadExecutor();

        for(int i=0;i<cycleTimes;i++){

            service.execute(new MyMonsterThread());

        }

        service.shutdown();

    }

    @Test

    public void testFunc() throws InterruptedException{

        System.out.println("-----------testFunc-----------");

        LuaState state = LuaStateFactory.newLuaState();

        state.openLibs();

        state.LdoFile(LuaDemo.luaPath+"demo.lua");

        

        state.getField(LuaState.LUA_GLOBALSINDEX, "testFunc");

        state.call(0, 0);

        state.close();

//        System.out.println(Math.toRadians(30));

//        System.out.println(Math.sin(Math.toRadians(30)));

    }

}

 

 

demo.lua

 

--monster赋值(传入对象,返回对象)

function create(monster)

monster:setRace("the first demo")

monster:setDefense(10)

att = monster:getAttack()

print("monster.attack=>"..att)

monster:setAttack(10-att)

monster:setLife(100)

print("create monster !");

return monster

end

 

--打印输出测试

function hello()

    print("Hello World from Lua !");

end

--数值计算结果输出

function calculate(a,b,c)

    return a+b+c

end

--多返回值测试

function getValues(a,b,c)

return a,b,c

end

--函数嵌套调用

function nestedFunc(a,b,c)

printFunc()

    return calculate(a,b,c)

end

function printFunc()

print("提供给nestedFunc 函数调用的打印函数 !");

end

function testFunc()

print("------LUA-----testFunc--------START-----")

a=1

b="123"

c={4,5,6}

d=hello

print(type(a))--打印数据类型

print(type(b))

print(type(c))

print(type(d))

print(_VERSION)--_VERSION 打印LUA版本

print( a, b,c, d)--多个返回值输出

--多行数据

reservedWords =[[Lua reserved words are:

and, break, do, else, elseif,end, false,

for, function, if, in, local, nil, not,

or,repeat, return, then, true, until, while]]

print(reservedWords)

 

--多个变量赋值

a1,a2,a3=1,"2_",3

print(a1,a2,a3)

--数据互换

b1,b2=3,5

print(b1,b2)

b1,b2=b2,b1

print(b1,b2)

 

a,b,c,d,e = 1, 1.123, 1E9, -123, .0008

print("a="..a, "b="..b, "c="..c, "d="..d, "e="..e) --字符串连接用 .. 取代"+"\

 

 

io.write("io.write writes to stdout but without new line.")

io.write(" Use an empty print to write a single new line.")

print()

 

a={} -- {} empty table

b={1,2,3}

c={"a","b","c"}

print(a,b,c) -- tables 不能被直接打印

 

---------测试object格式数据----------------

user={}

user.username="linfenliang"

user.password="123456"

user.age=26

user.isMan=true

 

if(user.age>20) then

print(user.username ,"is more than 20 years old")

elseif(user.age>10) then

print(user.username, "maybe a student")

else

print(user.username, "is just a little boy ")

end

 

if(user.username=="linfenliang") then

print("yes,I am linfenliang !")

else

print("sorry,you got the wrong guy!")

end

 

print(user.username,user.password,user.age,user.isMan)

 

judge(user)

 

 

 

print "------LUA-----testFunc --------END -----" --也可不添加括号

end

--如果 age==26,address shanghai,否则为 not in shanghai

function judge(user)

user.address = (user.age==26) and "I am in Shanghai" or "I am not in Shanghai"

print(user.address)

 

while(user.age~=30) do

user.age=user.age+1

io.write(" My age is growing ..."..user.age)

end

 

print()

 

repeat

user.age=user.age-1

print(" I am beginning young "..user.age)

until user.age==26

 

-- 14依次打印

for a=1,4

do print(a)

end

 

print()

-- 16,每次增长3

for a=1,6,3

do print(a)

end

print()

--pairs 迭代table元素

for key,value in pairs({12,8,9,7})

do print(key,value)

end

 

arr = {1,2,3,"four","five",6}

for k,v in pairs(arr)

do print(k,v)

end

 

a=0

while true do

a=a+1

if a==10 then

break

end

end

print("循环累加:"..a)

--全局变量与局部变量测试

sayHello()

print(word_a,word_b)

--字符串格式化测试

io.write(string.format("hello,now is %s, I am %s, I am %s",os.date(),"linfenliang","a good man!\n"))

--数学公式测试

print(math.sqrt(81),math.pi,math.sin(0.5235987755982988))

--字符串操作

--string.byte, string.char, string.dump, string.find, string.format,

--string.gfind, string.gsub, string.len, string.lower, string.match,

--string.rep, string.reverse, string.sub, string.upper

print(string.reverse("abcdefg"),string.rep("abcd",5),string.find("abcdeadvdsrerdv","dv"))

--table测试

t = {1}

table.insert(t,2)

table.insert(t,3)

table.sort(t,function(v1,v2) return v1>v2 end)

print("table t==>"..table.concat(t,":"))

table.insert(t,"iii")

--输出

for k,v in ipairs(t)

do print(k,v)

end

--Lua IO 操作

-- IO 函数:

-- io.close , io.flush, io.input, io.lines, io.open, io.output, io.popen,

-- io.read, io.stderr, io.stdin, io.stdout, io.tmpfile, io.type, io.write,

-- file:close, file:flush, file:lines ,file:read,

-- file:seek, file:setvbuf, file:write

 

print(io.open("E://demo.lua","r"))

 

--os.clock, os.date, os.difftime, os.execute, os.exit, os.getenv,

--os.remove, os.rename, os.setlocale, os.time, os.tmpname

print(os.date())

 

dofile("E://demo.lua")

 

str_01 = "print(\"Hello,this function is load from String!\")"

loadstring(str_01)()

math.randomseed(os.time())

a = math.random(10,20)

b = math.random(10,20)

c = math.random(10,20)

d = math.random(10,20)

e = math.random(10,20)

f = math.random(10,20)

print(a,b,c,d,e,f)

 

end

word_a = "hello"

--测试本地变量与全局变量

function sayHello()

local word_a = "nihao"

word_b = "I am good"

print(word_a,word_b)

end

问题

1、在做并发测试时,发现如果多次创建关闭 LuaState,会出现异常,甚至会导致JVM崩溃,分析原因可能为加载编译器与执行器占用内存过大导致,但是我将JVM内存参数改为512MB还是会出现这个问题,还是有疑问。

总结

一直没有找到一个比较典型的使用案例,《Lua游戏开发实践指南》有些例子,还在研究。

你可能感兴趣的:(lua)