画面上にあるものだけをレンダリングする


6

私はこの世界にかなり新しいので、我慢してください。

Slickを使用して記述されたトップダウンの2Dゲームにブロックのグリッドがあります。それを考える最良の方法は、ポケモンの世界です。

現時点では、画面上にあるかどうかに関係なく、特定のマップ上のすべてのブロックをレンダリングしています。

これを行うより良い方法はありますか?私の考えは、おそらく私がレンダリングしたものから画像を作成し、レンダリングに画面に合うセクションを取得することでした。これを行う方法はわかりませんが、詳しく説明する前に専門家に相談したいと思いました。ありがとう!;)

編集

Slickには、特殊なケースでのクリッピングと画面のビューポートを処理する方法があることを付け加えたいと思います。詳細については、Wikiページ参照してください。


1
はい、画面上にあるものだけをレンダリングする必要があります。おそらく外側にも小さなバッファがあるので、プレーヤーが速く移動しても端にちらつきが発生しません。java / slickがこれを行うための組み込みの方法を提供しているかどうかはわかりません。私は彼らがそうすることを想像するでしょう。

回答:


11

これを行う1つの方法は、現在のビューの境界ボックスに対してブロックの境界ボックスをチェックすることです(さらに、安全のために少しビットを追加します)。

ブロックがビューと相互作用する場合(完全に内部またはクリップされている場合)、それを描画します。表示されない場合-完全に外にある場合は描画しないでください。

このチェックは、特に2Dで非常に迅速に実行できます。ブロックのどの程度が表示されているかを知る必要はありません。ブロックの一部が表示されている可能性があるだけです。

場合最大 Xはブロックの座標よりも小さい最小 Xビューの座標または最小 Xブロックの座標よりも大きい最大 Xは、ビューの座標を、このブロックは間違いなく見えません。Y座標でも同じテストを実行できます。

Joeがコメントで指摘しているように、使用しているフレームワーク/ライブラリには、この機能が組み込まれている場合があります。


2

このようなことをしてください:

if (renderX >= 0 && renderY >= 0
    && renderX <= container.getWidth() && renderY <= container.getWidth()) {
    //Render
}

オブジェクトごとにサイズが異なるため、オブジェクトごとにカスタムにする必要があります。コンポーネントの各グループを個別にレンダリングします。TiLeDを使用している場合、ここに私が作成した素晴らしいコードがあります。

TiledMap map = mapComp.getMap();

    //Render positions as integers
    int renderX = (int) renderPos.getX();
    int renderY = (int) renderPos.getY();

    //Render offset for map
    int xRenderOffset = renderX % 32;
    int yRenderOffset = renderY % 32;

    //Get the first tile to be rendered
    int firstTileX = (int) -renderX / 32;
    int firstTileY = (int) -renderY / 32;

    //Render tiles only if their indices are greater than 0
    if (firstTileX < 0) {
        xRenderOffset += Math.abs(firstTileX) * 32;
        firstTileX = 0;
    }

    if (firstTileY < 0) {
        yRenderOffset += Math.abs(firstTileY) * 32;
        firstTileY = 0;
    }

    //Get the last tile to be rendered
    int lastTileX = firstTileX + (client.getContainer().getWidth() / 32) + 1;
    int lastTileY = firstTileY + (client.getContainer().getHeight() / 32) + 2;

    //Verify that the last tile is valid
    if (lastTileX > 127) {
        lastTileX = 127;
    }

    if (lastTileY > 127) {
        lastTileY = 127;
    }

    //Check if the map will be visible on the screen
    if (lastTileX >= 0 && lastTileY >= 0) {
        map.render(xRenderOffset, yRenderOffset, firstTileX, firstTileY, lastTileX, lastTileY, 0, true);
        map.render(xRenderOffset, yRenderOffset, firstTileX, firstTileY, lastTileX, lastTileY, 1, true);
        map.render(xRenderOffset, yRenderOffset, firstTileX, firstTileY, lastTileX, lastTileY, 2, true);
        map.render(xRenderOffset, yRenderOffset, firstTileX, firstTileY, lastTileX, lastTileY, 3, true);
    }

32はタイルの幅、127はマップのサイズです-1。


ちょっとしたコードですが、このコードではTiLeDを使用しません。私は自分が非常に楽しんでいるマップを処理する独自の方法を採用することにしました。これは、Microsoftが発表したPlatformerスターターキットのテキストファイル実装に基づいています。+1。:)
Andy

1

ブロックのサイズが均一で(クラシックポケモンゲームの場合のように)、2D配列に格納されている場合、おそらくこれを行うための最良の方法は、次のようなforループを実行することです。

int startX = playerX - halfWidth;
int startY = playerY - halfHeight;

for( int x = startX , maxX = playerX + halfWidth; x < maxX; ++x )
{
    for( int y = startY , maxY = playerY + halfHeight; y < maxY; ++y )
    {
        DrawBlock( x - startX, y - startY, tiles[x][y] );
    }
}

ここで、halfWidthとhalfHeightは、それぞれ画面の幅と高さの半分です。これにより、DrawBlockの呼び出しが表示されているものだけに削減されます。グリッドをスクロールしている場合は、各方向に追加のタイルを描画し、アニメーション化されたオフセット値を必要に応じてDrawBlockパラメータに追加できます。

この方法は、編集でリンクしたクリッピングの方法を補完するものであることに注意してください。ここで紹介した方法を使用すると、ブロックが画面全体を占めるべきではない場合(たとえば、ユーザーインターフェイス用にブロックの周囲に境界線がある場合)にクリッピングが役立ち、アニメーションの目的で余分なブロックが描画されないようにします。他の要素の上に描画されます。この場合、クリッピング領域をグリッドを表示したい場所に正確に設定し、必要な最小限のブロックのみを描画します。


良いお勧めです!ただし、Slickはこれらの処理をバックグラウンドで適切に処理しているように見えるため、クリッピングを処理するために独自のコードを追加する必要はありません。
Andy
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.