5

我正在尝试将基于 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(或任何其他 Lua api)从 Java 主机一次执行 1 条语句,还是我被迫使用 lex 和 yacc 开发自己的脚本引擎?

欢迎任何好主意,谢谢!

4

2 回答 2

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 接口不提供用于获取隐式分配的 Globals 实例的 API,您需要这些实例来生成,并且创建一个新的 Globals 实例并使用它来生成显然是没有意义的。
于 2014-12-24T04:01:17.933 回答
3

好像您缺少异步模式。如果c=35必须在 处执行一次,那么正确的方法是将character作为第三个参数传递给方法,并且您的引擎(执行实际的“行走”)将在适当的时候调用该回调。(24,359)function() c=35 endwalk

character.walkTo(24, 359, function ()
    c = 35
end)

否则,walk可以安排步行到引擎并立即让步,在正确的事件上恢复。在这种情况下,您必须设置脚本 worker-coroutine(您不能在主状态下屈服)。

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

您可以随时使用 取消脚本script=nil

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

于 2014-12-22T16:47:33.063 回答