2012-05-06 17 views
11

我正在開發一個使用Lua腳本的Java遊戲。爲了執行這些腳本,我使用了LuaJ和Java的ScriptEngine類。例如...如何在Java應用程序中在Android上運行Lua腳本?

ScriptEngineManager sem = new ScriptEngineManager(); 
scriptEngine = sem.getEngineByExtension(".lua"); 
script = ((Compilable)scriptEngine).compile("some lua here"); 

然而,這顯然是不支持在Android(東西與Android沒有一個完全成熟的JVM做,我讀的地方)。有沒有一種方法可以在Android上使用Lua腳本?也許有一個LuaJ替代品?也許有一種直接使用LuaJ編譯和執行Lua腳本的方法(雖然我看不到)。

僅供參考,我看到這個錯誤,當我嘗試在Android上運行此代碼:

05-06 16:12:32.870: E/dalvikvm(17509): Could not find class 'javax.script.ScriptEngineManager', referenced from method unearth.levels.LevelReader.<init> 
05-06 16:12:32.870: W/dalvikvm(17509): VFY: unable to resolve new-instance 787 (Ljavax/script/ScriptEngineManager;) in Lunearth/levels/LevelReader; 
05-06 16:12:32.870: D/dalvikvm(17509): VFY: replacing opcode 0x22 at 0x0018 
05-06 16:12:32.875: E/dalvikvm(17509): Could not find class 'javax.script.Compilable', referenced from method unearth.levels.LevelReader.parseScript 
05-06 16:12:32.875: W/dalvikvm(17509): VFY: unable to resolve check-cast 782 (Ljavax/script/Compilable;) in Lunearth/levels/LevelReader; 
05-06 16:12:32.875: D/dalvikvm(17509): VFY: replacing opcode 0x1f at 0x0047 
05-06 16:12:32.875: W/dalvikvm(17509): VFY: unable to resolve exception class 788 (Ljavax/script/ScriptException;) 
05-06 16:12:32.875: W/dalvikvm(17509): VFY: unable to find exception handler at addr 0x51 
05-06 16:12:32.875: W/dalvikvm(17509): VFY: rejected Lunearth/levels/LevelReader;.parseScript (Lorg/w3c/dom/Element;Lunearth/levels/Level;)V 
05-06 16:12:32.875: W/dalvikvm(17509): VFY: rejecting opcode 0x0d at 0x0051 
05-06 16:12:32.875: W/dalvikvm(17509): VFY: rejected Lunearth/levels/LevelReader;.parseScript (Lorg/w3c/dom/Element;Lunearth/levels/Level;)V 
05-06 16:12:32.875: W/dalvikvm(17509): Verifier rejected class Lunearth/levels/LevelReader; 
05-06 16:12:32.890: W/dalvikvm(17509): threadid=11: thread exiting with uncaught exception (group=0x40c331f8) 
05-06 16:12:32.895: E/AndroidRuntime(17509): FATAL EXCEPTION: GLThread 1062 
05-06 16:12:32.895: E/AndroidRuntime(17509): java.lang.VerifyError: unearth/levels/LevelReader 
05-06 16:12:32.895: E/AndroidRuntime(17509): at unearth.Game.startGame(Game.java:201) 
05-06 16:12:32.895: E/AndroidRuntime(17509): at unearth.Game.update(Game.java:713) 
05-06 16:12:32.895: E/AndroidRuntime(17509): at unearth.screens.LoadScreen.update(LoadScreen.java:56) 
05-06 16:12:32.895: E/AndroidRuntime(17509): at unearth.UnearthListener.render(UnearthListener.java:71) 
05-06 16:12:32.895: E/AndroidRuntime(17509): at com.badlogic.gdx.backends.android.AndroidGraphics.onDrawFrame(AndroidGraphics.java:423) 
05-06 16:12:32.895: E/AndroidRuntime(17509): at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1462) 
05-06 16:12:32.895: E/AndroidRuntime(17509): at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1216) 
05-06 16:12:58.600: D/dalvikvm(17509): GC_CONCURRENT freed 334K, 3% free 16196K/16647K, paused 2ms+6ms 

更新:

也許這個項目有一些有用的代碼? http://code.google.com/p/android-scripting/

回答

11

我發現了一種在Android上使用LuaJ的方法! :-)

關鍵是直接使用LuaJ API,而不是通過javax.script。要弄清楚因爲沒有教程是有點棘手的,所以這裏有一個前後,這樣其他人就不必經過LuaJ源代碼和JavaDoc。我真的希望這可以幫助別人,因爲它驅使我瘋狂!

注: 「secretgame」 是不是我的遊戲;-)

後的實際名稱:

package secretgame.scripting; 

import java.io.ByteArrayInputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.util.ArrayList; 

import org.luaj.vm2.LuaClosure; 
import org.luaj.vm2.LuaTable; 
import org.luaj.vm2.LuaValue; 
import org.luaj.vm2.Prototype; 
import org.luaj.vm2.compiler.LuaC; 
import org.luaj.vm2.lib.jse.CoerceJavaToLua; 
import org.luaj.vm2.lib.jse.JsePlatform; 

import secretgame.SecretGameException; 
import secretgame.events.EventArgs; 
import secretgame.levels.Level; 

public class DirectLuaj implements Lua 
{ 
    private final Level level; 
    private final ScriptTools scriptTools; 
    private final ScriptEvents scriptEvents; 
    private int nextId = 0; 
    private ArrayList<LuaClosure> scripts = new ArrayList<LuaClosure>(); 

    public DirectLuaj(Level level, ScriptTools scriptTools, 
     ScriptEvents scriptEvents) 
    { 
    this.level = level; 
    this.scriptTools = scriptTools; 
    this.scriptEvents = scriptEvents; 
    } 

    @Override 
    public int add(String scriptText) throws SecretGameException 
    { 
    try { 
     InputStream input = new ByteArrayInputStream(scriptText.getBytes()); 
     Prototype p = LuaC.compile(input, "script"); 
     LuaValue g = JsePlatform.standardGlobals(); 
     LuaClosure c = new LuaClosure(p, g); 
     scripts.add(c); 
    } 
    catch (IOException e) { 
     throw new SecretGameException("compile failed", e); 
    } 

    return nextId++; 
    } 

    @Override 
    public void run(int id, EventArgs args) throws SecretGameException 
    { 
    LuaClosure script = scripts.get(id); 

    LuaTable bindings = new LuaTable(); 

    bindings.set("java", toLua(scriptTools)); 
    bindings.set("level", toLua(level)); 
    bindings.set("args", toLua(args)); 
    bindings.set("events", toLua(scriptEvents)); 

    script.setfenv(bindings); 

    script.call(); 
    } 

    private LuaValue toLua(Object javaValue) { 
    return javaValue == null? LuaValue.NIL: 
      javaValue instanceof LuaValue? (LuaValue) javaValue: 
      CoerceJavaToLua.coerce(javaValue); 
    } 
} 

前:

package secretgame.scripting; 

import java.util.ArrayList; 

import javax.script.Bindings; 
import javax.script.Compilable; 
import javax.script.CompiledScript; 
import javax.script.ScriptEngine; 
import javax.script.ScriptEngineManager; 
import javax.script.ScriptException; 

import secretgame.SecretGameException; 
import secretgame.events.EventArgs; 
import secretgame.levels.Level; 

// sadly this won't work on Android because there's no such thing 
// as javax.script in Dalvik ... dumb Android java :| 
public class JavaxScriptingLua implements Lua 
{ 
    private ScriptEngine scriptEngine; 
    private final Level level; 
    private final ScriptTools scriptTools; 
    private final ScriptEvents scriptEvents; 
    private int nextId = 0; 
    private ArrayList<CompiledScript> scripts = new ArrayList<CompiledScript>(); 

    public JavaxScriptingLua(Level level, ScriptTools scriptTools, ScriptEvents scriptEvents) 
    { 
    this.level = level; 
    this.scriptTools = scriptTools; 
    this.scriptEvents = scriptEvents; 

    ScriptEngineManager sem = new ScriptEngineManager(); 
    scriptEngine = sem.getEngineByExtension(".lua"); 
    } 

    public int add(String scriptText) throws SecretGameException 
    { 
    try { 
     CompiledScript script = ((Compilable)scriptEngine).compile(scriptText); 
     scripts.add(script); 
    } 
    catch (ScriptException e) { 
     throw new SecretGameException("could not compile lua.", e); 
    } 

    return nextId++; 
    } 

    public void run(int id, EventArgs args) throws SecretGameException 
    {  
    Bindings bindings = scriptEngine.createBindings(); 

    bindings.put("java", scriptTools); 
    bindings.put("level", level); 
    bindings.put("args", args); 
    bindings.put("events", scriptEvents); 

    try { 
     scripts.get(id).eval(bindings); 
    } 
    catch (ScriptException e) { 
     throw new SecretGameException("could not run script.", e); 
    } 
    } 
} 
1

然而,這顯然是不支持在Android

正確的。

事做沒有一個完全成熟的JVM機器人,我讀的地方

正確的。如果你看看the JavaDocs,你會發現Android SDK中不存在javax.script

也許我會試試這個:https://github.com/damonkohler/sl4a

這是一種選擇。另一種方法是通過NDK將Lua解釋器嵌入到您的應用中,如this sample application

+0

感謝您的回答 - 但我設法無論如何,LuaJ都可以在Android上工作。如果您有興趣,請查看我的答案。 –

4

代替LuaJ,您可以(也)使用LuaJava和Lua使用NDK爲Android編譯。這允許Lua完全訪問Java提供的任何內容。看看this example看看如何開始。

Lua 5.1.4 + LuaJava編譯提供在libs目錄(一個單一的libluajava.so文件),如果你不想擺弄NDK,但它是相對容易設置。

+0

AndroLua上的榮譽,但我發現了一種在Android上使用LuaJ的方式,這樣我就不必重新編寫我現有的代碼。請參閱我的答案,瞭解我是如何解決問題的。 –

0

要在Android上使用Lua,你可以使用JNLua + Lua 5.2(用C實現)。與JSR 223(javax.script中)支持的唯一的Android端口是在這裏:https://github.com/danke-sra/jnlua-android

使用此端口,你可以做你想做的:

ScriptEngine scriptEngine = new LuaScriptEngineFactory().getEngine(); scriptEngine.eval("lua statements");

相關問題