スレッディングなしのスクリプティングとシネマティクス


12

ゲームエンジンにスクリプトを実装する方法に苦労しています。いくつかの要件があります。直感的である必要があり、カスタム言語、パーサー、インタープリターを記述したくない、スレッドを使用したくない、などです。(もっと簡単な解決策があると確信しています。複数のゲームロジックスレッドの面倒は必要ありません。)Pythonのスクリプトの例(別名擬似コード):

def dramatic_scene(actors):
    alice = actors["alice"]
    bob = actors["bob"]

    alice.walk_to(bob)
    if bob.can_see(alice):
        bob.say("Hello again!")
    else:
        alice.say("Excuse me, Bob?")

ストーリーテリングの壮大な部分は、実装の問題を引き起こします。walk_toゲームの時間がかかるため、メソッド全体を一度に評価することはできません。すぐに戻ると、アリスはボブに向かって歩き始め、(同じフレームで)挨拶(または挨拶)します。しかし、walk_toBobに到達したときに戻るブロッキングコールは、アリスが歩くのと同じ実行スレッドをブロックしているため、ゲームが停止します。

各機能をアクションにalice.walk_to(bob)キューに入れることを検討しました- オブジェクトをキューにプッシュし、アリスがどこにいてもボブに到達した後にポップされます。それはもっと微妙に壊れています:ifブランチはすぐに評価されるので、ボブがアリスに背を向けても挨拶するかもしれません。

他のエンジン/人は、スレッドを作成せずにスクリプトをどのように処理しますか?私は、jQueryアニメーションチェーンなど、ゲーム開発者以外の領域でアイデアを探し始めています。この種の問題にはいくつかの良いパターンがあるはずです。


1
質問に対する+1、特に「Python(別名擬似コード)」の場合:)
リケット

Pythonは超大国のようなものです。
ojrac

回答:


3

パンダのようなものがこれを行う方法は、コールバックを使用することです。ブロックする代わりに、次のようになります

def dramatic_scene(actors):
    alice = actors["alice"]
    bob = actors["bob"]

    def cb():
        if bob.can_see(alice):
            bob.say("Hello again!")
        else:
            alice.say("Excuse me, Bob?")
    alice.walk_to(bob, cb)

完了したコールバックを使用すると、これらの種類のイベントを必要なだけ深く連鎖させることができます。

編集:このスタイルのより良い構文を持っているので、JavaScriptの例:

function dramatic_scene(actors) {
    var alice = actors.alice;
    var bob = actors.bob;
    alice.walk_to(bob, function() {
        if(bob.can_see(alice)) {
            bob.say('Hello again!');
        } else {
            alice.say('Excuse me, Bob?');
        }
     });
}

+1では十分に機能しますが、コンテンツを設計するのは間違っていると思います。スクリプトがシンプルで明確に見えるように、私は自分の側で余分な仕事をしたいと思っています。
ojrac

1
@ojrac:実際には、この方法の方が優れています。同じスクリプトで、複数の俳優に同時に歩き始めるように指示できるからです。
バートヴァンヒューケロム

うーん、良い点。
ojrac

ただし、読みやすさを向上させるために、コールバック定義をwalk_to()呼び出し内にネストするか、(後に言語がサポートする場合)後に入れて、後で呼び出されるコードがソースで後で見えるようにすることができます。
バートヴァンヒューケロム

残念ながら、Pythonはこの種の構文にはあまり適していません。JavaScriptの方が見栄えがよくなります(上記を参照、ここではコードの書式設定を使用できません)。
-coderanger

13

ここで検索する用語は「コルーチン」です(通常、言語キーワードまたは関数名はですyield)。

コルーチンは、サブルーチンを一般化して、特定の場所で実行を中断および再開するための複数のエントリポイントを許可するプログラムコンポーネントです。

実装は、まずあなたの言語に依存します。ゲームの場合、実装をできるだけ軽量にする(スレッドやファイバーよりも軽量にする)必要があります。ウィキペディアのページ(リンク)には、さまざまな言語固有の実装へのリンクがあります。

Luaにはコルーチンのサポートが組み込まれていると聞きました。GameMonkeyも同様です。

UnrealScriptは、これを「状態」および「潜在関数」と呼ぶもので実装しています。

C#を使用している場合は、Nick Gravelynによるこのブログ投稿をご覧ください。

さらに、「アニメーションチェーン」という考え方は、同じものではありませんが、同じ問題に対する実行可能な解決策です。Nick Gravelynには、これのC#実装もあります


ナイスキャッチ、テトラッド;)
アンドリューラッセル

これは本当に良いことですが、100%そこに到達するかどうかはわかりません。コルーチンを使用すると、呼び出し元のメソッドに譲歩できるように見えますが、Luaスクリプトから、Walk(walk_to()!= done){yield}。
ojrac

@ojrac:Luaについては知りませんが、Nick GravelynのC#メソッドを使用している場合、スクリプトマネージャーがチェックする条件を保持するデリゲート(または1つを含むオブジェクト)を返すことができます(ニックのコードは時間を返すだけです)これは暗黙的に条件付きです)。潜在関数自体がデリゲートを返すようにすることもできるためyield return walk_to();、スクリプトに次のように記述できます。
アンドリューラッセル

C#での歩留まりは素晴らしいですが、シンプルで使いにくいスクリプト用にソリューションを最適化しています。yieldよりコールバックを説明する方が簡単なので、他の答えを受け入れます。できれば+2にします。
ojrac

1
通常、yield呼び出しを説明する必要はありません。たとえば、「walk_to」関数でそれをラップできます。
キロタン

3

スレッド化しないことは賢いことです。

ほとんどのゲームエンジンは一連のモジュラーステージとして動作し、メモリ内の各要素が各ステージを駆動します。「ウォークトゥサンプル」の場合、通常、歩行するキャラクターが敵を殺すために探しているべきではない状態にあるAIステージ、アニメーションXを実行するアニメーションステージ、物理ステージ(またはシミュレーション段階)実際の位置が更新される場所など

上記の例では、「alice」はこれらのステージの多くに存在するピースで構成されるアクターであるため、ブロッキングactor.walk_to呼び出し(またはフレームごとに1回ずつnext()を呼び出すコルーチン)は適切なコンテキストを持たない可能性があります多くの決定を下します。

代わりに、 'start_walk_to'関数はおそらく次のようになります。

def start_cutscene_walk_to(actor,target):
    actor.ai.setbrain(cutscene_brain)
    actor.physics.nocoll = 1
    actor.anims.force_anim('walk')
    # etc.

次に、メインループはaiティック、物理ティック、アニメーションティック、カットシーンティックを実行し、カットシーンはエンジン内の各サブシステムの状態を更新します。カットシーンシステムは、各カットシーンが何をしているのかを確実に追跡する必要があります。また、カストシーンのような線形で決定論的な何かのためのコルーチン駆動システムは理にかなっています。

このモジュール性の理由は、物事をシンプルかつシンプルに保つだけでなく、一部のシステム(物理学やAIなど)では、物事を適切に解決し、ゲームを一貫した状態に保つために、すべての状態を同時に知る必要があるためです。

お役に立てれば!


私はあなたの目的が好きですが、実際にはactor.walk_to([別のアクター、固定位置、または位置を返す関数でさえ])の値について強く感じています。私の目標は、シンプルで理解しやすいツールを提供し、ゲームのコンテンツ作成部分以外の複雑さをすべて処理することです。また、各スクリプトを有限状態マシンとして扱う方法が本当に欲しいのだということに気づきました。
ojrac

お役に立てて嬉しいです!私の回答はトピックから少し外れているように感じました:)あなたの目標を達成するためのactor.walk_to関数の値に間違いなく同意します。あなたの実装について聞くことを楽しみにしています。
アーロンブレイディ

コールバックとチェーン関数のjQueryスタイルの組み合わせで行くようです。受け入れられた答えを参照してください;)
ojrac
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.