画像の準備
前回の記事までで背景画像を表示する準備が整いました。まずは表示したい画像を用意しないことにははじまりません。生成AIに森の中で道が3本に分かれるシーンを描いてもらいました。
いやこれ4本やん。と私もそう声を荒げてChatGPT 4oさんに何度もつっこんだのですが、あまりこういう生成は得意ではないようです。ほとんど2本になったり、絡み合った模様みたいな道になったり、プロンプトを追加すればするほどカオスになる感じでした(笑)。森の中に3本の道がある絵というのはなかなかないので学習が十分ではないのでしょうかね。まあサンプルですし妥協しました。
この画像を、「res://wood_paths.png」として保存します。「res://」はプロジェクトファイルがあるフォルダでした。これで読み込む画像の準備が整いました。
TextureRectの仕様を確認
次に、画像表示の処理を _ready() に追加しないといけないですね。TextureRectのGodot 4.3のドキュメントを見てみましょう。
TextureRect — Godot Engine (stable) documentation in English
抜粋すると、最終的に下記の set_texture で画像を設定できるのではないかとあたりをつけました。
Texture2D texture
void set_texture(value: Texture2D)
Texture2D get_texture()
The node's Texture2D resource.
ただし、引数に Texture2D 型の画像が必要です。今持っているのはPNGファイルですから、それを何らかの方法で読み込んで、Texture2D 型の変数に変換してあげる必要があります。
画像の読み込みは、Godotエンジンでは実施する方法が主に2つあります。
①インスペクタ(画面右側のGUI)から各ノードのプロパティをぽちぽち設定して実施する
②ノードのreadyやprocess処理内に読み込み処理を記述する
上記の②だと、完全にプログラミングなのですが、①だと全くコードを書かずに済みます。①である程度設定しておいて、残りを②で書くみたいなこともできそうです。いまの私のように中途半端な理解のまま進めていると、逆に、これ①と②どっちでどこまでやるのが正解なの?とわけがわからなくなったりします。ひとまず一番簡単なやり方で、インスペクタとコード両方のやり方で実現してみます。
背景画像の設定(インスペクタから実施)
まずはインスペクタで背景画像を設定する方法です。Godotエンジンの、シーンのところの「TextureRect」を選択し、右の「インスペクター」パネルの、「TextureRect」の「Texture」を確認します。いま「<空>」になっています。その右の「>」ボタンをクリックして、一覧の中から「読み込む」を選択します。
画像を選択します。
こんな風に画像が選択されました。
これだけで完了です。あと、いま「コードに何も書かずにこのGUI設定だけで画像表示ができるか」を検証するのが目的なので、コードに何も記述がないことを確認しておきましょう。
TextureRectノードの texture_rect_background.gd スクリプトの _ready() と _process() には何も処理がありませんね。
さて、この状態で[ビルド]→[実行]を実行してみます。
ゲーム画面が表示されました。
画像の表示ができました。これくらいならコードを書く必要は全くないということですね。画像の表示領域と、テキストの表示領域が噛み合ってないですが、これはあとで直すことにします。
背景画像の設定(コードで実施)
コードだけで背景画像を設定する方法です。TextureRectのドキュメントで既に参照したとおり、TextureRectの、set_texture() メソッドを使えばいいことはわかっています。あとは、その引数で必要な Texture2D をどうやって調達するかですね。
結論からいうと下記のコードで load します。
self.texture = load("res://wood_paths.png")
set_texture(self.texture)
まず、loadってなんだ、なんでここから急に呼べるんだろう?と思った方は鋭いです。TextureRectクラスには load というメソッドはないんですね。ということは、TextureRect クラスの親クラスの誰かが load メソッドをもっているのではないかなと推測しました。TextureRect クラスの継承関係は下記のようになっています。
親クラスのどこにも、「load」メソッドは無いのですね。この load はどこからでてきてん・・と悩み、頭をかきむしり、机の上に大量の髪の毛が散乱し、これでカツラがつくれるんじゃね?と思っていたときのことです。何気なく load のところにカーソルを合わせ、右クリックのメニューに「シンボル検索」とあったので押してみたら、探していた答が出てきました。探し求めている答えは、いつだってすぐ近くにあるものなんですよね(哲学)。
ファイルシステムのパスから、Resourceオブジェクトを返却するとありますね。ResourceLoaderというクラスにある load と同じ実装だそうです。まあそれはいいとして、なぜこれが呼べてしまうのか。この記述のもっと上をみてみましょう。
GDScriptクラス。これは Built-in クラスで、ここに書いてある「ユーティリティ関数やアノテーション」の一覧は全て、「どんなGDスクリプトからでもアクセス可能」(accessible from any script)とのことです。だから load が使えるのですね、納得。
さて、_ready() 内に下記の行を追加します。
これだけです。あとは実行するだけですが、インスペクションのところで、GUIで既に設定済みの場合はそちらが動いてしまい、このコードが本当に動作しているかわからないので、念のため確認して<空>になっていることを確認しましょう。
確認できたら、ビルドして実行してみます。
ゲーム画面が無事表示されました。インスペクターで設定したときとほぼ同じですね(表示領域がずれている問題点も含め)。
これで画像の表示は終了ですが、先ほどのソースについてより深く理解したい人に向けて補足しておきます。まず、追加したコードは下記でした。
self.texture = load("res://wood_paths.png")
set_texture(self.texture)
先ほどみたGDScriptクラスの説明では、load は Resource を返却するとありました。では、self.texture が何者なのか、ついでに調べてみましょう。下記の一文を追加します。
self.texture = load("res://wood_paths.png")
print(self.texture)
set_texture(self.texture)
出力に表示されたのは下記です。
<CompressedTexture2D#-9223372009189145322>
この self.texture は、CompressedTexture2D クラスのオブジェクトであることがわかります。さっきResource といっていたのは嘘だったのか。ひどい。というわけではありません。
CompressedTexture2D のクラス継承図は下記になっています。
CompressedTexture2D というのは、Texture2D クラスの子でもあり、Resource クラスの子でもあります。思うに、load というメソッドは、別に画像に限らず、Resource クラスを親とする非常に多くのクラスのオブジェクトを、ファイルパスから読み取ることができるのだと思います。そのため、GDScript の load メソッドの説明としては、Resource クラスを返却するとしているのですね。
load メソッドで今回読み取った結果、PNG形式のファイルは、CompressedTexture2D と判断されました。これは Texture2D クラスの子クラスでもあるので、Texture2D でもあります。そのため、だいぶ最初の方で書いてましたが、TextureRect の持つメソッド、set_texture の引数としてもふさわしい、ということになるのですね。以上、クラスに関する余談でした。
まとめ
画像を表示することができるようになりました。しかし、表示領域がおかしくなっているので修正が必要です。次回の記事で、これらを修正していきましょう。
それでは今日はこのへんで。
コメント