Is it possible to execute a single lua statement from a host program?

北城余情 提交于 2019-12-04 07:51:54

Seems like you are missing asynchronous pattern. If c=35 has to be executed once character occurs at (24,359), then the correct way is to pass function() c=35 end as third argument to walk method and your engine (that performs actual 'walking') will call that callback when appropriate.

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

Otherwise, walk may schedule walking to engine and yield immediately, resuming on correct event. In this case you have to setup script worker-coroutine (you cannot yield in main state).

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

You may cancel the script anytime with script=nil.

yield() has some limitations, consult the manual.

Bonus answer for everyone who is sticking with this problem.

Here is my exact solution:

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

-- Output --

Started walking.

(2 seconds later)

Arrived!

One thing you should be very careful about:

  • Do NOT use java's ScriptEngine interface if you want to accomplish this. ScriptEngine interface doesn't provide API for obtaining the implicitly allocated Globals instance that you need for yielding, and making a new instance of Globals and using that for yielding is obviously pointless.
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!