是否可以从宿主程序执行单个lua语句?

时间:2014-12-21 10:35:58

标签: java lua luaj

我正在尝试将基于lua的脚本系统嵌入到我的游戏引擎中。 我希望脚本能够同时具有阻塞和非阻塞命令,例如:

character.walkTo(24, 359);  // Blocks until character arrives
c = 35; // Non blocking, execution goes on to the next statement

自" walkTo"需要活跃"对于超过1帧的执行,我希望能够从Java主机而不是整个函数运行1个语句。这是因为真正的多线程是不合适的,这是不需要的。

如果我只能执行1条语句,并保持执行状态"暂停"直到下一个语句执行,我才能实现阻塞命令,如" walkTo"通过检查 如果命令在主机中完成,如果是,则继续执行下一个语句,否则,等到下一帧迭代。

有没有办法从带有LuaJ的Java主机(或任何其他Lua api)执行1个语句,或者我被迫用lex和yacc开发自己的脚本引擎?

欢迎任何好主意, 谢谢!

2 个答案:

答案 0 :(得分:4)

为所有坚持这个问题的人提供奖励。

这是我的确切解决方案:

- test.lua -

onLookAt = function()
    character:walkTo(234, 35)
    print("Arrived!")
end

- LuaTest.java -

public static void luaTest() {
    Globals g = JsePlatform.standardGlobals();
    g.load(new CoroutineLib());

    g.set("character", CoerceJavaToLua.coerce(new Character(g)));
    g.load(Gdx.files.internal("test.lua").reader(), "test.lua").call();
    g.load("co = coroutine.wrap(onLookAt)").call();
    g.get("co").call();
    try {
        // Simulate time that passes while the script is paused
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    g.get("co").call();
}

public static class Character{
    Globals g;

    public Character(Globals g){
        this.g = g;
    }

    public void walkTo(int x, int y) {
        System.out.println("Started walking.");
        g.yield(LuaValue.NONE);
    }
}

- 输出 -

  

开始行走。

(2秒钟后)

  

到达!

你应该非常小心的一件事:

  • 如果要完成此操作,请不要使用java的ScriptEngine接口。 ScriptEngine接口不提供用于获取隐式分配的API Globals实例,你需要屈服,并创建一个全新的Globals和 用它来屈服是显而易见的。

答案 1 :(得分:3)

好像你缺少异步模式。如果在c=35 character发生(24,359)后必须执行function() c=35 end,那么正确的方法是将walk作为第三个参数传递给character.walkTo(24, 359, function () c = 35 end) 方法和您的引擎(执行实际行走时,会在适当的时候调用该回调。

walk

否则,script = coroutine.wrap(function () character.walkTo(24, 359) -- will yield and leave callable global 'script' c = 35 end) script() -- resume first time -- here script is over ... -- this wrapper may be implemented in Lua or host language function character.walkTo(x, y) engine.startActualWalkingTo(x, y) coroutine.yield() -- yields to host -- coroutine.resume() will continue here end ... -- somewhere in engine code (pseudo-code here) for event in eventLoop do if character.x == endPoint.x and character.y == endPoint.y then script() -- resume again at c=35 end end 可能会安排步行到引擎并立即屈服,恢复正确的事件。在这种情况下,您必须设置脚本worker-coroutine(您无法在主状态下生成)。

script=nil

您可以随时使用{{1}}取消脚本。

yield()有一些限制,请参阅手册。