在Java中使用Lua脚本语言

来源:互联网 发布:plc编码器编程 编辑:程序博客网 时间:2024/05/22 09:49

转自:http://mobile.51cto.com/iphone-286406.htm

如何在Java中使用Lua脚本语言是本文要介绍的内容,主要是来学习LUA脚本语言JAVA中如何来使用,Lua就不说了, 现在比较热门, 语法也很简单. 为了在Java中调用, 折腾了比较长的时间, 就把一些东西记在下面.来看详细内容讲解。

Lua是支持内嵌在C程序中的, 但是官方不支持Java. 在网上查了下, 有LuaJava开源库, 拿来试用了一下, 发现这个库还算比较完善的. 地址是

  1. http://www.keplerproject.org/luajava/  (不一定能够打开)
  2. http://luaforge.net/projects/luajava/ (这个网站里面的Archived Releases中的luajava是可以点击的,点击后会出现luajava-1.1.zip等
  3. http://github.com/jasonsantos/luajava

解压luajava-1.1-win32-lua51这个包。

这个LuaJava实际上就是按照Lua官方文档, 把Lua的C接口通过JNI包装成Java的库. 下载, 里面是一个.dll, 一个.jar. 把.dll放到java.library.path下, 再把.jar放到classpath中,java/jdk/jre/lib下面,在右击项目名称-》build path -》add external jars-》选中刚才加的luajava-1.1.jar,点击finish 

(java.library.path在哪?http://blog.csdn.net/shy_snow/article/details/6500689)

Code:
  1. public class Test{  
  2.   
  3. public static void main(String args[]){  
  4.   
  5. System.out.println("test");  
  6. System.out.println(System.getProperty("java.library.path"));  
  7.   
  8. }  
  9.   
  10. }  

 结果:

Hello! World
C:/Program Files/Java/jdk1.6.0_17/bin;.;C:/WINDOWS/Sun/Java/bin;C:/WINDOWS/system32;C:/WINDOWS;C:/WINDOWS/system32;C:/WINDOWS;C:/WINDOWS/System32/Wbem;C:/Program Files/Common Files/Thunder Network/KanKan/Codecs;C:/Program Files/TortoiseSVN/bin;C:/Program Files/Microsoft SQL Server/80/Tools/BINN
 一般这个路径是你的java项目引用的jdk下的jre目录的bin目录。java/jdk/jre/bin.

 

————————————————

path 路径,是java编译时需要调用的程序(如java,javac等)所在的地方 。

classpath 类的路径,在编译运行java程序时,如果有调用到其他类的时候,在classpath中寻找需要的类。

______________________________



但是, 测试的时候, 很快发现了第一个问题: 在调用LuaJava中提供的LuaState.pushInteger 方法的时候, 出现了错误 : Unsatisfied Link Error. 其他的LuaState.pushNumber方法倒是没有问题. 用Depends工具看了下, 这个.dll居然没有导出pushInteger这个函数. 晕....

下载LuaJava的源代码, 查看了下Luajava.c 和 Luajava.h, 发现果然里面有点问题, 在.h里面定义了JNI中对应Java函数的C函数

JNIEXPORT void JNICALL Java_org_keplerproject_luajava_LuaState__1pushInteger

但是.c中没有实现这个函数. 无语, 看来大马虎哪都有啊. 幸亏有源代码, 照猫画虎在Luajava.c中加上这个函数的实现,

  1. JNIEXPORT void JNICALL Java_org_keplerproject_luajava_LuaState__1pushInteger  
  2.    (JNIEnv * env, jobject jobj, jobject cptr, jint i)  
  3. {  
  4.     lua_State * L = getStateFromCPtr( env , cptr );  
  5.     lua_pushinteger(L, i);  

然后编译. 编译也出现了问题了, 官方文档中说可以用VC++来Build, 但是没有说官方用的是什么版本. 我用VC2005就不行. 好在Luajava比较小, 就一个.h 一个 .c , 在VC中新建一个.dll项目, 把文件加进去, 修改一下build参数 (Include 需要加上lua的头文件, lib中需要加上lua的.lib文件, 另外要选上 Compile as C Code (/TC) ) Build, 通过了.

这时再在Java中调用pushInteger方法就没有问题了.

在测试中, 发现Luajava提供的文档中, 对于Lua脚本怎么调用Java对象/方法很详细, 但是在Java中怎么调用Lua函数/取得返回值 就没有. 参考了http://www.lua.org/manual/5.1/manual.html#lua_CFunction 的Lua C文档, 实现了传递对象到Lua中并取得返回值的代码:

Test1: 测试传递简单类型, 并取得返回值:(注意下面pushIntegrate方法必须按照上面的进行修改后才能使用,如果没有修改,可以用pushNumber方法代替)

Lua 脚本(test.lua):

  1. function test(a,b)  
  2.     return a+b  
  3. end 

Java代码:

  1. static {  
  2.         //加载luajava-1.1.dll, 因为LuaJava最后还是要调用Lua的东西  
  3.         System.loadLibrary("luajava-1.1");  
  4.     }  
  5.       
  6.     public static void main(String[] argu) throws LuaException {  
  7.           
  8.         LuaState L = LuaStateFactory.newLuaState();  
  9.  
  10.         L.openLibs();  
  11.  
  12.         //读入Lua脚本  
  13.         int error = L.LdoFile("test.lua");  
  14.         if (error != 0) {  
  15.             System.out.println("Read/Parse lua file error. Exit.");  
  16.             return;  
  17.         }   
  18.           
  19.         //找到函数test  
  20.         L.getField(LuaState.LUA_GLOBALSINDEX, "test");  
  21.         //参数1压栈  
  22.         L.pushInteger(1);  //L.pushNumber(1);
  23.         //参数2压栈  
  24.         L.pushInteger(2);  //L.pushNuber(2);
  25.         //调用!! 一共两个参数, 1个返回值  
  26.         L.call(2, 1);  
  27.         //保存返回值, 到a中  
  28.         L.setField(LuaState.LUA_GLOBALSINDEX, "a");  
  29.         //读入a  
  30.         LuaObject l = L.getLuaObject("a");  
  31.         //打印结果.  
  32.         System.out.println("Result is " + l.getString());  
  33.         L.close();  

测试2: 传递Java对象

  1. class Value {  
  2.     public int i;  
  3.     public void inc() {  
  4.         i++;  
  5.     }  
  6.     public int get() {  
  7.         return i;  
  8.     }  
  9.     public String toString() {  
  10.         return "Value is " + i;  
  11.     }  

Lua脚本: (该脚本中调用两次对象的inc方法, 并调用get方法输出结果)

  1. function test1(v)  
  2.     v:inc();  
  3.     v:inc();  
  4.     print("In lua: " .. v:get());  
  5.     return v  
  6. end 

Java 代码: (前面都一样, 略)

  1. //找到函数test1  
  2. L.getField(LuaState.LUA_GLOBALSINDEX, "test1");  
  3. //生成新的对象供测试  
  4. Value v = new Value();  
  5. //对象压栈  
  6. L.pushObjectValue(v);  
  7. //调用函数test1, 此时1个参数, 1个返回值  
  8. L.call(1, 1);  
  9. //结果放在b中.  
  10. L.setField(LuaState.LUA_GLOBALSINDEX, "b");  
  11. LuaObject l = L.getLuaObject("b");  
  12. System.out.println("Result is " + l.getObject()); 

运行结果:

  1. Result is Value is 2  
  2. In lua: 2 

和预期的一致.

实现一个怪物的创建,把lua里的设定当作初始状态传给monstor,名字为sample monstor,防御10,攻击10,生命100

1.先导入lib--luajava-1.1.jar

  1. import org.keplerproject.luajava.LuaState;  
  2. import org.keplerproject.luajava.LuaStateFactory;  
  3.  
  4. public class Load{  
  5. LuaState luaState;  
  6. /**  
  7. * Constructor  
  8. * @param fileName File name with Lua .  
  9. */  
  10. Load(final String fileName) {  
  11. this.luaState = LuaStateFactory.newLuaState();  
  12.  
  13. this.luaState.openLibs();  
  14.    this.luaState.LdoFile(fileName);  
  15.  
  16. }  
  17. /**  
  18. * Ends the use of Lua environment.  
  19. */  
  20. void close() {  
  21. this.luaState.close();  
  22. }  
  23. /**  
  24. * Call a Lua inside the Lua to insert  
  25. * data into a Java object passed as parameter  
  26. * @param Name Name of Lua .  
  27. * @param obj A Java object.  
  28. */  
  29. void run(String Name, Object obj) {  
  30. this.luaState.getGlobal(Name);  
  31. this.luaState.pushJavaObject(obj);  
  32. this.luaState.call(1,0);  
  33. }  
  34. }  
  35.  
  36. public class Monster{  
  37. /* Info */  
  38. protected String race;  
  39. protected int defense;  
  40. protected int attack;  
  41. protected int life;  
  42. /* */  
  43. private Load ;  
  44. public Monster(String race) {  
  45. /* Loads Lua for this race.*/  
  46. this. = new Load(race+".lua");  
  47. /*Call Lua create .*/  
  48. .run("create", this);  
  49. }  
  50.  
  51. public void setRace(String race) {  
  52.    this.race = race;  
  53. }  
  54. public String getRace() {  
  55. return race;  
  56. }  
  57. public int getDefense() {  
  58. return this.defense;  
  59. }  
  60. public void setDefense(int defense) {  
  61. this.defense = defense;  
  62. }  
  63. public int getLife() {  
  64. return this.life;  
  65. }  
  66. public void setLife(int life) {  
  67. this.life = life;  
  68. }  
  69. public void setAttack(int attack) {  
  70. this.attack = attack;  
  71. }  
  72. public int getAttack() {  
  73. return this.attack;  
  74. }  
  75. }  
  76.  
  77. monstor.lua---  
  78.  
  79. create(monster)  
  80. monster:setRace("Sample Monster")  
  81. monster:setDefense(10)  
  82. monster:setAttack(10)  
  83. monster:setLife(100)  
  84. end 

但总是抛出这个错误:

  1. PANIC: unprotected error in call to Lua API (Invalid method call. No such method.) 

不知为何,以后用到的时候再research.

已经查出来,原来在Monster类中少了个方法:

  1. public void setRace(String race) {  
  2.    this.race = race;  

怪不得会找不到,

要在一lua文件a.lua里导入其他的lua文件b.lua,用require "b"

如果要从lua中运算后得到返回参数,则需要做一下修改:在lua文件中改成:

  1. create(monster)  
  2. monster:setRace("Sample Monster")  
  3. monster:setDefense(10)  
  4. monster:setAttack(10)  
  5. monster:setLife(100)  
  6. return monster  
  7. end 

在Load.java中的run改成如下:

  1. void run(String Name, Object obj) {  
  2.    this.luaState.getGlobal(Name);  
  3.    this.luaState.pushJavaObject(obj);  
  4.    this.luaState.call(1, 1);// 一个参数,0个返回   
  5.    try {  
  6.     Object object =luaState.getObjectFromUserdata(1);  
  7.    } catch (LuaException e) {  
  8.     e.printStackTrace();  
  9.    }  

小结:如何在Java中使用Lua脚本语言的内容介绍完了,希望通过本文的学习能对你有所帮助!


0 0
原创粉丝点击