如何在Java中使用Lua腳本語(yǔ)言
如何在Java中使用Lua腳本語(yǔ)言是本文要介紹的內(nèi)容,主要是來(lái)學(xué)習(xí)LUA腳本語(yǔ)言在JAVA中如何來(lái)使用,Lua就不說(shuō)了, 現(xiàn)在比較熱門(mén), 語(yǔ)法也很簡(jiǎn)單. 為了在Java中調(diào)用, 折騰了比較長(zhǎng)的時(shí)間, 就把一些東西記在下面.來(lái)看詳細(xì)內(nèi)容講解。
Lua是支持內(nèi)嵌在C程序中的, 但是官方不支持Java. 在網(wǎng)上查了下, 有LuaJava開(kāi)源庫(kù), 拿來(lái)試用了一下, 發(fā)現(xiàn)這個(gè)庫(kù)還算比較完善的. 地址是
- http://www.keplerproject.org/luajava/
這個(gè)LuaJava實(shí)際上就是按照Lua官方文檔, 把Lua的C接口通過(guò)JNI包裝成Java的庫(kù). 下載, 里面是一個(gè).dll, 一個(gè).jar. 把.dll放到j(luò)ava.library.path下, 再把.lib放到classpath中, helloworld運(yùn)行OK.
但是, 測(cè)試的時(shí)候, 很快發(fā)現(xiàn)了第一個(gè)問(wèn)題: 在調(diào)用LuaJava中提供的LuaState.pushInteger 方法的時(shí)候, 出現(xiàn)了錯(cuò)誤 : Unsatisfied Link Error. 其他的LuaState.pushNumber方法倒是沒(méi)有問(wèn)題. 用Depends工具看了下, 這個(gè).dll居然沒(méi)有導(dǎo)出pushInteger這個(gè)函數(shù). 暈....
下載LuaJava的源代碼, 查看了下Luajava.c 和 Luajava.h, 發(fā)現(xiàn)果然里面有點(diǎn)問(wèn)題, 在.h里面定義了JNI中對(duì)應(yīng)Java函數(shù)的C函數(shù)
JNIEXPORT void JNICALL Java_org_keplerproject_luajava_LuaState__1pushInteger
但是.c中沒(méi)有實(shí)現(xiàn)這個(gè)函數(shù). 無(wú)語(yǔ), 看來(lái)大馬虎哪都有啊. 幸虧有源代碼, 照貓畫(huà)虎在Luajava.c中加上這個(gè)函數(shù)的實(shí)現(xiàn),
- JNIEXPORT void JNICALL Java_org_keplerproject_luajava_LuaState__1pushInteger
- (JNIEnv * env, jobject jobj, jobject cptr, jint i)
- {
- lua_State * L = getStateFromCPtr( env , cptr );
- lua_pushinteger(L, i);
- }
然后編譯. 編譯也出現(xiàn)了問(wèn)題了, 官方文檔中說(shuō)可以用VC++來(lái)Build, 但是沒(méi)有說(shuō)官方用的是什么版本. 我用VC2005就不行. 好在Luajava比較小, 就一個(gè).h 一個(gè) .c , 在VC中新建一個(gè).dll項(xiàng)目, 把文件加進(jìn)去, 修改一下build參數(shù) (Include 需要加上lua的頭文件, lib中需要加上lua的.lib文件, 另外要選上 Compile as C Code (/TC) ) Build, 通過(guò)了.
這時(shí)再在Java中調(diào)用pushInteger方法就沒(méi)有問(wèn)題了.
在測(cè)試中, 發(fā)現(xiàn)Luajava提供的文檔中, 對(duì)于Lua腳本怎么調(diào)用Java對(duì)象/方法很詳細(xì), 但是在Java中怎么調(diào)用Lua函數(shù)/取得返回值 就沒(méi)有. 參考了http://www.lua.org/manual/5.1/manual.html#lua_CFunction 的Lua C文檔, 實(shí)現(xiàn)了傳遞對(duì)象到Lua中并取得返回值的代碼:
Test1: 測(cè)試傳遞簡(jiǎn)單類(lèi)型, 并取得返回值:
Lua 腳本(test.lua):
- function test(a,b)
- return a+b
- end
Java代碼:
- static {
- //加載Lua5.1.dll, 因?yàn)長(zhǎng)uaJava最后還是要調(diào)用Lua的東西
- System.loadLibrary("lua5.1");
- }
- public static void main(String[] argu) throws LuaException {
- LuaState L = LuaStateFactory.newLuaState();
- L.openLibs();
- //讀入Lua腳本
- int error = L.LdoFile("test.lua");
- if (error != 0) {
- System.out.println("Read/Parse lua file error. Exit.");
- return;
- }
- //找到函數(shù)test
- L.getField(LuaState.LUA_GLOBALSINDEX, "test");
- //參數(shù)1壓棧
- L.pushInteger(1);
- //參數(shù)2壓棧
- L.pushInteger(2);
- //調(diào)用!! 一共兩個(gè)參數(shù), 1個(gè)返回值
- L.call(2, 1);
- //保存返回值, 到a中
- L.setField(LuaState.LUA_GLOBALSINDEX, "a");
- //讀入a
- LuaObject l = L.getLuaObject("a");
- //打印結(jié)果.
- System.out.println("Result is " + l.getString());
- L.close();
- }
測(cè)試2: 傳遞Java對(duì)象
- class Value {
- public int i;
- public void inc() {
- i++;
- }
- public int get() {
- return i;
- }
- public String toString() {
- return "Value is " + i;
- }
- }
Lua腳本: (該腳本中調(diào)用兩次對(duì)象的inc方法, 并調(diào)用get方法輸出結(jié)果)
- function test1(v)
- v:inc();
- v:inc();
- print("In lua: " .. v:get());
- return v
- end
Java 代碼: (前面都一樣, 略)
- //找到函數(shù)test1
- L.getField(LuaState.LUA_GLOBALSINDEX, "test1");
- //生成新的對(duì)象供測(cè)試
- Value v = new Value();
- //對(duì)象壓棧
- L.pushObjectValue(v);
- //調(diào)用函數(shù)test1, 此時(shí)1個(gè)參數(shù), 1個(gè)返回值
- L.call(1, 1);
- //結(jié)果放在b中.
- L.setField(LuaState.LUA_GLOBALSINDEX, "b");
- LuaObject l = L.getLuaObject("b");
- System.out.println("Result is " + l.getObject());
運(yùn)行結(jié)果:
- Result is Value is 2
- In lua: 2
和預(yù)期的一致.
實(shí)現(xiàn)一個(gè)怪物的創(chuàng)建,把lua里的設(shè)定當(dāng)作初始狀態(tài)傳給monstor,名字為sample monstor,防御10,攻擊10,生命100
1.先導(dǎo)入lib--luajava-1.1.jar
- import org.keplerproject.luajava.LuaState;
- import org.keplerproject.luajava.LuaStateFactory;
- public class Load{
- LuaState luaState;
- /**
- * Constructor
- * @param fileName File name with Lua .
- */
- Load(final String fileName) {
- this.luaState = LuaStateFactory.newLuaState();
- this.luaState.openLibs();
- this.luaState.LdoFile(fileName);
- }
- /**
- * Ends the use of Lua environment.
- */
- void close() {
- this.luaState.close();
- }
- /**
- * Call a Lua inside the Lua to insert
- * data into a Java object passed as parameter
- * @param Name Name of Lua .
- * @param obj A Java object.
- */
- void run(String Name, Object obj) {
- this.luaState.getGlobal(Name);
- this.luaState.pushJavaObject(obj);
- this.luaState.call(1,0);
- }
- }
- public class Monster{
- /* Info */
- protected String race;
- protected int defense;
- protected int attack;
- protected int life;
- /* */
- private Load ;
- public Monster(String race) {
- /* Loads Lua for this race.*/
- this. = new Load(race+".lua");
- /*Call Lua create .*/
- .run("create", this);
- }
- public void setRace(String race) {
- this.race = race;
- }
- public String getRace() {
- return race;
- }
- public int getDefense() {
- return this.defense;
- }
- public void setDefense(int defense) {
- this.defense = defense;
- }
- public int getLife() {
- return this.life;
- }
- public void setLife(int life) {
- this.life = life;
- }
- public void setAttack(int attack) {
- this.attack = attack;
- }
- public int getAttack() {
- return this.attack;
- }
- }
- monstor.lua---
- create(monster)
- monster:setRace("Sample Monster")
- monster:setDefense(10)
- monster:setAttack(10)
- monster:setLife(100)
- end
但總是拋出這個(gè)錯(cuò)誤:
- PANIC: unprotected error in call to Lua API (Invalid method call. No such method.)
不知為何,以后用到的時(shí)候再research.
已經(jīng)查出來(lái),原來(lái)在Monster類(lèi)中少了個(gè)方法:
- public void setRace(String race) {
- this.race = race;
- }
怪不得會(huì)找不到,
要在一lua文件a.lua里導(dǎo)入其他的lua文件b.lua,用require "b"
如果要從lua中運(yùn)算后得到返回參數(shù),則需要做一下修改:在lua文件中改成:
- create(monster)
- monster:setRace("Sample Monster")
- monster:setDefense(10)
- monster:setAttack(10)
- monster:setLife(100)
- return monster
- end
在Load.java中的run改成如下:
- void run(String Name, Object obj) {
- this.luaState.getGlobal(Name);
- this.luaState.pushJavaObject(obj);
- this.luaState.call(1, 1);// 一個(gè)參數(shù),0個(gè)返回
- try {
- Object object =luaState.getObjectFromUserdata(1);
- } catch (LuaException e) {
- e.printStackTrace();
- }
- }
小結(jié):如何在Java中使用Lua腳本語(yǔ)言的內(nèi)容介紹完了,希望通過(guò)本文的學(xué)習(xí)能對(duì)你有所幫助!