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秒後)

到着した!

あなたが非常に注意する必要がある1つのこと:

  • これを実現したい場合は、Java の ScriptEngine インターフェイスを使用しないでください。ScriptEngine インターフェースは、譲り渡すために必要な暗黙的に割り当てられた Globals インスタンスを取得するための API を提供しません。また、Globals の新しいインスタンスを作成し、それを譲り渡すために使用することは明らかに無意味です。
于 2014-12-24T04:01:17.933 に答える
3

非同期パターンが欠落しているようです。c=35で1 回実行する必要があるcharacter場合、3 番目の引数としてメソッド(24,359)に渡すのが正しい方法です。エンジン (実際の「ウォーキング」を実行する) は、必要に応じてそのコールバックを呼び出します。function() c=35 endwalk

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

それ以外の場合は、walkエンジンへのウォーキングをスケジュールして、すぐに降伏し、正しいイベントで再開します。この場合、スクリプト worker-coroutine をセットアップする必要があります (main 状態で譲ることはできません)。

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 に答える