[失敗]ドット絵と高解像度UIを同じ画面に出す [Godot 4.2] 

:::note alert
申し訳ございません！
この記事の内容で文字を表示すると、フォントがかなり崩れます。
![anti_pattern.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699119/c74d6122-01d6-2097-0634-daa028a8e1e8.png)
フィクションの犯行予告みたいになっている上に、文字が消えている箇所もあります。

「大きな画面にドット絵の画面を拡大表示する」というアプローチを取って、文字崩れにもちゃんと配慮した方法の記事を書いたので、そちらを御覧ください。
[[Godot 4.2] ピクセルパーフェクト(ドット絵)と高解像度のUIを同じ画面に出す(修正版) #ゲーム制作 - Qiita](https://qiita.com/aka3/items/eab493da5dede9d06204)
:::


公式ドキュメントの[複数の解像度 — Godot Engine (4.x)の日本語のドキュメント](https://docs.godotengine.org/ja/4.x/tutorials/rendering/multiple_resolutions.html)を読むと、一般的なシナリオの1つとして「ゲーム全体を低解像度で作ってピクセルパーフェクトで表示する方法」が書かれています。
今回はそれに加えて「(キャラクターなどの)ドット絵はピクセルパーフェクトで表示するけど、UIなどは利便性重視で普通に高解像度で作る方法」を調べました。

つまるところ、このような画面です。
![1280x720.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699119/30833be5-013e-0845-e384-8d0346121b57.png)

<details><summary>別の解像度(違いが分かりづらいです)</summary>

![1600x900.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699119/352bc703-4853-e767-6d4a-4f0483c01ef6.png)

</details>


雑にフリーハンドで描いた赤いアイコンは高解像度で表示しつつ、ドット絵は画面上にピクセルパーフェクトで表示します。

# 結論
特にスクリプトを書かずとも実現可能です。

- プロジェクト設定にて解像度をドット絵用に下げ、ピクセルスナッピングを有効にする
- ドット絵を表示するノードの [`CanvasItem.texture_filter`](https://docs.godotengine.org/ja/4.x/classes/class_canvasitem.html#class-canvasitem-property-texture-filter) を `Nearest` に設定する
- 高解像度のアイコンは縮小して配置する

# ドット絵のためのプロジェクト設定
基本的には[公式ドキュメントのドット絵の場合のシナリオ](https://docs.godotengine.org/ja/4.x/tutorials/rendering/multiple_resolutions.html#desktop-game)に従います。

プロジェクト設定を開いたら、以下の2つのセクションで設定を行います。
* 「表示」-「ウィンドウ」
* 「レンダリング」-「2D」

## 「表示」-「ウィンドウ」の設定
まずは **「ビューポートの幅」「ビューポートの高さ」をアスペクト比 16:9 に当てはまる低解像度に設定します**。
ドキュメントでは `640x360` が推奨されていますが、今回はドット絵が小さいので半分の `320x180` にしました。

しかしこのままだと実行時にものすごく小さなウィンドウで表示されてしまいます。
「高度な設定」のトグルをオンにすると出てくる「ウィンドウ広さのオーバーライド」「ウィンドウ高さのオーバーライド」である程度大きめの値を設定することで、はじめから見やすい大きさのウィンドウで起動することができます。
今回は私が使っているモニターの解像度より一回り小さい `1280x720` としました。

次に **「ストレッチ」-「モード」を `canvas_items` に、「スケールモード」を `integer` に設定します**。
特にスケールモードの設定が重要で、これにはゲーム画面のサイズを最初に設定した値(今回は `320x180`)の整数倍に限定するという意味があります。
整数倍にしないとどうなってしまうのかは[公式ドキュメントのこのあたり](https://docs.godotengine.org/ja/4.x/tutorials/rendering/multiple_resolutions.html#stretch-scale-mode)を読めばよく分かります。

<details><summary>プロジェクト設定のスクリーンショット</summary>

![「表示」-「ウィンドウ」の設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699119/3f4874a7-60a7-e196-e9aa-8fa94eeb36a6.png)

</details>

## 「レンダリング」-「2D」の設定
最後に「スナップ」内にある **「Snap 2D Transforms to Pixel」と「Snap 2D Vertices to Pixel」をオンにします**。
これはドット絵を表示するノードの座標が整数値ではなくなったときでもドット絵を正しく表示するための設定です。

<details><summary>プロジェクト設定のスクリーンショット</summary>

![「レンダリング」-「2D」の設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699119/85f6323c-6b80-0a9a-6a7d-508e31965da5.png)

</details>

:::note info

これら2つのプロパティは名前がなんとなくそれっぽいのですが、なんと[公式ドキュメントに説明が書かれていません](https://docs.godotengine.org/ja/4.x/classes/class_viewport.html#class-viewport-property-snap-2d-transforms-to-pixel)。
2つのプロパティの違いがよくわかりませんが、片方だけだとドット絵がこんな風に崩れます。
![崩れたドット絵.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699119/2d8ab065-bb4b-ec23-b2d6-616c87149781.png)
両方オフだとさらに悲惨な崩れ方をします。
:::

# ノードの設定
ここからはシーンに配置するノードの設定についてです。

## ドット絵を表示するなら `Nearest`
ドット絵をくっきり表示させるなら、当然バイリニアではなくニアレストネイバー法を使う必要があります。

[`CanvasItem.texture_filter`](https://docs.godotengine.org/ja/4.x/classes/class_canvasitem.html#class-canvasitem-property-texture-filter) を `TEXTURE_FILTER_NEAREST` にすればよいです。
インスペクタでも設定が可能で、 `Nearest` を選択します。
このプロパティのデフォルト値は `TEXTURE_FILTER_PARENT_NODE`(インスペクタでは `Inherit` 表示)で、すなわち親の CanvasItem ノードと同じ値を使うという意味です。
そのためドット絵を表示する一番の先祖の設定を変更しておけば大丈夫です。

または、プロジェクト設定でデフォルト値を設定することもできます。
![フィルタの設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699119/a0ce3fc0-e844-f049-3720-298b8aceabba.png)


## 高解像度のUIを縮小して配置する
まずはシーンにUI要素をまとめて縮小するための Control ノードを追加します。
このノードでは **Size をUI要素の想定解像度に設定し、 Scale を変更して縮小します**。

Size を設定するのは、このノードを擬似的な画面の枠として使うためです。
**Scale の値は `プロジェクト設定の解像度 / Size`** で求めてください。
今回は Size を `1280x720` にして Scale は `0.25` になりました。
はじめは `1920x1080` を使おうと思いましたが、そうすると Scale に誤差を含む値を入れることになり、挙動に不安があったのでやめました。

この方法を使うと、ウィンドウサイズを大きくした時にUI要素が鮮明に表示されます[^expand]。
[^expand]: 原理がよくわからないため、「試してみたところ大丈夫でした」としか言えません。ごめんなさい。

:::note info
[`Control.scale` の説明](https://docs.godotengine.org/ja/4.x/classes/class_control.html#class-control-property-scale)には「scale はアニメーション用のプロパティで、解像度変更に対応したかったら Viewport 使ってね」と書かれています。
しかしそれに従って SubViewport を使ってみたところ、縮小したラスター画像を再拡大したせいでアイコン画像がガビガビになりました。
:::

その後はこのノードの子として通常通り [TextureRect](https://docs.godotengine.org/ja/4.x/classes/class_texturerect.html) や [TextureButton](https://docs.godotengine.org/ja/4.x/classes/class_texturebutton.html) などのノードを配置して texture を適宜設定します。
親の Control ノードが画面と同じサイズに調整されるので、通常と変わらない要領で配置できるはずです。

# これで完成
これで冒頭の画面をいろいろな解像度で表示することができます。

# 参考文献
* [複数の解像度 — Godot Engine (4.x)の日本語のドキュメント](https://docs.godotengine.org/ja/4.x/tutorials/rendering/multiple_resolutions.html)
* [Viewport — Godot Engine (4.x)の日本語のドキュメント](https://docs.godotengine.org/ja/4.x/classes/class_viewport.html)
* [CanvasItem — Godot Engine (4.x)の日本語のドキュメント](https://docs.godotengine.org/ja/4.x/classes/class_canvasitem.html)