我正在用Java开发使用Lua脚本的Android游戏。为了执行这些脚本,我将LuaJ与Java的ScriptEngine类一起使用。例如…
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/
我找到了在Android上使用LuaJ的方法!:-)
关键是直接使用LuaJ API,而不是通过javax.script。由于没有教程,因此要弄清楚是有点棘手的,所以这里前后是这样,这样其他人就不必遍历LuaJ源代码和JavaDoc。我真的希望这能帮助某人,因为它驱使我疯狂!
javax.script
注意: “ 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); } } }