1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GodotEngineで画面やプロセスに関するいくつかのTips

Posted at

はじめに

今回は以前記事にしたカメラ映像のネタの続きに関する実装方法やその他ちょっとだけプロセスに関する機能を紹介しようと思う。

画面に関するTips

複数のカメラ映像を重ねた後の画面サイズの調整について

以前、GodotでUnityのカメラと同じく優先度をつけて映像を重ねたい場合のテクニックを紹介した。

このテクニックの最後でカメラ映像がウィンドウサイズと合わずに隙間ができることに触れた。
本来のデフォルトのビューポートとカメラ映像だと、ウィンドウサイズを変えるとちゃんとカメラ映像とビューポートのサイズは追随する。

さすがにこのような表示のままではゲームやアプリとして活用しづらいかもしれない。

image.png

そこで、SubViewportContainerとSubViewportを使った場合でもちゃんとウィンドウサイズに追随するようにしてみた。

手順

たとえば次のように、SubViewportとCamer3Dを複数設置していたとする。

image.png

  1. ルートウィンドウのサイズ変更イベントを用意する
  2. _ready処理の中でイベントを接続する

適当なノードにスクリプトをアタッチし、ルートつまりWindowに対して size_changed のイベントを接続する。

test.gd
func _ready():
    #---root(Windowsのインスタンス)の size_changedシグナルにリサイズイベントを接続する
	get_tree().root.connect("size_changed", _on_window_resize)

## リサイズイベント
func _on_window_resize():
    #---デフォルトのビューポートのサイズを取得
	#var viewport_size = get_viewport().get_visible_rect().size
    var winsize = get_tree().root.size
	print(viewport_size, winsize)
	
	#---UIという名前のノードだとする
    #   念の為SubViewportContainerの親のControlノードのサイズも変更しておく
	self.size = Vector2(winsize.x, winsize.y)

	#---SubViewportContainer
    var maincamera_container: SubViewportContainer = get_node("MainCameraContainer")
    maincamera_container.size = Vector2(winsize.x, winsize.y)
    #---各SubViewport
	(maincamera_container.get_node("FrontMainViewport") as SubViewport).size = Vector2(winsize.x, winsize.y)
	(maincamera_container.get_node("IKViewport") as SubViewport).size = Vector2(winsize.x, winsize.y)
 

ポイントは、ルート(Window)のビューポートのサイズ size を取得することだ。
他にも get_visible_rect()でも取得できるのだが、こちらは描画されているウィンドウつまり四角形の大きさを取得するため厳密には画面解像度を含めたサイズではない。こちらを使うとSubViewportの映像が想定通りの解像度にならないことがあったので、使うなら size だ。

この size を、SubViewportContainer自体と、子のSubViewport達の size プロパティにも代入してあげる。
これでウィンドウのサイズを変更したときでも各SubViewportの映像もきちんとサイズが追随して変更される。

無題の動画.gif

複数ビューポートを使っている場合のスクリーンショットの取得方法

ゲーム画面の現在の映像をスクリーンショットに撮るのは、公式マニュアル にもあるように、次の一文でよい。

get_viewport().get_texture().get_image().save_jpg("user://testscreenshot00.jpg")

ただ、SubViewportContainerとSubViewportを使っていたり、任意の解像度でスクリーンショットを取得したい場合はこれだけでは足りない。

次のようにする。

func capture_screen():
    var FULLRESOLUTION = Vector2i(1920,1080)
	#---通常のスクリーンショットの撮り方
	get_viewport().get_texture().get_image().save_jpg("user://testscreenshot00.jpg")

	#---サブビューポートが複数あり、それぞれのスクリーンショットの撮り方
    #一時的に解像度も変更する(サブビューポート単位で可)
	(maincamera_container.get_node("FrontMainViewport") as SubViewport).size = FULLRESOLUTION
	(maincamera_container.get_node("IKViewport") as SubViewport).size = FULLRESOLUTION
    #---画面解像度変更を待たないといけない
	await get_tree().create_timer(0.1).timeout
    #---特定のSubViewportのスクリーンショットを取得して保存
	(maincamera_container.get_node("FrontMainViewport") as SubViewport).get_texture().get_image().save_jpg("user://testscreenshot01.jpg")
	(maincamera_container.get_node("IKViewport") as SubViewport).get_texture().get_image().save_jpg("user://testscreenshot02.jpg")
	print_debug("save screenshot!")
    #---念の為待つ
	await get_tree().create_timer(0.1).timeout
    #---解像度を戻す(rootのサイズを代入)
	(maincamera_container.get_node("FrontMainViewport") as SubViewport).size = get_tree().root.size

Godotでは、Viewport/SubViewportが画面操作の起点となる。現在の映像をテクスチャ(ViewportTexture)として取得するメソッドが get_texture() として備わっているので非常に扱いやすい。

サブビューポートをそのまま参照してもよいが、ゲームやツールの機能として任意の解像度でスクリーンショットを取得したい場合もあるだろう。
そういうときは、取得対象の映像が出力されるサブビューポートのサイズを変更してあげればよい。
ただし、すぐ画像として保存することはできないので、 create_timer でわずかにウェイトを入れよう。

サブビューポートから取得したViewportTextureから、Imageを取得する。
そのImageの save_jpg メソッドを呼び出せば、ローカルディスクに保存できる。

また、Webビルドなどでスクリーンショットを保存したい場合には、 save_jpg_to_buffer メソッドを使ってバイト配列をjavascript側に渡してやれば保存できると思われる。

公式マニュアルはこちら。

整理するとこうだ。
カメラ→テクスチャ→画像として保存
ではなく、
ビューポート(with カメラ)→テクスチャ→画像として保存
ということになる。

複数のSubViewportを使っていると、個々のSubViewportをそれぞれ別目的で活用しやすい。
テクスチャをこのようにスクリーンショットとして保存できたり、 Unityでいうところのレンダーテクスチャ的に他のノードへと連携して活用したりとできる。

その他Tips

ノードを完全に無効化する

ノードをそもそも動かさないようにするためには、process_mode を変更する。

var charabody3d = get_node("CharacterBody3D") #名前が型と同じ例
#---無効化(一切動かない)
charabody3d.process_mode = Node.PROCESS_MODE_DISABLED
#---有効化
charabody3d.process_mode = Node.PROCESS_MODE_INHERIT
#---親と関係なく常に有効化であれば下記でも良い。
charabody3d.process_mode = Node.PROCESS_MODE_ALWAYS

公式マニュアルはこちら。
enum ProcessMode

Unityでいうところの enabled やSetActiveに相当すると思われる。

終わりに

以上、画面に関する操作と、プロセスに関するTipsを紹介した。

Unityだとこうすればよかったけど、Godotではどうするの?というTipsを今後も発見や実践したら紹介していきたい。

今回のネタも、Godotだとビューポートの使い方さえ覚えておけばすぐできる(少なくともSubViewportを使わなければたった一文でできる)ので、個人的にはかなりわかりやすくて使いやすい。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?