GodotEngineでポケモンずかん作ってみた解説
挨拶
こんにちは、Godot Engine 4.0のβ版を楽しんでいるSaitosです。
今回、動画にもしている「ポケモン図鑑つくってみた」を解説しようと思ったのですが、すでに記事を3回書き直しています…。
理由は、ノードの機能や個々のレイアウトについてを細かく説明すると、あまりにも内容が多いので、無限に時間が過ぎていくんですよね。
なので、かなり掻い摘んで、サンプルファイルを見てもらう流れにしました。
すいません。
目的

Godot EngineのGUIについての情報共有を目的とするため、今回使用した機能を掻い摘んで説明していきます。
GUIの機能は結構強力で、慣れると楽しいので、ぜひ使ってみてください。
ThemeとTypeVariation
まず、Controlノードにのみ設定できるResourceとしてThemeがあります。
横文字ばかりですが、要するにスキンのようなものです。WebでいうところのCSSのようなものです。
ThemeにはDefault Fontを設定でき、このThemeが設定されたControlノード以下の子ノードたちはすべてこのThemeのフォントやデザインが使用されます。

4.0から、ダイナミックフォントではフォントファイルをそのまま使う事ができる上、サイズを変更しても綺麗に描画されるようになりました。
また、Theme内でTypeを追加し、各ノードにType Variationとして割り当てると、そのTypeの名前がついたノードは同じ見た目になります。
今回のポケモン図鑑では、HeaderとFooterという名前でTypeを追加して使っています。
使い方として、例えば、ThemeでButtonのスタイルを変更するとボタンはすべて同じデザインになってしまいます。
ボタンが2種類あって、別々のデザインにしたい場合、片方にはTheme Overrideを使用してデザインを上書きするような使い方をしなければなりませんでした。
しかしType Variationを使うことで、1つのThemeで個別のデザインを設定できるので、とても便利です。
Containerとレイアウト
Container系のノードは、内包するコンテンツを自動でレイアウトする機能を持っています。
これはレスポンシブ対応のため、画面サイズが変わっても、よい見た目をできる限り保つための機能です。

しかし、場合によっては内包されたコンテンツが、都合の良いサイズにならない場合があります。
例えば、VBoxContainerは、コンテンツを自動的に縦並びにします。
今回のポケモン図鑑でいうと、図鑑のトップ画面はヘッダー・ボディ・フッターの3つの要素で縦並びになっています。
しかし、ヘッダー・フッターは任意のサイズで固定しておきたく、ボディはウィンドウのサイズが変わっても縦に引き伸ばされた状態であってほしいです。

この場合、まずはVBoxContainerに内包したBodyノードのプロパティを変更します。
Bodyノードを選択してインスペクタから、Layout > Container Sizingを開いて、Expandにチェックを入れます。

すると、ウィンドウのサイズが変わってもぴったりと引き伸ばされた状態になります。
次に、HeaderとFooterのノードですが、これらはサイズを固定しておきたいので、Layout > Custom Minimum sizeのX・Yのサイズを指定します。
今回は縦方向なのでYの値を任意の値に変更します。

すると、Bodyが引き伸ばされた影響で潰されていたHeaderとFooterノードですが、入力したサイズで固定されているのがわかります。
Containerで自動レイアウトをした上で、思い通りのサイズを保ちたい場合は、Layoutから調整をすると使いやすくなります。
コンテンツ同士の大きさの比率を設定する
LayoutのContainer Sizingの下部に、Stretch Ratioという項目があります。
これは、並んだコンテンツのうち、選択しているコンテンツの大きさの比率の設定です。
例えば、VBoxContainerに3つのコンテンツが並んでいる場合、デフォルトでは1.0 : 1.0 : 1.0の比率になっています。
つまり1/3ずつの大きさになっています。
これを、0.5 : 0.5 : 1.0とすると、下図のようになります。

また、1.0 : 1.0 : 2.0に設定しても、0.5 : 0.5 : 1.0と同じ比率になります。
TextureRectとテクスチャの設定
TextureRectノードは単純に設定したテクスチャを表示するだけの機能ですが、その表示方法(Stretch Mode)を選ぶことができます。
ストレッチモードを色々変更する場合は、Texture Size Ignore(テクスチャサイズを無視)にチェックを入れておきます。
テクスチャサイズよりも小さくする場合が多いのですが、テクスチャサイズを無視しないと、最小サイズがテクスチャサイズになるので使いにくくなります。
ポケモン図鑑を作る上で、ほぼすべてのTextureRectで、StretchをSTRETCH_KEEP_ASPECT_CENTEREDに設定しています。
これは、画像のアスペクト比を固定してストレッチした上で、中央揃えにする という設定です。

つまり横幅または縦幅のいずれかが狭まった際に、画像が小さく表示されます。
例えば今回のポケモン図鑑の、取得状態のアイコンは、そのまま画像を表示すると大きいため、マージンを空けつつTextureRectはCustom Minimum sizeのXを狭めて細長くしています。
これによりアスペクト比が固定になっているので、中央に揃いながら小さく表示され、微調整が簡単にできました。
TextureRectでできないこと
というか、Controlノードを継承している以上、自動レイアウトに逆らえない部分がある ということです。
例えば、ポケモン図鑑のトップ画面で、ポケモンの名前が入ったボタンにポケモンのドット絵アイコンがついています。

このアイコンは若干はみ出ているのですが、自動レイアウトだとはみ出すことができません。(厳密にはできなくないけど、すごくやりづらい)
なので、今回のポケモン図鑑ではTextureRectではなくNode2DのSprite2Dを子ノードとして使用し、レイアウトしました。
すべてをControlノードで対応しようとすると、仕様によって対応しづらい箇所が出てくるので、臨機応変に使えるものを使うのがよいかと思います。
Buttonとシグナル
Buttonに限らずですが、Controlノードはフォーカスされたときやマウスが乗ったときなどにシグナルを発行します。
このシグナルを受け取って、何らかの処理をします。
今回のポケモン図鑑では管理用のノードがButtonを動的に複数作って、ポケモン図鑑のトップ画面のリストを作成しています。
その際に、Buttonのfocus_enteredとfocus_exitedとpressedのシグナルにconnectして、フォーカスされたらボタンの絵を変更し、フォーカスが外れたら絵を戻し、押されたら画面遷移する処理をしています。

Godot Engineではシグナルのやり取りは必ず発生するので、実際のゲーム部分よりもGUIで慣れるとわかりやすいと思います。
特にボタンのpressedはシグナルで処理する他ないのですが、選択肢がない分、実装方法は限られているので慣れるのにはちょうどいいかと思います。
SubViewportとViewportTexture
SubViewportは、別のシーンの描画結果をテクスチャとして表示するために使います。
例えば2Dゲームの中に3Dシーンを入れたり、その逆も可能です。
GUIも同様に、GUIの中で、部分的に2Dや3Dのシーンを表示させたい という時に便利です。
今回のポケモン図鑑では、ポケモンを選んだ時に表示されるポケモンのプレビューに使っています。

SubViewportをViewportTextureとして使用する場合の注意ですが、ViewportTextureを(シーンツリー上で)参照するノードより上に追加する必要があります。
処理の順番の問題だとは思いますが、エラーが出ますので、回避するために順番にご注意ください。
また、Godot Engine beta7時点でも、ViwportTextureを参照すると、ゲーム本体には影響はありませんが、エディタのログに毎フレームVulkanエラーが出ます。
ひとまずはViewportTextureを設定せずに開発し、最後に設定してあげるなど、ひと工夫して進めれば大丈夫です。(きっとRCには直る…はず!Issueを投げましょう)
サンプルファイル
本プロジェクトはGithubで公開していますので、汚いプロジェクトファイルですが、よろしければご覧ください。
色々細かな処理のスクリプトやシェーダーも含まれています。
かなり解説を端折って、GUIの機能に特化して記事を書きました。
ダラダラと説明しながら映像で解説している動画もありますので、よろしければどうぞ
さいごに
ポケモン図鑑完成のための作業中、Godot JapanのDiscordコミュニティのメンバーに助けていただきながら完成しました。
2022年12月現在400名を超えて、日本のユーザーも徐々に多くなってきたのを感じます。
今回のアドベントカレンダーも含め、Godotコミュニティとしての活動も緩やかに増えていっていますので、最後までご覧頂いた方で、もしコミュニティが気になった方は、ぜひご参加ください。
Discussion