Search Unity

2D Pixel Perfect:レトロな 8 ビットゲームの制作に向けた Unity プロジェクトのセットアップ方法

, 3月 13, 2019

ドット絵で描かれたシンプルなメカニクスのレトロゲームを見れば、昔からのゲーマーは懐かしい記憶を思い浮かべるでしょう。一方、若いゲーマーにとっても、レトロゲームは親しみやすいものです。今日、「レトロ」と分類されるゲームは数多くありますが、本当の意味で懐かしいルックアンドフィールを持つタイトルを制作するには、努力と計画が必要です。そこで私たちは、このトピックについて詳しく語ってもらうために、Mega Cat Studios のスタッフを招きました。このブログ記事では、重要な Unity の設定、グラフィックスの構造、カラーパレットなど、NES 風のゲームのアートを本物らしく作成するのに必要なすべてのことをご紹介します。

サンプルプロジェクトを入手し、機能を確認しながらお読みください。

ペンシルバニア州ピッツバーグに拠点を置く Mega Cat Studios は、当時の雰囲気を忠実に再現したレトロゲームの制作を 1 つのアートの形に昇華させました。実際、同社のいくつかのタイトルはカートリッジの形で入手でき、セガジェネシスなどの古いコンソールでプレイすることも可能です。

『リトルメデューサ』と『コーヒークライシス』

Unity ワークフローでレトロさを最大限に演出

Unity ワークフローに最近追加された機能により、Unity はレトロゲーム制作によく適した環境になりました。2D タイルマップシステムがさらに改良され、マス目や 6 角形のタイルマップに加えて、等角法で描かれたタイルマップを使用できるようになりました。また、新しい Pixel Perfect Camera コンポーネントを使うことで、ピクセルベースの一貫したモーションとビジュアルを実現できます。さらにポストプロセッシングスタックを使えば、さまざまな優れたレトロ画面エフェクトまで追加できるようになりました。ただし、このような作業に取りかかる前に、アセットをインポートして正しく設定する必要があります。

スプライトアセットの準備

まず、アセットを鮮明に表示するために、正しく設定する必要があります。使用する各アセットをプロジェクトビューで選択し、インスペクターで次の設定を変更してください。

  • 「Filter Mode」を「Point」に変更
  • 「Compression」を「None」に変更

他のフィルターモードを選択すると、画像が少しぼやけてしまい、私たちが求めている鮮明なピクセルアートスタイルになりません。圧縮を使用すると、画像のデータが圧縮され、オリジナルの画像の精度が若干失われてしまいます。圧縮すると、一部のピクセルの色が変わり、場合によってはカラーパレット全体に変化が生じるため、この点に注意することが重要です。色数が少なく、スプライトが小さいほど、圧縮によって生じる視覚的な変化が大きくなります。標準の圧縮(初期値)と無圧縮の比較を以下に示します。

標準の圧縮/オリジナルの画像に忠実な無圧縮

また、インスペクターで画像の「Max Size」設定にも注意する必要があります。スプライト画像のどちらかの軸のサイズが、「Max Size」プロパティ(初期値は 2048)よりも大きい場合、自動的にそのサイズに変更されます。サイズが変更されると、通常は画質が多少劣化し、画像がぼやけます。一部のハードウェアはどちらかの軸のサイズが 2048 を超えるテクスチャを正しくサポートしていないため、このサイズ内に収めることをお勧めします。

「Max Size」を 2048 に設定した場合/「Max Size」を 4096 に設定した場合

「Max Size」が 2048 に設定されている一方の軸のサイズが 2208 のスプライトシートのスプライトを表示すると、上の画像のようになります。ご覧のとおり、「Max Size」プロパティを 4096 に引き上げることで、画像を適切なサイズにし、画質の低下を防ぐことができます。

最後に、スプライトやスプライトシートを準備するときは、ピボットユニットのモードを「Normalized」ではなく「Pixels」に設定してください。

この設定にすると、スプライトのピボットポイントが、画像の各軸の 0 から 1 までの実数の範囲ではなく、ピクセルに基づくようになります。スプライトがピクセルに基づいて正確にピボットしないと、ピクセルパーフェクトなスプライト表現が得られません。スプライトのピボットは、スプライトエディターで設定できます。スプライトエディターは、スプライトアセットを選択した状態でインスペクターから開くことができます。

2D Pixel Perfect パッケージのインストール

アセットを用意したら、次は「ピクセルパーフェクト」になるようにカメラを設定しましょう。ピクセルパーフェクトな画像は、クリアで鮮明に表示されます。ピクセルパーフェクトでないピクセルアートは、ぼやけ(エイリアシング)が生じていたり、正方形で表示されるべきピクセルが長方形で表示されていたりするため、すぐにそれとわかります。

2D Pixel Perfect パッケージは、Unity のパッケージマネージャーを使ってインポートすることができます。ツールバーから「Window」メニュー、「Package Manager」の順にクリックします。新しいウィンドウで「Advanced」をクリックし、「Show preview packages」が有効になっていることを確認します。左側のリストから「2D Pixel Perfect」を選択し、ウィンドウの右上にある「Install」を選択します。

以上です。これで Pixel Perfect Camera コンポーネントの使用を開始する準備ができました。

高いレベルのピクセルパーフェクト

Pixel Perfect Camera コンポーネントを追加すると、Unity の Camera コンポーネントが拡張されます。これを追加するには、メインカメラに移動し、Pixel Perfect Camera コンポーネントを追加します。Pixel Perfect Camera コンポーネントのオプションが表示されない場合は、前述の手順に従って、まずプロジェクトにコンポーネントをインポートしてください。

では、利用できる設定を確認していきましょう。

まず、「Run In Edit Mode」をオンにして、Game ビューの画面アスペクト比を「Free Aspect」にすることをおすすめします。そうすると、Game ビューのサイズを自由に変更できるようになります。特定の解像度にしたときに最適なピクセルアート表示が得られなかった場合、その旨を知らせる便利なメッセージが Game ビューに表示されます。

各設定を一通り見て、その機能とゲームの外観にどう影響するかを確認してみましょう。

  • Assets Pixels Per Unit – このフィールドは、各アセットのインスペクターで選択可能な設定に関連します。一般的に、ゲームのワールド空間で使用する各アセットは、単位あたりのピクセル数(PPU)を揃えるべきとされています。ここにもその値を入力します。ゲームの世界を 16 x 16 ピクセルのタイルのマス目とスプライトで構成する場合、PPU を 16 に設定するのが適切でしょう。そうすれば、マス目の各タイルがワールド空間座標の 1 ユニットになるからです。選択した PPU を必ずここに入力してください。
  • Reference Resolutionここでは、すべてのアセットを表示する解像度を指定します。レトロな見た目にしたい場合は、通常、解像度を非常に小さくします。たとえば、セガジェネシスのネイティブの解像度は 320 x 224 です。セガジェネシスのゲームを移植する場合は、320 x 224 の基準解像度を使います。一般的な 16:9 のディスプレイを使用する場合は、320 x 180 や 398 x 224(垂直方向の解像度を維持したい場合)に設定するとうまくいきます。
  • Upscale Render Texture – この設定を使うと、基準解像度にできるだけ近い解像度でシーンがレンダリングされ、実際のディスプレイサイズに合わせてアップスケールされます。この設定を有効にすると画面全体にレンダリングされるため、フルスクリーンのピクセルパーフェクトな表示を実現したい場合にお勧めします。また、「Upscale Render Texture」は、回転時のスプライトの外観にも大きく影響します。

1. オリジナル(回転なし)2. 「Upscale Render Texture」なし(45 度回転。エッジが斜めになりピクセルサイズが変わるため、ピクセルパーフェクトではない)3. 「Upscale Render Texture」を使用(45 度回転。すべてのピクセルが同じサイズになり、ピクセルパーフェクトな表示が保たれているが、オリジナルと比べるとスプライトの精度が少し落ちている)

  • Pixel Snapping(「Upscale Render Texture」が無効な場合にのみ利用可能) – この設定を有効にすると、スプライトレンダラーが自動的にワールド空間のグリッドにスナップされます。この場合、グリッドのサイズは選択した PPU に基づきます。この設定を使用しても、オブジェクトのトランスフォームの位置に影響はありません。そのため、2 つの位置を補間してオブジェクトを滑らかに動かしながら、鮮やかでピクセルパーフェクトな表示を実現できます。
    • 例:

「Pixel Snapping」を無効にした場合。背景を (0, 0) に、キャラクタースプライトを (1.075, 0) に配置すると、一部のピクセルは正しく整列されません。ご覧のとおり、一部のピクセルがキャラクターの影で半分だけ覆われています。「Pixel Snapping」を有効にした場合。背景(0, 0)とキャラクタースプライト(1.075, 0)の位置は同じです。ピクセルが互いにぴったりとスナップされています。

  • Crop Frame(X および Y) – この設定を有効にすると、基準解像度と正確に一致するようワールド空間の表示領域がトリミングされます。また、画面隅の隙間を埋めるためにディスプレイに黒い余白が追加されます。
  • Stretch Fill – 「Crop Frame」の X 軸と Y 軸の両方を有効にした場合に利用できるようになります。この設定を有効にすると、アスペクト比を維持したまま、Game ビューが画面にフィットするようにカメラのスケールが設定されます。このスケーリングは基準解像度の整数倍で行われるとは限らないため、基準解像度の整数倍以外の解像度では、ピクセルパーフェクトになりません。この設定を使うと、多くの解像度でピクセルパーフェクトな表示が得られなくなりますが、黒い余白を表示させずに画面全体を埋めることができるというメリットがあります。「Stretch Fill」を使うと、多くの場合、ぼやけが生じますが、通常のアラート表示メッセージは表示されません。

「Stretch Fill」によってぼやけたキャラクターと背景

Pixel Perfect Camera を使用する場合の推奨設定

さまざまな用途に適した、鮮やかでピクセルパーフェクトな表示を実現したいなら、次の設定をお勧めします。

  • プレイヤーのウィンドウ解像度よりも絶対に大きくならない基準解像度を使う(320 x 180 など)
  • 「Upscale Render Texture」を必要に応じて有効にする
    • 90 度、180 度、270 度以外の回転を使う場合や、回転したスプライトに視覚エフェクトを使いたい場合は、有効にします。
    • 「Upscale Render Texture」を有効にすると、基準解像度によっては、一部の解像度でピクセルパーフェクトな画像を実現できないことがあります。Pixel Perfect Camera コンポーネントで有効にした「Run in Edit Mode」を利用して、この設定やさまざまな画面解像度を試し、選択した解像度で問題か発生するかどうかを確認してください。この設定を使ってすべての解像度でピクセルパーフェクトな画像が得られるならば、最高のピクセルパーフェクトな表現をフルスクリーンで実現できます。
  • 必要に応じて「Pixel Snapping」を有効または無効にする
    • これは他の項目に比べると、個人的な好みで選んでいい項目です。スナップを使わない方が動きがはるかに滑らかになりますが、画像のピクセルが互いにずれて見えることがあります。
  • 「Upscale Render Texture」を使用しない場合は「Crop Frame」の「X」や「Y」を有効にする
    • 「Upscale Render Texture」を使っても、一貫してピクセルパーフェクトな結果にならない場合は、X 軸や Y 軸をトリミングすると、基準解像度よりも高い解像度であればピクセルパーフェクトな画像を実現できます。ただし、解像度によっては、画面の隅に大きな余白が生じます。
  • 「Stretch Fill」を無効にする

可能な場合は基準解像度を含め、16:9 のアスペクト比での表示に合わせてカメラの設定を最適化することをお勧めします。この記事を執筆している時点では、大半のゲーマーが 16:9 のモニターと 1920 x 1080 の解像度でプレイしています。たとえば、320 x 180 の基準解像度は 16:9 であるため、1920 x 1080 や、320 x 180 の偶数倍の解像度(1280 x 720 など)でプレイしても、黒い余白が表示されることはありません。

Unity のツールバーから「Edit」>「Project Settings」>「Player」に移動して、ゲームでサポートするアスペクト比を制限できます。ターゲットにしているアスペクト比では思いどおりに機能するものの、特定のアスペクト比ではうまく表示されない設定がある場合は、ここで、ウィンドウがそうしたアスペクト比で表示されないようにできます。ただし、すべてのユーザーが制限がうまく機能する表示設定を使用できるわけではないため、アスペクト比の制限は推奨されていないことに留意してください。画面に合っていない解像度でのプレイを強いるよりは、余白が表示されることを許容してトリミングを有効にすることを検討してください。

NES 風のアートワークを本物らしく作成する方法

ここまでは、ピクセルパーフェクトなアートを描画できるように Unity を設定する方法について説明してきました。次は、オリジナルのニンテンドーエンターテインメントシステム(NES)の制限に沿ってゲームアートワークを作成する際の基本事項を見ていきましょう。NES 世代の人々は、本物らしい NES 風画像を作成しようとしているアーティストに数多くの制限を課しています。たとえば、使用するパレット、画面上のオブジェクトのサイズと数などの制限が含まれます。また、このコンソールを「ターゲットとする」ときは、256 x 240 の基準解像度を使用することも重要です。

パレット

「純正の」NES アートワークを作成する場合、アーティストが順守しなければならない制限は数多くあります。こうした制限の中には、エミュレートしようとしているレトロなコンソールの種類に関係なく課されるものもありますが、その他多くは NES 固有のものです。1 つ目の、そしておそらく最も重要な制限は、画像でのカラーパレットの使用方法に関係しています。NES はカラーパレットに関してはかなり独特であり、フルカラーパレットがコンソールにハードコーディングされています。NES に搭載されたグラフィックスプロセッサーに一連の値を送ると、その値に関連付けられている色が返されます。NES ではこのようにして画像で使う色を選択しています。以下は NES のカラーパレットの画像です。

これらの色は、コンソール自体に組み込まれているため、変更できません。皆さんが見たことのあるどの NES ゲームでも、画像を描画するために、これらの色を組み合わせて使用しています。

サブパレット

サブパレットは、ゲームで使用する色の組み合わせを作るために作成され、ゲーム内のスプライトや背景要素に割り当てられます。NES のパレットは、スプライトや背景に割り当てることができるよう、サブパレットに分割されます。それぞれのサブパレットには、すべてのサブパレットで使われる共通の色が 1 つと、固有の色が 3 つあります。背景とスプライトに対して、それぞれ 4 つのサブパレットを読み込むことができます。スプライトの場合、各サブパレットの最初にある共通色が透過色として扱われます。

これはゲームで使用されている一連のサブパレットの例です。上は背景のサブパレット、下はスプライトのサブパレットです。この例では、すべてのサブパレットで共有されている共通色として黒が使用されています。共通色はスプライト上では透過色として扱われるため、黒を可視色として使用するためには、スプライトのサブパレットに黒色のパレットエントリをもう 1 つ作成する必要があります。

サブパレットの割り当て

パレットの使用上の制限は、ゲームでパレットを使用する方法に目を向けると、さらに厳しいものに見えてきます。このことを説明するためには、レトロなコンソールがどのようにアートを格納、使用、表示するかについてさらに詳しく解説しなければなりません。レトロなコンソールのアートワークは、8 x 8 ピクセルのタイルとしてゲーム内に格納されます。このタイルベースの手法を使用した場合、さまざまなオブジェクトにタイルを再利用することで、容量を節約できます(たとえば、歩道のタイルは建物の横桟の描画にも再利用できます)。タイルベースの格納に関して注意すべきもう 1 つの重要な点は、一般的に、色情報がグラフィックスとともに保存されることはないということです。すべてのタイルはモノクロのパレットとともに保存されます。そうすることで、ゲーム内でタイルが表示されるたびにサブパレットをタイルに割り当てることができるため、異なるサブパレットを使い、画面に同じタイルを同時に表示することが可能になります。最新のプラットフォームでレトロなコンソールらしいアートワークを作成する場合、この仕組みは重要です。パレットをアートワークに割り当てる方法に関係しているからです。

NES では、スプライトと背景に対して、別々の方法でパレットを割り当てています。スプライトのサブパレットは、タイル単位で割り当てられます。つまり、スプライト内の各 8 x 8 のタイルには、スプライトの 4 つのサブパレットのうち 1 つを割り当てることができます。

この忍者キャラクターには、色づかいに深みをもたせるために 2 つのサブパレットを使用しています。右側のキャラクターは 8 x 8 のスプライトタイルに分割されていることがわかります。この分割された表示の場合、剣とヘッドバンドに使われている明るい青緑色と最も濃い赤色が、それらのタイルでしか使われていないことがより明らかになります。一方で、濃い紫色と黒色の輪郭線が残りの 3 つのタイルで使用されていることもわかります。

一方、背景にはさらに多くの制限があります。背景には、16 x 16 のチャンクの形でパレットが割り当てられます。画面全体分の背景に対するサブパレットの割り当ては、属性テーブルというものによって指定されます。ほとんどのレトロなアートワークでタイルセグメントが繰り返し多用されているのは、この属性テーブルが理由です。これらのセグメントは、属性テーブルにうまくフィットするように、多くの場合 16 x 16 のタイルで構成されます。ハードウェアの制限に対処するためのものであるにもかかわらず、背景に対するこの 16 x 16 のタイルベースの手法は、レトロなアートワークの決定的な特徵の 1 つとなり、それを再現するときには不可欠となります。

これは制限内で制作した RPG 風の街の背景の例です。右側の画像では、16 x 16 ピクセルのブロックに整然と分割されている様子が示され、ブロック単位にパレットが選択されていることがわかります。屋根のタイル、草地、橋上のレンガなどは、容量節約のために、これらのブロックのセグメントを繰り返すことで構成されています。小さな建物の屋根のタイルすべてに使用されているタイルは同じですが、それぞれに異なるサブパレットを割り当てて、外観に違いが出るようにしています。

スプライトのレイヤー化

アーティストはスプライトの 8 x 8 のタイルごとに異なるサブパレットを使用できますが、今よりもさらに深い色づかいをしたいと思うこともあるでしょう。そこで登場するのがスプライトのレイヤー化です。スプライトのレイヤー化とは、スプライトを 2 つのスプライトに分割してから重ね合せる手法です。これにより、8 x 8 タイル 1 つにつき 1 つのサブパレットしか使えない制限を回避できます。この方法を使えば、実質的に 1 つの 8 x 8 のエリア内で使える色の数を倍にすることが可能です。この方法には、1 つだけ大きな欠点があります。それはスプライトのレイヤー化の制限です。NES が一度に画面上に表示できる 8 x 8 のスプライトタイルは 64 個だけで、同じ水平線上に並べて表示できるスプライトタイルは 8 個だけです。その数に達すると、その数を超えるスプライトタイルは画面上にレンダリングされません。そのため、多くの NES ゲームでは、一度に画面上に多くのスプライトを表示すると、スプライトが点滅します。つまり、1 フレームごとに表示と非表示が切り替わるスプライトが生じるということです。アーティストはスプライトを相互に重ねる場合、こうした制限に注意する必要があります。色の数は 2 倍になりますが、同一水平線上のスプライトタイルの数も 2 倍になるからです。

これはスプライトのレイヤー化の実例です。一番左は、オリジナルの 3 色バージョンの幽霊海賊のスプライトです。そこから、これを身体と帽子、顔と手の 2 つの部分に分割し、それぞれに異なるパレットを割り当てました。最後に 2 つの部分を重ねると、一番右のような結果になります。

また、スプライトのレイヤー化を背景に対して使用すると、属性テーブルの制限も回避できます。通常、このテクニックは、色づかいを豊かにするために、ストーリー画面やキャラクターの肖像などの静的な画像に使います。これは、画像の一部を背景として描いてから、その上にスプライトを重ねて残りの部分を埋めるという方法で行います。

幽霊海賊の肖像でも、使える色の数を増やすために、スプライトのレイヤー化を使用しています。緑色の頭はスプライトとして画面上にレンダリングされていますが、襟と帽子は背景の一部としてレンダリングされています。この手法により、アーティストは 16 x 16 のエリア内で使用できる色数を増やして、属性テーブルの制限を回避することができます。

グラフィックスバンク

次の NES の大きな制限を説明するにあたり、まずグラフィックスがタイル形式で格納されているという事実をもう一度思い出す必要があります。グラフィックスタイルは 256 個のタイルページに格納されており、そのページのタイルは VRAM 内の別の場所に読み込むことはできません。そのため、異なるページにあるタイルを必要に応じてすぐに組み合わせることは困難です。NES の VRAM で一度に表示できるタイルは 512 個だけです。さらに、この 512 個のタイルは、スプライト用と背景用に、半分に分けられます。つまり、どのような場合でも表示できるのは、256 個のスプライトタイルと 256 個の背景タイルだけです。多種多様なスプライト要素と背景要素を表示したいと考えている場合、これが厳しい制限となることがあります。

VRAM に読み込まれる、ゲームの背景タイルとスプライトタイルを視覚的に表したものです。コンソールでは、背景とスプライトが別々のページに整理して保持されます。

この制限に対処するために、NES には、各ページをバンクと呼ばれるページの部分に分割できる機能が備わっています。そのため、NES はグラフィックスデータ内のさまざまな位置にある個々のタイルを読み込むことはできませんが、異なるタイミングでページの一部を読み込むことはできます。ほとんどのゲームのバンクは、1K か 2K のどちらかになります。1K バンクはページの 4 分の 1(64 タイル)に相当するのに対し、2K バンクはページの半分(128 タイル)に相当します。アーティストは、両方のタイプのバンクを使う必要があるため、スプライト要素と背景要素のどちらにそれぞれのタイプのバンクを使用するかという方針を決めなければなりません。つまり、スプライトと背景の両方に 1K バンクを使うことはできません。一方のページには 1K バンク、もう一方のページには 2K バンクを使う必要があります。一般的に、大半のゲームでは、スプライトに 1K バンク、背景に 2K バンクを使用する傾向が見られます。これは、背景タイルセットの方が静的であることが多く、その場に応じて変える必要性が少ないからです。

これは、上と同じ画像をバンクに分割した様子を示しています。左側の背景のペインでは 2K バンクを使用している(つまり、中央で分割されている)のに対し、右側のスプライトのペインでは 1K バンクを使用しています。各バンクは必要に応じてその場で自由に切り替えることができます。

スプライトに 1K バンクを使用すると、非常に便利です。他のすべてのスプライトに加えて、1 ページに収まらないほど多様なアニメーションがあるプレイヤースプライトを読み込む必要がある場合も、個々のアクションを 1K バンクに格納しておけば、画面上で生じているアクションに応じてバンクを切り替えることができます。また、ゲーム内の 1 つのエリアで多種多様なスプライトを使うことも可能になります。たとえば、プレイヤーが 6 種類の敵に遭遇するエリアがゲーム内にあるとしましょう。ところが、スプライトページには、プレイヤーとその他の 3 種類のスプライトしか使用できません。その場合も、1 種類の敵スプライトが画面上から消えたときに、敵スプライトのバンクの 1 つを切り替えて、別の種類の敵を表示することができます。

スプライトに 1K バンク、背景に 2K バンクを使用した場合でも、数少ないものの大きな欠点があります。その 1 つは、NES による背景アニメーションの処理方法です。NES ゲームの背景要素をアニメーション化するために、アーティストは、アニメーション化される背景要素のバンクの複製を作成する必要があります。新しく複製した各バンクには、アニメーション化する要素ごとにアニメーションの次のフレームを含めます。そして、これらのバンクをパラパラ漫画のように 1 つずつ切り替えてアニメーションを作り出します。アーティストが背景に 2K バンクを使用している場合、このように複製したバンクすべてを格納するために多くの容量が必要になることがあります。この問題を回避する方法の 1 つとして、ゲーム全体のアニメーション化される背景要素をすべて、1 つのバンクに格納する方法があります。しかし、その方法を使っても、それぞれの背景の静的要素に使えるタイルが 128 個しか余らないという制限が残ります。アートに使用するバンクの種類を決定する際に最善策を決めるのはアーティストの役割です。

レイヤー化のテクニック

NES 時代の多くのゲームでは、背景にパララックススクロールなどの効果を作成するテクニックが使用されていましたが、このような効果の作成もアーティストやデザイナーには課題となります。後に登場する 16 ビットのコンソールでは複数の背景レイヤーを使用できるようになりましたが、NES ではそれは許されません。背景はすべて、1 つのフラットな画像です。奥行き感やレイヤー感を出すために、さまざまなプログラミングテクニックが使用されていました。たとえば、奥行きのある背景を作成するために、開発者はある特定の水平線(ラスターライン)が画面上にレンダリングされるタイミングを伝えるレジスターを設定できます。その後、このレジスターを使用すると、画面がスクロールされる速度と方向を制御することが可能です。これを使えば、背景の他の部分とは異なる速度でスクロールされる帯状の背景を作成できます。アーティストやデザイナーにとってここで大切なのは、背景が 1 つのフラットな画像のままであることです。ゆっくりと動く背景よりも「手前」にあるべきの足場やその他の要素がそのエリアに配置されている場合、同様にその要素も背景画像の他の部分よりもゆっくりとスクロールするはずです。そのため、デザイナーはシーン内のどこに要素を配置するかに注意する必要があります。また、アーティストは効果がシームレスになるように背景を作成する必要があります。

この例の画面では、赤色でハイライトされているエリアは、奥行きを擬似的に表現するために、スクロールの速度が背景の他の部分よりも遅くなるように設定されています。その上にあるヘッドアップディスプレイもフラットな背景画像の一部ですが、この部分はスクロールしないように設定されています。

背景要素の 1 つをフォアグラウンドに表示したいアーティスト向けのテクニックはもう 1 つあります。NES では、開発者はスプライトの優先度を 0 よりも小さい値に設定できます。これを行うと、スプライトがすべての不透明の背景ピクセルの背後に表示されます。また、スプライトの優先度はその場で変更したりトリガーしたりできるため、特定の要素では必要に応じてスプライトの優先度を変更することが可能です。

まとめ

レトロなコンソールに忠実なプロジェクトを作成する際は、最新の開発案件では気にする必要のない多くの技術的な事柄を考慮する必要があります。古いマシンは、CPU や GPU を使った操作の融通性が乏しく、画像のレンダリング方法や処理方法に制限がありました。そのため、ハードウェアの制限に対処するために、デザイナーはクリエイティブに考える必要がありました。現代において昔のゲームの外観やデザインを再現するためには、これらの制限やテクニックについて知ることが重要になります。次の記事では、16 ビットの時代に課せられていたデザイン上の制限に加え、「古いテレビ」感を Unity でそれらしく再現するのに必要な作業について取り上げます。

12 コメント

コメントの配信登録

コメント受付を終了しました。

  1. Jerry Brace

    3月 15, 2019 6:28 pm

    Excellent post! I’m currently revising a game I did in a NES retro style (Shuttle Scuttle – App Store and Google Play Store). The new version of the game is being developed in Unity with the PixelPerfectCamera and in parallel being developed for the NES using the NESmaker software. NESmaker is a great way to validate your 8-bit NES artwork on real hardware before using in Unity (I use an EverDrive to run the .NES rom on the system). Looking forward to the 16-bit post.

  2. Woa! That’s an amazing post, very informative, please keep them coming! :)

  3. Thank you for this quite thorough blog post!

    Unfortunately, I see no mention of the UI or Canvas. Is there any plans for a built-in component to make the canvas scale with the pixel-perfect camera?

    The example project does not cover this issue and a few quick tests did not provide any satisfying results, in particular when enabling Crop Frame on the X and Y axises.

    1. It may be worth remembering that these retro games didn’t really have a concept of a UI. If there was a UI, it was just sprites and the system didn’t know any different. As such, for truly retro, you would want to do the same. That being said, creating a world space canvas will adhere to world space rendering and may be your best bet. That being said, I am no expert and could be completely wrong :) Let me ask the folks at Mega Cat.

  4. Awesome post! Thanks a lot.

  5. Insane Scatterbrain

    3月 14, 2019 2:02 pm

    Awesome post! I had to look hard for a lot of this information for my latest project, so it’s great to see this in one place and still learn a lot of new things. :)

    Another thing to note is that “Texture Quality” should be set to “Full Res” under the “Quality Settings”, which is not the default for the “Very Low” settings. Otherwise, your textures will look blurry.

  6. One step forward to completely *nail* the rendering part is to use double-blit upscaling from the original render buffer, something that Sonic Mania does. The process is fairly simple:
    -Render into a low-res buffer
    -Upscale with integer to the closest lower resolution of your output display
    -Upscale to display with linear filtering

    As a result we eliminate bad pixel placement at the cost of an additional blit while retaining relatively clean look, which the default pixel perfect camera doesn’t provide with its 1 blit method (last time I checked it rendered the default low-res buffer and blitted it straight to the screen which resulted in a lot of interpolation)

  7. This blog post is awesome for a number of reasons:

    – Detailed, yet succinct explanations of common problems and solutions.
    – Explains the how AND the why.
    – Explores techniques that aren’t common knowledge to newcomers.
    – Pixel graphics! <3

  8. I appreciate these options, but if I really wanted to make an 8 bit game with Unity I would strip out most of what Unity is and base the graphics around a render texture and a framework that lets you DrawSprite( spriteX, x, y, rotation, scale ). The logic would be straight C# not monobehaviours and physics.
    You really want low-level blit functions like RenderTexture.Draw(texture, x, y, rotation, scale); which can be done with Graphics.Blit but not easily

    1. Andrew Ackerman

      3月 14, 2019 1:23 am

      If you’re disabling Unity’s rendering and physics engine as well as rolling your own pure C# scripts instead of MonoBehaviors, at that point I have to wonder if there’s any point in using Unity at all anymore. You might as well use a lower level 2D game engine like GameMaker or Ogre, or even just roll your own engine from scratch.

  9. Thank you so much for this article! I have a question regarding resolution and sprite size. You mention it is best to set the resolution to something small (like 320×180) so it will only be stretched larger and not cropped to a smaller view of the scene. When it comes to sprites, having such as small resolution means there is very little pixel density on the screen, so you would be forced to use small assets, such as 16×16, to actually fit a decent amount of sprites into a scene with such a small resolution. This would also mean your sprites can’t be very detailed as well. However, looking at some of the pictures in the article (such as Coffee Crisis) there is clearly a lot of pixels being displayed on the screen at one time. How do you go about fitting much larger sprite sizes (64×64, 128×128, etc.) with more detail into such a small resolution? Do you set the Pixels Per Unit to be larger than the actual sprite size (a 32×32 sprite is given a PPU of 64 so it fills less of the screen), or is there some other solution you use?

    1. Correct! So this post covers some general setup and limitations for 8-bit consoles. The next post will cover 16-bit consoles which have more “oof” to work with. I believe Coffee Crisis was released as a Sega Genesis cartridge, so 16-bit.