この記事について

Godotで作ったUIを小さいウィンドウで開くと、ボタンが右にはみ出したり、画面全体を縮めた結果、文字が読みにくくなったりします。まず確認したいのは、画面全体の拡大縮小と、UI部品の並び方です。

制作中のUI素材「Mendworks」の確認でも、横長の画面を幅390に収めるだけでは文字が小さくなりました。そこで文字の大きさを保ち、狭いときは縦に並べ、必要な部分をスクロールする形へ変更しています。

制作中のMendworksを幅390で表示した実例。左は横長の画面を全体縮小した状態、右は配置と折り返しを見直した状態です。掲載した右側は画面上部で、下へ続きます。
制作中のMendworksを幅390で表示した実例。左は横長の画面を全体縮小した状態、右は配置と折り返しを見直した状態です。掲載した右側は画面上部で、下へ続きます。

Mendworksの修正版には独自の配置処理もあります。この記事では仕組みを追いやすくするため、別の小さなシーンを使い、標準のControlとContainerだけで組み直します。ボタンは配置確認用で、修理や予約の処理は実装していません。

使用環境はGodot 4.6.3、Linux、Compatibilityレンダラーです。デスクトップのウィンドウ表示を例にしているため、スマートフォンやWebでは別途、表示と操作を確認してください。赤枠の番号は、基本手順の見出し番号と対応しています。

この記事でわかること

  • Controlを親のサイズに合わせる方法
  • ContainerのFillとExpand、最小サイズの確認箇所
  • 長い文章を折り返し、縦スクロールで最後まで見せる方法
  • 横並びのボタンを、狭い画面で次の行へ送る方法

基本手順

Godotで空のプロジェクトを開いた状態から進めます。Scene → New Sceneで新しいシーンを作り、左のSceneドックでUser Interfaceを選びます。作られたControlをUIに名前変更し、ui.tscnとして保存します。

子ノードは、親にするノードを選んでSceneドックの+を押し、種類を検索してCreateで追加します。ここでは次の親子関係にします。括弧内がノードの種類です。名前を変えるときは対象を選び、F2を押します。

UI (Control)
└ Margin (MarginContainer)
  └ Scroll (ScrollContainer)
    └ Content (VBoxContainer)
      ├ Title (Label)
      ├ Description (Label)
      ├ Actions (HFlowContainer)
      │ ├ Inspect (Button)
      │ ├ Parts (Button)
      │ ├ Reserve (Button)
      │ └ Cancel (Button)
      ├ DetailsTitle (Label)
      ├ Details (Label)
      └ End (Label)

LabelのTextには見出し・説明文・長めの確認用文章を入れます。Endには「ここまで表示できれば末尾の確認は完了です。」など、最後まで見えたことがわかる文を入れておきます。ノードの位置をドラッグでそろえる作業は、ここでは不要です。

1. 画面全体を縮めない検証条件にする

Project → Project Settings → General → Display → Windowを開きます。Viewport Widthを390、Viewport Heightを844にし、StretchのModeをdisabled、Scaleを1.0にします。ResizableはOnのままにします。

手順1。赤枠は検証用のViewport Width・Heightと、StretchのModeです。Aspectはdisabledでは表示結果に影響しません。
手順1。赤枠は検証用のViewport Width・Heightと、StretchのModeです。Aspectはdisabledでは表示結果に影響しません。

この設定は、文字の大きさを保って部品を並べ直すUIを確認するためのものです。横長ゲームのHUDまで一律にdisabledへ変更する、という意味ではありません。ゲーム画面全体を基準解像度から拡大縮小するならcanvas_itemsなどを検討し、その上で配置を調整します。既存のゲームでは別シーンや複製したプロジェクトで試してください。

参考:Godot 4.6 公式 Multiple resolutions

2. 外側のControlを広げて余白を付ける

SceneでUIを選び、InspectorのLayoutを開きます。Layout Modeがある場合はAnchorsにし、Anchors PresetをFull Rectにします。次にMarginも選び、同じくFull Rectにします。UIは画面に、MarginはUIに追従するようになります。

手順2。Marginを選択した状態です。赤枠のAnchors PresetがFull Rectになっていることを確認します。
手順2。Marginを選択した状態です。赤枠のAnchors PresetがFull Rectになっていることを確認します。

続けてMarginのTheme Overrides → Constantsを開き、Margin Left・Top・Right・Bottomのチェックを入れ、すべて20にします。この余白はMarginContainerの設定です。ControlのTransformにある位置やサイズを変更する操作ではありません。

手順2。MarginContainerの四辺の余白を20にした状態です。
手順2。MarginContainerの四辺の余白を20にした状態です。

Scroll以降はContainerの子になります。親Containerが位置やサイズを決めるため、すべての子にFull Rectを設定する必要はありません。Inspectorに「This node is a child of a container.」と出たら、次のContainer Sizingを使う側だと考えると区別しやすくなります。

参考:Godot 4.6 公式 Size and anchors

参考:Godot 4.6 公式 MarginContainer

3. 長くなった内容を縦スクロールできるようにする

Scrollを選び、InspectorのScrollbarでHorizontal Scroll ModeをDisabled、Vertical Scroll ModeをAutoにします。直接の子はContentひとつにし、見出し・説明文・ボタンはContentの下へ入れます。

手順3。赤枠はScrollContainerの横・縦のスクロール設定です。
手順3。赤枠はScrollContainerの横・縦のスクロール設定です。

Autoでは、内容が表示範囲より長くなったときに縦スクロールが使えます。横スクロールを無効にするだけで、幅の広すぎる子が自動的に直るわけではありません。次の手順で、Contentと文字の幅を調整します。

参考:Godot 4.6 公式 ScrollContainer

4. Contentに利用できる横幅を渡す

Contentを選び、Layout → Container Sizingを開きます。Horizontalの配置をFillにして、Expandにチェックを入れます。VerticalはFillのまま、Expandはオフにしておきます。

手順4。赤枠はContentのHorizontalです。Fillに加えてExpandが有効になっています。
手順4。赤枠はContentのHorizontalです。Fillに加えてExpandが有効になっています。

Fillは割り当てられた領域を使い、Expandは利用できる余った領域を受け取るための設定です。ScrollContainerの中にあるContentが横幅を受け取ることで、その下のLabelも折り返す幅を持てます。

ContentのCustom Minimum SizeはX・Yとも0にします。またTheme Overrides → ConstantsのSeparationを18にすると、縦に並ぶ要素の間に余白ができます。最低幅として800などの大きい数値が残っていると、幅390へ縮めてもその幅より小さくなれません。

参考:Godot 4.6 公式 Using Containers

5. Labelを折り返し表示にする

Descriptionを選び、Autowrap ModeをWord (Smart)にします。Title・DetailsTitle・Details・Endも同じ設定にします。Word (Smart)は単語単位を基本に折り返し、ひとつの単語が幅に収まらない場合にも分割します。

手順5。赤枠はDescriptionのAutowrap Modeです。折り返し先の幅は、前の手順で親から受け取っています。
手順5。赤枠はDescriptionのAutowrap Modeです。折り返し先の幅は、前の手順で親から受け取っています。

各LabelのLayout → Custom Minimum SizeをX=120、Y=0にします。Inspector上のFilter Propertiesへminimumと入力すると見つけやすくなります。Godot 4.6.3では、Container内で折り返すLabelの最小サイズが両方0だと警告が出るため、今回は対象の最小画面より十分小さい幅を指定しています。120はこのサンプルの値で、どのUIにも共通の正解ではありません。

手順5。赤枠はLabelの最小サイズです。サンプルではX=120、Y=0にし、文章の高さは内容に合わせます。
手順5。赤枠はLabelの最小サイズです。サンプルではX=120、Y=0にし、文章の高さは内容に合わせます。

Theme Overrides → Font Sizes → Font Sizeは本文のLabelを18、Titleを26、DetailsTitleを22にします。Clip Textはオフ、Max Lines Visibleは-1のままにします。日本語が四角になる場合は、日本語グリフを含むフォントをTheme Overrides → Fonts → Fontへ設定してください。この作例ではNoto Sans CJK JPをSystemFontで指定しています。配布用フォントは別途、利用条件と書き出し先での表示を確認します。

参考:Godot 4.6 公式 Label

参考:Godot 4.6 公式 TextServer

6. 横並びのボタンを次の行へ送る

ActionsにはHBoxContainerではなくHFlowContainerを使います。HFlowContainerは、子が横幅に収まらなくなると次の行へ送るContainerです。ActionsのTheme Overrides → ConstantsでH SeparationとV Separationを12にします。

4つのButtonのTextを「状態を確認」「部品を見る」「修理を予約」「キャンセル」にします。それぞれLayout → Custom Minimum SizeをX=156、Y=48にします。Container Sizingは初期値のFillのままにし、Expandは付けません。

手順6。赤枠はInspectボタンの最小サイズです。残りの3つのButtonも同じ156×48にします。
手順6。赤枠はInspectボタンの最小サイズです。残りの3つのButtonも同じ156×48にします。

この組み合わせなら、幅390では2列×2行、幅768以上では4つ横並びになりました。これは今回の余白・文字・フォント・ボタン幅での結果です。文言を長くしたり、翻訳したりすると、ボタン自体の必要幅も変わるため、同じ幅で再確認してください。

参考:Godot 4.6 公式 HFlowContainer

7. 小さい幅と大きい幅で最後まで確認する

Ctrl+Sで保存して実行します。まず390×844で、説明文が右へ切れないこと、ボタンが次の行に回ること、縦スクロールでEndまでたどり着けることを確認します。見出しだけが収まっていても、下の文章やボタンが見えなければ確認は終わりません。

数値をそろえて比較したい場合は、実行を止め、Project SettingsのAdvanced Settingsを有効にします。Display → Window → SizeのWindow Width OverrideとWindow Height Overrideを変更し、768×900、1440×900でも実行します。Viewport Width・Heightは390×844のままです。ウィンドウの枠を除いた表示領域が確認したいサイズになっているかも見てください。

手順7。画面幅によるレイアウトの比較です。赤枠7は説明文とボタンの並びです。比較画像は縮小表示していますが、本文のFont Sizeはどの画面幅でも18です。
手順7。画面幅によるレイアウトの比較です。赤枠7は説明文とボタンの並びです。比較画像は縮小表示していますが、本文のFont Sizeはどの画面幅でも18です。

ウィンドウ幅を変えても本文のFont Sizeは18のまま、横方向にはみ出さず、末尾までスクロールできることを確かめます。配布する場合は、端末のDPIや画面の縦横比、長い翻訳文、文字を大きくする設定でも確認してください。

手順7の結果。390×844の末尾。赤枠7の確認文まで縦スクロールで到達できています。
手順7の結果。390×844の末尾。赤枠7の確認文まで縦スクロールで到達できています。

うまくいかないときの確認箇所

文字が一文字ずつ縦に並ぶ

Labelの折り返しだけを有効にしても、親から横幅が渡っていないと極端に細くなります。まずScrollの表示範囲が確保されているか、次にContentのHorizontalがFill+Expandか、最後にLabelへ大きすぎる最小幅を入れていないかを確認します。

横スクロールを消しても右側が切れる

Custom Minimum Sizeを、親から子へ順に見ます。実際の最小サイズは、この設定値だけでなく文字・画像・背景の必要サイズにも左右されます。折り返さないLabelや、元画像の幅を最小サイズとして使っているTextureRectがないかも確認します。TextureRectはExpand ModeとStretch Modeが別の設定なので、画像の幅を制御したいのか、縦横比を保ちたいのかを分けて調整します。

参考:Godot 4.6 公式 Control

参考:Godot 4.6 公式 TextureRect

ドラッグで直した位置が元に戻る

Containerの直接の子は、親が位置や大きさを管理します。子のPositionを繰り返し直す前に、親の種類、Separation、子のContainer Sizingを確認してください。自由配置が必要な画面では、Containerが管理する範囲と、通常のControlで配置する範囲を分けます。

収まったのに文字が小さすぎる

大きな基準画面を小さく縮めていないか、Stretch ModeとScaleを確認します。読みづらさを解決するために文章を短く切る前に、折り返し・縦並び・スクロールで読める場所を確保します。HiDPIでは同じ設定値でも見え方が変わるので、必要に応じてユーザーが文字やUIを大きくできる設定も用意します。

画像だけがざらつく

文字は読めるのに小さいアイコンだけがざらつく場合は、画像を大幅に縮小している可能性があります。元画像の解像度や、Mipmaps・Texture Filterを別に確認します。Mipmapsを有効にしても、Labelの折り返しやContainerの幅は直りません。

参考:Godot 4.6 公式 Importing images

まとめ

小さい画面でUIが崩れたら、外側のControlが画面に追従しているか、Containerが子へ幅を渡しているか、文字とボタンが折り返せるか、縦に長くなった内容を最後まで読めるか、という順に確認すると原因を絞れます。

設定を変えた後は、小さい幅だけで終わらせず、大きい幅と長い文章でも同じシーンを開いてみてください。画面に収まることと、読めて操作できることの両方を確認するのがポイントです。