2012-05-06 14 views
11

Sto sviluppando un gioco Android in Java che utilizza gli script Lua. Per eseguire questi script, sto usando LuaJ con la classe ScriptEngine di Java. Per esempio ...Come si eseguono script Lua su Android in un'applicazione Java?

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

Tuttavia, questo è a quanto pare non supportato su Android (qualcosa a che fare con Android non avere una piena regola JVM, ho letto da qualche parte). C'è un modo in cui posso usare gli script Lua su Android? Forse c'è un'alternativa LuaJ? Forse c'è un modo di compilare ed eseguire script Lua usando direttamente LuaJ (anche se non riesco a vedere come).

FYI, vedo questo errore quando provo a fare funzionare questo codice su 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 

Aggiornamento:

Forse questo progetto ha un po 'di codice utile? http://code.google.com/p/android-scripting/

risposta

11

Ho trovato un modo di utilizzare LuaJ su Android! :-)

La chiave è utilizzare l'API LuaJ direttamente anziché tramite javax.script. È un po 'difficile da capire perché non ci sono tutorial, quindi eccone un prima e un dopo, in modo che gli altri non debbano passare attraverso il codice sorgente LuaJ e JavaDoc. Spero davvero che questo aiuti qualcuno che mi ha fatto impazzire!

Nota: "secretgame" non è il nome effettivo del mio gioco ;-)

Dopo:

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); 
    } 
} 

Prima:

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

Tuttavia, questo è a quanto pare non supportato su Android

corretta.

qualcosa a che fare con Android non avere una piena regola JVM, ho letto da qualche parte

corretta. Se guardi allo the JavaDocs, vedrai che javax.script non esiste nell'SDK di Android.

Forse farò dare una prova: https://github.com/damonkohler/sl4a

Quella è un'opzione. Un altro è quello di incorporare l'interprete Lua nella tua app tramite NDK, come in this sample application.

+0

Grazie per la risposta - ma sono riuscito a far funzionare LuaJ su Android comunque. Vedi la mia risposta se sei interessato. –

4

Invece di LuaJ è possibile (anche) utilizzare LuaJava insieme a Lua compilato per Android utilizzando l'NDK. Ciò consente a Lua pieno accesso a tutto ciò che è disponibile da Java. Dai un'occhiata a this example per scoprire come iniziare.

Lua 5.1.4 + LuaJava compilato sono forniti nella directory libs (un singolo libluajava.so file) se non si vuole perdere tempo con l'NDK, ma è relativamente facile da configurare in ogni caso.

+0

Complimenti su AndroLua, ma ho trovato un modo di utilizzare LuaJ su Android, in modo che non devo riscrivere il mio codice esistente. Vedi la mia risposta per come ho risolto il problema. –

0

Per usa Lua su Android, puoi usare JNLua + Lua 5.2 (implementato in C). L'unico porto Android con 223 supporto JSR (javax.script) è qui: https://github.com/danke-sra/jnlua-android

Usando questa porta, si può fare ciò che si vuole:

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

Problemi correlati