java中使用Lua脚本语言是本文要介绍的内容,主要是来学习LUA脚本语言在JAVA中如何来使用,Lua就不说了, 现在比较热门, 语法也很简单. 为了在Java中调用, 折腾了比较长的时间, 就把一些东西记在下面.来看详细内容讲解。 Lua是支持内嵌在C程序中的, 但是官方不支持Java. 在网上查了下, 有LuaJava开源库, 拿来试用了一下, 发现这个库还算比较完善的. 地址是
- http://www.keplerproject.org/luajava/
这个LuaJava实际上就是按照Lua官方文档, 把Lua的C接口通过JNI包装成Java的库. 下载, 里面是一个.dll, 一个.jar. 把.dll放到java.library.path下, 再把.lib放到classpath中, helloworld运行OK. 但是, 测试的时候, 很快发现了第一个问题: 在调用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);
6. }
然后编译. 编译也出现了问题了, 官方文档中说可以用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: 测试传递简单类型, 并取得返回值: Lua 脚本(test.lua): 1. function test(a,b)
2. return a+b
3. end
Java代码: 1. static {
2. //加载Lua5.1.dll, 因为LuaJava最后还是要调用Lua的东西
3. System.loadLibrary("lua5.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);
23. //参数2压栈
24. L.pushInteger(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();
34. }
测试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. }
12. }
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());
运行结果:
- Result is Value is 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
但总是抛出这个错误:
- 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;
3. }
怪不得会找不到, 要在一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. }
10. }
Java中使用Lua脚本语言的内容介绍完了,希望通过本文的学习能对你有所帮助! - 详解如何实现Lua调试器案例
- 关于Lua Module机制分析
- 初学者必看:Lua入门学习教程
- 关于LUA中闭包操作学习教程
- 详解Lua语言源代码文件含义
- 初学者必备文档:关于Lua源文件分析
|