2Dゲームで任意の大きな画像を処理する方法は?


13

質問

本当に大きな画像(ハードウェアがサポートできるサイズよりも大きい)を使用する2Dゲームがある場合、どうしますか?たぶん、私にはこれまでになかったこの問題に対する興味深い解決策があるかもしれません。

私は基本的に、一種のグラフィックアドベンチャーゲームメーカーに取り組んでいます。私のターゲットオーディエンスは、ゲーム開発(およびプログラミング)の経験がほとんどない人です。このようなアプリケーションで作業している場合、「画像を分割する」ように指示するよりも、内部で問題を処理する方が好みではないでしょうか?

環境

グラフィックカードは、使用できるテクスチャのサイズに一連の制限を課していることはよく知られています。たとえば、XNAを使用する場合、選択するプロファイルに応じて、2048または4096ピクセルの最大テクスチャサイズに制限されます。

通常、2Dゲームではほとんどの場合、小さな個別のピース(タイルや変形したスプライトなど)から構築できるレベルがあるため、それほど問題にはなりません。

しかし、古典的なpoint'n'clickグラフィックアドベンチャーゲーム(Monkey Islandなど)について考えてみてください。グラフィックアドベンチャーゲームの部屋は通常、全体的に設計されており、風景に取り組んでいる画家のように、再現可能なセクションがほとんどまたはまったくありません。または、大規模な事前レンダリングされた背景を使用するFinal Fantasy 7のようなゲーム。

これらの部屋のいくつかはかなり大きくなることがあり、頻繁に3画面以上の幅に広がります。現在、これらの背景を最新の高解像度ゲームのコンテキストで考慮すると、サポートされる最大テクスチャサイズを簡単に超えてしまいます。

これに対する明白な解決策は、背景を要件内に収まる小さなセクションに分割し、それらを並べて描画することです。しかし、あなた(またはあなたのアーティスト)はあなたのテクスチャのすべてを分割する人でなければなりませんか?

高レベルAPIを使用している場合、この状況に対処し、内部で(XNAのコンテンツパイプラインなどの前処理として、または実行時に)テクスチャの分割とアセンブルを行う準備をしてはいけませんか?

編集

XNA実装の観点から、私が考えていたものを以下に示します。

私の2Dエンジンは、Texture2Dの機能の非常に小さなサブセットのみを必要とします。実際にこのインターフェイスに減らすことができます:

public interface ITexture
{
    int Height { get; }
    int Width { get; }
    void Draw(SpriteBatch spriteBatch, Vector2 position, Rectangle? source, Color  color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth);
}

Texture2Dに依存する唯一の外部メソッドはSpriteBatch.Draw()であるため、拡張メソッドを追加してそれらの間にブリッジを作成できます。

    public static void Draw(this SpriteBatch spriteBatch, ITexture texture, Vector2 position, Rectangle? sourceRectangle, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth)
    {
        texture.Draw(spriteBatch, position, sourceRectangle, color, rotation, origin, scale, effects, layerDepth);
    }

これにより、以前にTexture2Dを使用したときにITextureを交換可能に使用できます。

それから、ITextureの2つの異なる実装、たとえばRegularTextureとLargeTextureを作成できます。RegularTextureは通常のTexture2Dを単純にラップします。

一方、LargeTextureは、フル画像の分割されたピースの1つにそれぞれ対応するTexture2Dのリストを保持します。最も重要な部分は、LargeTextureでDraw()を呼び出すと、すべての変換を適用し、すべてのピースを1つの連続したイメージであるかのように描画できることです。

最後に、プロセス全体を透明にするために、ファクトリメソッドとして機能する統合テクスチャローダークラスを作成します。テクスチャのパスをパラメーターとして受け取り、制限を超えているかどうかに応じて、RegularTextureまたはLargeTextureのいずれかになるITextureを返します。しかし、ユーザーはそれがどれであるかを知る必要はありませんでした。

少しやり過ぎですか、それとも大丈夫ですか?


1
画像の分割を行いたい場合は、コンテンツパイプラインを拡張してプログラムでそれを行います。すべての機能がすべてのシナリオをカバーするために存在するわけではなく、ある時点で自分で拡張する必要があります。個人的に音を分割することは、最も単純なソリューションのように聞こえます。これは、多数のリソースがあるタイルマップのような画像を処理できるためです。
DMan

コンテンツパイプラインで実行するのが最も賢明なアプローチです。しかし、私の場合、実行時にイメージをロードする必要があり、実行時のソリューションを考え出すことができました(これが昨日この質問をした理由です)。しかし、本当の美しさは、この「タイルマップ」を取得し、通常のテクスチャのように動作させることから得られます。つまり、私は今では半分ほどがあるよ:)など、あなたはまだ描画するspritebatchするためにそれを渡すことができ、そしてあなたはまだ位置、回転、スケール、SRC / DESTの長方形を指定することができます
デビッドゴーバイア

しかし、真実は言われています、私はすでにそれが本当に価値があるかどうか、またはサポートされている最大画像サイズが2048x2048であることをユーザーに伝える警告をユーザーに単に表示する必要があるのか​​どうか疑問に思っています。
デヴィッドゴーベイア

設計については本当にあなた次第です。プロジェクトを完了し、部屋間をスクロールできない場合は、大きなテクスチャをスクロールできるエディターを終了しない方が良いでしょう:D
Aleks

APIに非表示にすることは、ゲーム作成者の生活を楽にする良い方法のように聞こえます。おそらく、Polygon(スプライト)クラスとTextureクラスに実装し、小さな画像を特別な場合ではなく、1x1のタイルにするだけです。そのため、テクスチャクラスは、すべてのタイルと行/列の数を記述するテクスチャグループです。Polygonクラスは、この情報を見て、それ自体を分割し、適切なテクスチャで各タイルを描画します。そのように、それ同じクラスです。スプライトクラスが表示可能なタイルのみを描画し、テクスチャグループが必要になるまでテクスチャをロードしない場合、ボーナスポイントがあります。
ウリウィットネス14

回答:


5

あなたは正しい軌道に乗っていると思います。画像を小さな断片に分割する必要があります。ゲームメーカーを作成しているため、XNAのコンテンツパイプラインは使用できません。あなたのメーカーが、開発者がVisual Studioを使用することを依然として要求するエンジンのようなものでなければ そのため、分割を行う独自のルーチンを作成する必要があります。プレーヤーに必要なビデオメモリの量に制限を設けないように、作品が見えるようになる前に作品をストリーミングすることも検討する必要があります。

アドベンチャーゲーム専用のトリックがいくつかあります。私はすべての古典的なアドベンチャーゲームのように、これらのテクスチャのいくつかのレイヤーを持っているので、あなたのキャラクターは木の後ろや建物の後ろを歩くことができます...

これらのレイヤーにパララックス効果を持たせたい場合は、タイルを分割するときに、すべての半透明を一度スキップします。ここで、タイルのサイズを考える必要があります。タイルが小さいと、オーバーヘッドの管理と描画呼び出しが追加されますが、データが少なくなり、タイルが大きいほどGPUに適していますが、透過性が高くなります。

パララックス効果がない場合、シーン全体を32ビットの深度を持つ2〜4個の巨大な画像で覆う代わりに、32ビットの深度を1つだけ作成できます。また、ピクセルあたりわずか8ビットのステンシルまたは深度レイヤーを使用できます。

このサウンドは、ゲーム開発者以外がアセットを管理するのが難しいようですが、実際にそうする必要はありません。たとえば、3本の木のある通りがあり、プレーヤーが2本の木の後ろ、3本目の木と残りの背景の前に行く場合...エディタで、そして次にゲームメーカーからビルドステップを作成すると、これらの巨大な画像(大きな画像の小さなタイル)を焼くことができます。

古典的なゲームのやり方について。彼らがおそらく同じようなトリックをしたのかどうかはわかりませんが、画面が320x240だったとき、ゲームは16色であったことを覚えておく必要があります。しかし、これは現在のアーキテクチャの動作方法ではありません:D

幸運を


おかげで、ここで非常に興味深いアイデアがたくさん!Adventure Game Studioで以前に使用されたステンシルレイヤーテクニックを実際に見ました。私のアプリケーションに関しては、私は少し違うことをしています。部屋には必ずしも1つの背景画像があるとは限りません。代わりに、ユーザーがインポートした画像のパレットと、背景/前景レイヤーがあります。ユーザーは、ピースを部屋に自由にドラッグアンドドロップして作成できます。したがって、もし彼が望めば、非インタラクティブにゲームオブジェクトを作成することなく、より小さなピースから構成することができます。ただし、これらの2つの層しかないため、視差はありません。
デヴィッドゴーベイア

そして、Monkey Island Special Edition(HQリメイク)のデータファイルを見てきました。すべての背景は、1024x1024個の断片に正確に分割されます(画像の大部分が未使用のままであっても)。とにかく、プロセス全体を透明にするために、編集内容を確認してください。
デヴィッドゴーベイア

256x256のようなもっと合理的なものを選ぶでしょう。この方法でリソースを無駄にせず、後でストリーミングを実装することにした場合、より合理的なチャンクをロードします。十分に説明しなかったのかもしれませんが、これらの小さな静的ゲームオブジェクトをすべて大きなテクスチャにベイクできることをお勧めします。保存するのは、大きな背景テクスチャがある場合、上部の静的オブジェクトで覆われているすべてのピクセルです。
アレクス

わかりましたので、すべての静的オブジェクト背景にマージし、分割してテクスチャーアトラスを作成します。その一連の考えに従って、他のすべてをテクスチャアトラスに焼き付けることもできます。それもいいアイデアです。しかし、今は「ビルド」ステップがありません。つまり、エディターとゲームクライアントの両方が同じエンジンと同じデータ形式で実行されるためです。
デヴィッドゴーベイア

私はステンシルアプローチが好きですが、アドベンチャーゲームエディターを作成している場合はおそらく使用しません。そのようなツールを作成する場合は、ゲーム開発者を対象とするためです。良い点と悪い点があります。たとえば、ビットがピクセルごとにトリガーを定義できる別の画像を使用したり、水をアニメーション化する場合は、簡単にステンシルできます。注:スクリプトのUML状態/アクティビティダイアグラムを調べる、奇妙な無関係な提案が1つあります。
アレクス

2

あなたが言うように、それらがもはや勝手に大きくならないようにそれらを切ってください。魔法はありません。それらの古い2Dゲームはそれを行うか、ソフトウェアでレンダリングされました。この場合、RAMサイズを超えるハードウェアの制限はありませんでした。注目すべきは、これらの2Dゲームの多くは実際には大きな背景を持たず、ゆっくりスクロールするだけで巨大に感じられることです。

グラフィックアドベンチャーゲームメーカーで行うことは、ゲームを実行するためにパッケージ化する前に、何らかの「ビルド」または「統合」ステップで大きな画像を前処理することです。

独自のAPIやライブラリを作成する代わりに既存のAPIとライブラリを使用する場合は、その「ビルド」中にこれらの大きな画像をタイルに変換し、2Dタイルエンジンを使用することをお勧めします。

独自の3Dテクニックを使用する場合は、タイルに分割し、よく知られた適切に設計された2D APIを使用して独自の3Dライブラリを作成することができます。この方法で、少なくとも良いAPI設計であり、設計の必要性が少なくなります。


ビルド時に実行するのが理想的です...しかし、私のエディターはレンダリングにもXNAを使用しています。これは単なるエンジンではありません。つまり、ユーザーが画像をインポートして部屋にドラッグすると、XNAは既にそれをレンダリングできるはずです。したがって、私の大きな問題は、コンテンツを読み込むときにメモリで分割するか、コンテンツを読み込むときにディスクで分割するかです。また、イメージを複数のファイルに物理的に分割すると、これらを異なる方法で保存する方法が必要になりますが、実行時にメモリに保存すると、ゲームのデータファイルを変更する必要がなくなります。
デヴィッドゴーベイア

1

ビジュアルプラクティスでのクワッドツリーの見え方に慣れている場合、詳細な大きな画像を、クワッドツリーのプルーフ/視覚化に似た比較的小さな画像にカットする方法を使用しました。しかし、私の方法は、色に基づいて異なる方法でエンコードまたは圧縮できる領域を具体的に切り取るために行われました。この方法を使用して、説明したとおりに実行することもできます。

実行時にそれらをカットすると、一時的に多くのメモリが必要になり、ロード時間が遅くなります。エディターで作成されたユーザーゲームの物理ストレージまたはロード時間を重視するかどうかに依存しますが、私は言います。

読み込み/実行時間:読み込みに関する方法は、それを比例サイズの断片に分割するだけです。ただし、ピクセル数が奇数の場合、一番右のピースの1ピクセルを考慮してください。画像がカットされるのを好まない人はいません。正方形または4つのセクション(2行2列)にしない理由は、xとyの両方を心配しないため、タイルメモリが小さくなるためです。同時に(そして、どれだけ多くの画像があるかに応じて、それは非常に重要かもしれません)

手前/自動:この場合、ユーザーに1つのイメージに保存するか、個別のピースとして保存するかを選択するというアイデアが好きです(1つのイメージがデフォルトである必要があります)。画像を.gifとして保存するとうまくいきます。画像は1つのファイルにあり、各フレームがアニメーションであるというよりは、すべて同じ画像の圧縮されたアーカイブのようになります(これは基本的に.gifと同じです)。これにより、物理的なファイルの転送が容易になり、ロードが容易になります。

  1. 単一のファイルです
  2. すべてのファイルのフォーマットはほぼ同じです
  3. いつそれを個々のテクスチャに分割するかを簡単に選択できます
  4. 単一のロードされた.gifにある場合、メモリ内の大量の画像ファイルを必要としないため、個々の画像にアクセスする方が簡単かもしれません。

ああ、.gifメソッドを使用する場合、.gifが壊れたファイルのようにアニメーション化するときの混乱を少なくするために、ファイル拡張子を別のもの(.gif-> .kittens)に変更する必要があります。(合法性については心配しないでください。.gifはオープン形式です)


こんにちは、コメントありがとうございます!誤解されたが申し訳ありませんが、あなたが書いたものが主に圧縮とストレージに関係していないのですか この場合、私が本当に心配しているのは、アプリケーションのユーザーが任意の画像をインポートできることと、(XNAの)エンジンが実行時に任意の画像をロードおよび表示できることです。GDIを使用して画像のさまざまなセクションを個別のXNAテクスチャに読み込み、通常のテクスチャと同じように動作する(つまり、描画と変換を全体としてサポートする)クラス内でそれらをラップすることで、簡単に解決できました。
デヴィッドゴーベイア

しかし、好奇心から、画像のどの領域を各セクションに入れるかを選択するために使用した基準について詳しく説明していただけますか?
デヴィッドゴーベイア

画像処理の経験が少ない場合は、頭上にある可能性があります。しかし、本質的には、画像をセグメントに分割することを説明していました。はい、.gifポイントはストレージとロードの両方を説明していましたが、イメージを切り取ってコンピューターに保存する方法を意味します。GIFとして保存する場合は、個々の画像に切り取ってから、アニメーションGIFとして保存し、画像の各カットを個別のアニメーションフレームとして保存できると言っていました。それはうまく機能し、私はそれが役立つかもしれない他の機能を追加しました。
ジョシュアヘッジズ

私が説明した四分木システムは、私がアイデアを得た場所であるため、完全に参照として記載されています。同様の問題を抱えている可能性のある読者に役立つ質問を詰め込む代わりに、詳細を知りたい場合はプライベートメッセージングを使用する必要があります。
ジョシュアヘッジス

ロジャー、GIFフレームを一種のアーカイブとして使用することについてのパートを得ました。しかし、私も疑問に思っています、GIFは限られたカラーパレットのインデックス形式ではありませんか?各フレームに32bpp RGBA画像全体を保存できますか?XNAはこれを何もサポートしていないので、それをロードするプロセスはさらに複雑になります。
デヴィッドゴーベイア

0

これは当たり前のように聞こえますが、部屋を小さく分割してみませんか?グラフィックスカードに頭をぶつけない任意のサイズ(1024x1024など)を選択し、部屋を複数の部分に分割します。

これにより問題が回避されることはわかっていますが、正直なところ、これは解決すべき非常に興味深い問題です。とにかく、これは些細な解決策の一種であり、あなたのために時々働くかもしれません。


このスレッドのどこかで理由を述べたかもしれないと思うが、繰り返しになるかどうかは分からない。基本的にはゲームではなく、一般向けのゲームメーカー(RPGメーカーと同じ範囲で考えてください)であるため、ユーザーが自分のアセットをインポートするときにテクスチャサイズの制限を強制する代わりに、処理するのが良いかもしれませんテクスチャのサイズ制限の技術的な詳細に煩わされることなく、舞台裏で自動的に分割とステッチを行います。
デイヴィッドゴーベイア

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