22

だから、ただの遊びで HTML5 RPG を作っています。マップは<canvas>(幅 512 ピクセル、高さ 352 ピクセル | 横に 16 タイル、上から下に 11 タイル) です。もっと効率よく塗る方法があれば知りたいです<canvas>

これが私が今それを持っている方法です:

マップ上でのタイルのロードとペイントの方法

Image()地図はピースを使ってタイル (32x32) で描かれています。画像ファイルは単純なforループを介してロードされtiles[]、使用時に PAINTEDと呼ばれる配列に配置されdrawImage()ます。

まず、タイルをロードします...

ここに画像の説明を入力

そして、これがどのように行われているかです:

// SET UP THE & DRAW THE MAP TILES
tiles = [];
var loadedImagesCount = 0;
for (x = 0; x <= NUM_OF_TILES; x++) {
  var imageObj = new Image(); // new instance for each image
  imageObj.src = "js/tiles/t" + x + ".png";
  imageObj.onload = function () {
    console.log("Added tile ... " + loadedImagesCount);
    loadedImagesCount++;
    if (loadedImagesCount == NUM_OF_TILES) {
      // Onces all tiles are loaded ...
      // We paint the map
      for (y = 0; y <= 15; y++) {
        for (x = 0; x <= 10; x++) {
          theX = x * 32;
          theY = y * 32;
          context.drawImage(tiles[5], theY, theX, 32, 32);
        }
      }
    }
  };
  tiles.push(imageObj);
}

当然のことながら、プレイヤーがゲームを開始すると、最後に中断したマップが読み込まれます。しかし、ここでは、すべての草のマップです。

現在、マップは 2D 配列を使用しています。マップの例を次に示します。

[[4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 1, 1, 1, 1], 
[1, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 1, 1, 1, 1, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 1, 13, 13, 1, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 1, 13, 13, 1, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 1, 13, 13, 1, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 1, 1, 1, 1, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 13, 13, 13, 1, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 13, 11, 11, 11, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 1, 1, 1, 1, 1, 1, 1, 13, 13, 13, 13, 13, 1], 
[1, 1, 1, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1, 1, 1]];

if単純な構造を使用してさまざまなマップを取得します。上記の 2 次元配列が になると、各配列の対応する数値は、内部returnに格納されているに従って描画されます。次に、正しい座標にペイントするために発生し、時間に従ってペイントします。Image()tile[]drawImage()xy32x-y

複数マップ切り替えの仕組み

currentID私のゲームでは、マップには、leftIDrightID、 、の 5 つのものがupIDありbottomIDます。

  • currentID:現在のマップの現在の ID。
  • leftID:currentID現在のマップの左側で終了するときにロードするID 。
  • rightID:currentID現在のマップの右側に出るときにロードするID 。
  • downID:currentID現在のマップの下部で終了するときにロードするID 。
  • upID:currentID現在のマップの上部で終了するときにロードするID 。

注意事項: leftIDrightIDupID、または のいずれかbottomIDが特定されていない場合、それは0. つまり、彼らはマップのその側を離れることはできません。それは目に見えない封鎖にすぎません。

そのため、人がマップの側面を出ると、どこから出たかに応じて...たとえば、下に出た場合、ロードbottomIDする数がmapマップに表示されます。

以下は、視覚化を容易にするための .GIF です。

ここに画像の説明を入力

ご覧のとおり、遅かれ早かれ、多くのマップで多くのID を扱うことになります。そして、それはおそらく少し混乱して多忙になる可能性があります.

明白な長所は、一度に 176 個のタイルをロードし、小さな 512x352 キャンバスを更新し、一度に 1 つのマップを処理することです。短所は、多くのマップを扱う場合、MAP ID が時々混乱する可能性があることです。

私の質問

  • これはマップを保存する効率的な方法ですか (タイルを使用する場合)、またはマップを処理するためのより良い方法はありますか?

私は巨大な地図の線に沿って考えていました。マップサイズは大きく、すべて 1 つの 2D 配列です。ただし、ビューポートは 512x352 ピクセルのままです。

視覚化するために(この質問のために)作成した別の.gifを次に示します。

ここに画像の説明を入力

私の英語が理解できない場合は申し訳ありません。わからないことは何でも聞いてください。うまくいけば、私はそれを明確にしました。ありがとう。

4

1 に答える 1

17

いくつかありますので、順番に回答していきます。


...521 の個別の PNG ファイル?

ここに画像の説明を入力

1 つを使用します。一つだけです。多分6、トップス。考えてみてください。ゲームのタイルを取得するためだけに、すべてのクライアントに 500 回の GET リクエストを実行させているのでしょうか? それはばかげています。

ほぼすべての主要なサイトが、スプライトマップを使用してリクエストを減らしています。たとえば、Youtube では、すべてのボタンに次の 1 つの画像を使用しています。

ここに画像の説明を入力

あなたも同じことをするべきです。


キャンバスをビューポートとして使用するというあなたのコンセプトは、パフォーマンスの観点からは正しいです。絶対に必要以上に大きくしないでください!


マップのパフォーマンスに関する質問については、最初は巨大な配列で問題ないはずです。これはそれを処理するための優れた方法であり、あなたの言葉が非常に大きくない限り、他のオプションを検討する必要はありません. 大規模な場合は、世界の「チャンク」が 400x400 (またはその程度) になる可能性があり、400 番目の行に到達すると、次の配列の行 0 を使用し始めます。もちろん、ヒーローが古き良き四隅のような場所にいる場合、いつでも「使用中」のアレイの最大数は4になります。

プレイヤーの位置は難しくありません。(2, 0)彼がタイル 822, 20 にいた場合、 ( から開始する場合) で表されるチャンクにいることを意味します(0, 0)。具体的には、彼はそのチャンクの 22、20 番目のタイルにいます。複雑な計算も ID もありません。IDを追跡する必要はありません。どのチャンクが最後のチャンクかを追跡する必要さえありません。マップの合計サイズが (たとえば) 1200x1200 であることがわかります。彼が (1201, 50) に移動しようとしても、チャンク(4, 0)が存在するかどうかを確認する必要さえありません。彼がそこに移動できないことはすぐにわかります。マップの幅は 1200 タイルしかありません。

パフォーマンスはどちらの方法でも問題なく、この特定の配列について心配する必要がある前に、実際には他の多くのことに依存します。私のアドバイスは、パフォーマンスを心配する前に、ゲームを作ることを心配することです。ゲームが遅くなったら、パフォーマンスを再検討してください。

パフォーマンスに到達したら、最初にこの問題以外のすべてを心配します。キャンバス ゲームでは、ボトルネックになる可能性はほとんどありません。配列からの読み取りは高速です。既にメモリ内にある大きな配列は高速である必要があります。問題があるべきではありません。実際に問題が発生するまで、問題を予測することに時間をかけません。


編集:プレーヤーで移動するビューポートの例: http://jsfiddle.net/kmHZt/10/

于 2012-07-10T04:12:19.667 に答える