2012-05-06 8 views
11

Estoy desarrollando un juego para Android en Java que usa scripts Lua. Para ejecutar estos scripts, estoy usando LuaJ con la clase ScriptEngine de Java. Por ejemplo ...¿Cómo ejecuto las secuencias de comandos Lua en Android en una aplicación Java?

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

Sin embargo, esto aparentemente no está soportado en Android (algo que ver con el androide no tener una JVM por completo soplado, que leí en alguna parte). ¿Hay alguna manera de que pueda usar los guiones de Lua en Android? Tal vez hay una alternativa LuaJ? Quizás haya una forma de compilar y ejecutar guiones Lua usando LuaJ directamente (aunque no puedo ver cómo).

FYI, ver este error cuando trato de ejecutar este código en 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 

Actualización:

Tal vez este proyecto tiene algún código útil? http://code.google.com/p/android-scripting/

Respuesta

11

¡Encontré una manera de usar LuaJ en Android! :-)

La clave es utilizar la API de LuaJ directamente a través de javax.script. Es un poco difícil de entender ya que no hay tutoriales, así que aquí hay un antes y un después para que los demás no tengan que pasar por el código fuente de LuaJ y JavaDoc. ¡Realmente espero que esto ayude a alguien ya que me ha vuelto loco!

Nota: "secretgame" no es el nombre real de mi juego ;-)

Después:

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

Antes:

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

Sin embargo, esto aparentemente no está soportado en Android

correcta.

algo que ver con el androide no tener una JVM por completo soplado, he leído en alguna parte

correcta. Si mira the JavaDocs, verá que javax.script no existe en el SDK de Android.

tal vez voy a probar esto: https://github.com/damonkohler/sl4a

Esa es una opción. Otra es incrustar el intérprete de Lua en su aplicación a través del NDK, como en el this sample application.

+0

Gracias por la respuesta - pero logró conseguir LuaJ trabajando en Android de todos modos. Vea mi respuesta si le interesa. –

4

En lugar de LuaJ puedes (también) usar LuaJava junto con Lua compilado para Android usando el NDK. Esto le permite a Lua acceso completo a lo que esté disponible desde Java. Eche un vistazo al this example para ver cómo empezar.

Lua 5.1.4 + LuaJava compilado se proporcionan en el directorio libs (un solo archivo libluajava.so) si no quiere jugar con el NDK, pero es relativamente fácil de configurar de todos modos.

+0

Felicitaciones por AndroLua pero encontré una forma de usar LuaJ en Android, así no tengo que volver a escribir mi código actual. Vea mi respuesta para saber cómo resolví el problema. –

0

Para usa Lua en Android, puedes usar JNLua + Lua 5.2 (implementado en C). El único puerto de Android con soporte JSR 223 (javax.script) está aquí: https://github.com/danke-sra/jnlua-android

El uso de este puerto, puede hacer lo que quiera:

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

Cuestiones relacionadas