How do I run Lua scripts on Android in a Java application?

后端 未结 4 888
孤街浪徒
孤街浪徒 2021-02-01 09:29

I\'m developing an Android game in Java which uses Lua scripts. To execute these scripts, I\'m using LuaJ with Java\'s ScriptEngine class. For example...

ScriptE         


        
4条回答
  •  Happy的楠姐
    2021-02-01 09:57

    I found a way of using LuaJ on Android! :-)

    The key is to use the LuaJ API directly as opposed to through javax.script. It's a little tricky to figure out as there's no tutorials, so here's a before and after so that others don't have to go through picking through the LuaJ source code and JavaDoc. I really hope this helps someone as it drove me bonkers!

    Note: "secretgame" isn't the actual name of my game ;-)

    After:

    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 scripts = new ArrayList();
    
      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);
      }
    }
    

    Before:

    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 scripts = new ArrayList();
    
      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);
        }
      }
    }
    

提交回复
热议问题