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)
扩展模块更加完善。含有大量的有用的函数库,非常利于线下工作,如作为工具脚本。另外还有大量的教程。
通过附加模块可实现极为出色的多维数组数值计算能力(个人认为在做机器学习算法等数学模型应用中可能会更合适),严格的说,Lua并没有数组的概念,所有的数据结构都是以table形式存储的。
自带ctypes数据类型。可以访问动态链接库(.so文件或.dll文件),无需对C进行扩展。、
支持远程调试。
Lua有一个简约的不能再简单的语法,这点上与Python没有较大差别。
Python对string与list做了较大层度的扩展,我建议如果想要在Lua中更有成效,就去使用扩展库
Python对Unicode编码的支持更好些
Python对空白字符敏感
Python内置了按位操作,Lua可通过扩展库实现
Python具有错误检测能力,而在这方面,Lua更易出错
Python有更为详细的初学者文档,目前尚缺乏对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 编译器
package com.chilijoy.bean;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
/*******************************************************************************
*
* Monster.java Created on 2014年7月28日
*
* 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);
}
}
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();
}
}
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());
}
}
}
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 2014年7月28日
* 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)));
}
}
--对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
-- 从1到4依次打印
for a=1,4
do print(a)
end
print()
-- 从1到6,每次增长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游戏开发实践指南》有些例子,还在研究。