JavaScriptで分岐ダイアログを実装するにはどうすればよいですか?


11

私は非常に基本的なビジュアルノベルタイプのゲームをJavaScriptで作成しています。私は初心者なので、楽しく学習するためにこれを行っています。計画が悪いため、会話の分岐にたどり着くときに少し問題に遭遇しました。

現在、ゲームのスクリプトを文字列変数に保持し、「#〜」などのタグを使用して各シーンを小さな配列に分割し、ゲームスクリプトが次のようになるようにします。

var script = "Hello World!#~How are you today?"
var gameText = script.split("#~");
//gameText[0]= Hello World!

これは線形のものに最適ですが、ダイアログツリーでブランチをどのように処理する必要がありますか?この方法は非常に複雑に見えます。各パスの長さを正確に把握する必要があり、変更が必要な場合は頭痛の種になるからです。

これをもっと簡単に行うにはどうすればよいですか?私はゲームをWebランタイムで動作させたいので、バニラJavaScriptに固執しようとしています。


このビデオはいくつかのアイデアを提供します:youtube.com/watch
JCM

私は最近、このためにNodeを使用して何かを開発する必要があり、非常に基本的なテキストファイル構造を選択しました。結果のコードとテキスト形式は、github.com / scottbw / dialoguejsで確認できます。コードはGPLです。自由に使用してください。Node JS以外のゲームに適応するのは難しくありません。「fs.load()」の部分をAjaxに置き換えてください。
スコットウィルソン

Inkle Studioによって開発された分岐ストーリースクリプト言語であるInkをチェックしてください。さまざまなプログラムによるインク統合(Java、Javascript、C#)と多くのサードパーティリソースがあります。インクは、多くの商用ゲームでも使用されています。最後に、構文をチェックして分岐ダイアログを「再生」できるデスクトップエディタInkyがあります。
Big Rich

回答:


8

フィリップの答えはすでに正しい方向を示しています。データ構造が不必要に冗長であると思うだけです。テキストが短いほど、読みやすくなります。

短いテキストでアルゴリズムが少し複雑になる場合でも、アルゴリズムを1回だけ作成するので、それは価値がありますが、ほとんどの時間はストーリーの作成と維持に費やされます。したがって、ほとんどの時間を費やすパーツをより簡単にするために最適化します。

var story = [
  { m: "Hi!" },
  { m: "This is my new game." },
  { question: "Do you like it?", answers: [
    { m: "yes", next: "like_yes" },
    { m: "no", next: "like_no" },
  ] },
  { label: "like_yes", m: "I am happy you like my game!", next: "like_end" },
  { label: "like_no", m: "You made me sad!", next: "like_end" },
  { label: "like_end" },
  { m: "OK, let's change the topic" }
];

このデザインのいくつかの説明:

ストーリー全体が1つの配列で記述されています。数値を指定する必要はありません。それらは配列構文によって自動的に提供されます。最初の項目にはインデックス0があり、次の項目にはインデックス1があります。

ほとんどの場合、次のステップの番号を書き込む必要はありません。ほとんどのテキスト行はブランチではないと思います。「次のステップは次の項目です」をデフォルトの仮定とし、それ以外の場合にのみメモをとりましょう。

ジャンプの場合は、数字ではなくラベルを使用してください。その後、後で数行を追加または削除すると、ストーリーのロジックが保持され、数値を調整する必要がなくなります。

明快さと短さの間の合理的な妥協点を見つけます。たとえば、「メッセージ」ではなく「m」と書くことをお勧めします。これは、これまでで最も頻繁に使用されるコマンドであるため、短くするとテキストが読みやすくなります。ただし、残りのキーワードを短くする必要はありません。(ただし、必要に応じて実行してください。重要なのは、読みやすくすることです。または、有効なキーワードとして「m」と「message」の両方をサポートすることもできます)。

ゲームのアルゴリズムは次のようになります。

function execute_game() {
  var current_line = 0;
  while (current_line < story.length) {
    var current_step = story[current_line];
    if (undefined !== current_step.m) {

      display_message(current_step.m);
      if (undefined !== current_step.next) {
        current_line = find_label(current_step.next);
      } else {
        current_line = current_line + 1;
      }

    } else if (undefined !== current_step.question) {

      // display the question: current_step.question
      // display the answers: current_step.answers
      // choose an answer
      // and change current_line accordingly

    }
  }
}

ちなみに、これらのアイデアはRen'Pyに触発されたものであり、これはあなたが望んでいるものではありません(JavaScriptではなく、Webではありません)が、とにかく素晴らしいアイデアが得られる可能性があります。


詳細な説明をありがとう、配列があなたとフィリップが示したように機能することを私は知りませんでした、それらは文字列または数値しか保持できないと思いました。
サイレント地図製作者、2013

1
私はあなたのソリューションを実装しようとしましたが、それはかなりうまくいきますが、場所によって({ label: "like_yes"; m: "I am happy you like my game!"; next: "like_end" },)は「;」ではなく「;」が必要だと思います。また、中かっこにあるものは正確に何と呼ばれていますか?それは配列内のオブジェクトですか?これの使い方の詳細が必要な場合、何を検索すればよいですか?
サイレント地図製作者、2013

はい、{...}オブジェクトです。JavaScriptでは、オブジェクトは、キーと値の連想配列(この例では使用されないいくつかの追加機能を含む)であり、PHPの配列やJavaのマップに似ています。詳細については、JavaScriptとECMAScriptに関するWikipediaの記事、およびそこからリンクされているドキュメント、特にECMAScriptの公式ドキュメントを参照してください。
ViliamBúr2013

1
ところで、彼がここで推奨するデータ構造は基本的にJSONであることに注意してください。個人的には、JSONまで移動することをお勧めします(ほとんどの場合、中かっこと「ツリー」を追加します:{"tree":[etc]}のように全体を囲みます)。その後、ダイアログツリーを外部ファイルに保存できます。ゲームがロードする外部ファイルにデータを配置することは、はるかに柔軟でモジュール化されています(そのため、このアプローチがベストプラクティスである理由です)。
2013年

5

ダイアログイベントの配列を作成することをお勧めします。各イベントは、NPCが言うテキストと可能なプレーヤーの応答の配列を含むオブジェクトであり、これは、応答テキストと、この応答に続くイベントのインデックスを持つオブジェクトです。

var event = []; // create empty array

// create event objects and store them in the array
event[0] = { text: "Hello, how are you?",
             options: [    { response: "Bad", next: 1 },
                           { response: "Good", next: 2 }
                      ]
           };
event[1] = { text: "Why, what's wrong?",
             options: [    { response: "My dog ran away", next: 3},
                           { response: "I broke up with my girlfriend", next: 4}
                      ]
           };
event[2] = { text: "That's nice",

...

2

別のアプローチを使用する必要があります。JavaScriptは配列とオブジェクトをサポートしているので、エントリごとに1つを使用して、すべての分割を節約し、実際のテキストを編集/読み取りしやすくしませんか?

必要に応じて、私が#1gamのために数時間中に作成したプロトタイプを見ることができます。ソースはGPLv3の下で自由に使用できます(GPLにこだわらない場合、インスピレーションを得るためだけに使用する場合は問題ありませんが、ゲームが終了したらお知らせください)。すばらしい文章などは期待しないでください。;)

CSSアニメーションなどを無視して、コードがどのように機能するかを簡単に説明します。

  • var data 本質的に、すべての可能な選択肢などのストーリー全体が含まれています。
  • すべての「場所」(またはページ/エントリ)はIDで識別されます。リストの最初のIDはstart、2番目はcwait、などです。
  • すべての場所には2つの必須要素が含まれています。キャプションと実際のテキストです。決定へのリンクは、次の形式の簡単なマークアップで記述され[target location:display text]ます。
  • 全体の「魔法」は内部で起こっていますnavigate():この関数は、マークアップリンクをクリック可能にします。デッドエンドの静的テキストも処理しているので、少し長くなります。重要な部分は、への最初の2つの呼び出しreplace()です。
  • オプションの最後のエントリは、ブレンドする新しい背景色を定義し、ゲームの全体的なムードをサポートします。
  • これらの色を定義する代わりに、他の場所を指すリンクを追加することもできます(これは私のコードで処理されないことに注意してください。これは、これを示すための単なるアイデアです)。

    'start': ['Waking up', 'You wake...', 'cwait:yell for help', 'cwait: wait a bit', 'clook: look around']

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.