Godot 4.0で変わったところ
概説
フリーのゲーム開発エンジンGodot Engineのバージョン4.0 beta1
を実際に使ってみて、3.5.x
からの変化で個人的に戸惑った点を書き連ねていきます。同じく3.x系
からの移行する方の手助けになれば幸いです。
4.0
に戸惑ったら、随時追記していく予定です。
この記事の更新履歴
2022-09-18 :
export
, String
のキャスト, enum
, Tween
, アンチエイリアスについて
2022-09-20 :
シグナルを加筆
2022-09-21 :
フォント, 変更になった関数名・変数名など, setgetの書き方を加筆
2022-09-22 :
型キャストまわり / → string型を加筆
2022-09-29 :
シグナルで引数を渡す方法を加筆
2022-10-01 :
ディレクトリやファイルの操作はDirAccess
、FileAccess
でを加筆
2022-10-07 :
Popup
のexclusive
の動作条件変更を加筆
2022-10-08 :
pause_mode
がprocess_mode
に変更に
2023-05-07 :
OpenSimplexNoise
→ FastNoiseLite
バグや所感、無くなった機能など
これらについては、Godotのバージョンアップで解消されていくと思われるので、スクラップにしてまとめています。
GDScript
export → @export
4.0
から変数のexport
が@export
に変わりました。また、@export_node_path
などexport
自体の種類も増えました。
以下にint
型の場合の書き方を示します。4.0の方がシンプルですね。
export (int) var foo:int = 1 # Godot 3.x
@export var bar:int = 1 # Godot 4.0+
enumが型として使えるようになった
4.0
から、enum(列挙型)
が型として使えるようになりました。簡単なコードを以下に例示します。
enum SampleType {TYPE_A, TYPE_B}
# Godot 3.xでenum型の変数を宣言する場合 -----------------------------------
var sample_type:int = SampleType.TYPE_A # 宣言するときはint型
export (SampleType) var sample_type:int # exportの書き方が少し複雑
# Godot 4.0+でenum型の変数を宣言する場合 ----------------------------------
var sample_type:SampleType = SampleType.TYPE_A # SampleType型として宣言できる
@export var sample_type:SampleType # exportがシンプルになった
Tweenの書き方が刷新された
こちらの記事を参照してください。
型キャストまわり
String
型
→ String(42)
みたいな感じで、int
やfloat
を雑にString型
にキャストするString()
関数は4.0
で廃止されました。
結論から書くと、単純なString型
へのキャストはvar_to_str()
を使うのが良さそうです。
詳細は以下の通りです:
調べた限りでは、var_to_str()
str()
String.num_int64()
などの関数でString型
に変換できます。なお、String.num_int64()
はint型
からのキャストにのみ対応しており、var_to_str()
とstr()
は、さまざまな型からのキャストが可能です。
いずれの関数もちゃんとString型
に変換できるか、typeof()
関数を使って実際に動作確認してみます。
# int型の変数を宣言
var i:int = 42
print(typeof(i)) # → 出力結果:2(int)
# ここから下のコードでString型にキャストします
# Godot 3.x での int → String キャスト -------------------------------
var the_answer = String(i)
print(typeof(the_answer)) # → 出力結果:4(=String)
# Godot 4.0+ での int → String キャスト ------------------------------
var casted_answer_one = String.num_int64(i)
var casted_answer_two = str(i)
var casted_answer_three = var_to_str(i)
print(typeof(casted_answer_one)) # → 出力結果:4(=String)
print(typeof(casted_answer_two)) # → 出力結果:4(=String)
print(typeof(casted_answer_three)) # → 出力結果:4(=String)
ちなみに、var_to_str()
とstr()
はほとんど挙動が同じでしたが、速度には少し差がありました。
単純なint -> String
の型キャストを100万回行うスクリプトを10回ほど実行したところ、処理に要した時間の平均はvar_to_str()
がおおよそ270msecで、str()
が310msec程度でした(String.num_int64()
は275msecくらい)。
Array -> String
を100万回型キャストした場合は、var_to_str()
が1380msec、str()
が1800msec前後でした。Dictionary -> String
の場合は、それぞれ5000msec, 7000msec前後です。
普通は100万回も型変換することはないと思いますが、var_to_str()
関数を使うとほんの少しだけ早そうです。
シグナル
シグナル自体がクラスになり、connect()
の書き方が変わりました。
以下のサンプルコードでは、子ノードである$Button
のbutton_down
とbutton_up
シグナルを使って、ログを出力します。
Godot 4.0+ のconnect文の箇所、button_down
とbutton_up
で微妙に書き方が違いますが、どちらもやっていることは同じで、呼び出したいメソッドをconnect()
の引数に指定しています。後者の方がシンプルですし、typoが起きづらくて良さそう。引数を使う場合の書き方はこちらです。
func _ready():
# Godot 3.x のconnect文 --------------------------------
$Button.connect("button_down", self, "_on_button_down")
# Godot 4.0+ のconnect文 -------------------------------
$Button.button_down.connect(Callable(self, "_on_button_down"))
$Button.button_up.connect(_on_button_up)
# シグナルで呼び出されるメソッドの書き方は、3.x, 4.0で共通
func _on_button_down():
print("pressed")
func _on_button_up():
print("released")
ちなみに、Godot 4.0からはconnect()
の第1引数に無名関数(ラムダ式)を書けるので、ちょっとした処理ならわざわざ別途関数を用意する必要がなくなりました。便利ですね。
$Button.button_down.connect(func(): print("pressed"))
シグナルについては、以前submaxさんの記事でも紹介されています。
シグナルで引数を渡す方法
emit_signal()
を使って引数を渡す方法はGodot 3.x
と同じですが、connect()
の時点で引数を設定する場合は、3.x
とはやり方が変わっているので注意が必要です。
4.0
では、引数付きのCallable
オブジェクトを返す関数であるbind()
を使う必要があります。
コードを見ていただいた方が早いかと思います。
func _ready():
# bindで任意の個数の引数を設定できる
$Button.button_down.connect(_on_button_down.bind("foo", "bar"))
func _on_button_down(arg1, arg2):
print(arg1, arg2) # $Buttonを押下すると「foobar」と出力される
なお、connect()
時点で引数を設定した場合は、その値がdisconnect()
するまで保持されます。変数を代入した場合には、参照ではなく値を渡すので注意してください。
変更になった関数名・変数名・クラス名など
変更になった変数名などで、ちょっと調べる必要があったものやアナウンスがあったものを列挙します。なお、DirAccess
、FileAccess
については後述します。
クラス名
-
Directory
→DirAccess
-
File
→FileAccess
-
OpenSimplexNoise
→FastNoiseLite
-
FastNoiseLite
ではSimplex
を含む、さまざまなタイプのノイズの生成ができるそうです
-
関数名
-
CanvasItem.update()
→CanvasItem.queue_redraw()
-
PackedScene.instance()
→PackedScene.instantiate()
DirAccess
、FileAccess
で
ディレクトリやファイルの操作はGodot 4.0 beta2
から、Directoryクラス
がDirAccess
に、Fileクラス
がFileAccess
になりました。また、クラス名が変わっただけでなく、いくつかの関数がstatic
になった他、new()
を使った初期化やclose()
処理が不要になりました。
static
でない関数も残っており、例えばDirAccess
で相対パスを扱う関数は初期化が必要です。ただ、初期化する場合も明示的にnew()
を呼び出す必要はありません。open()
関数で、任意のディレクトリを開いた状態で初期化されます。
以下にサンプルコードを載せます。
# open()関数で初期化し、同時に指定したパスを開く
var directory = DirAccess().open("res://Sprites/")
# res://Sprites/ ディレクトリにある file_a.txt を file_b.txt に変更
directory.rename("file_a.txt", "file_b.txt")
なお、上記の例で言えば絶対パスを使ってファイル名やディレクトリ名を変更する場合は、rename()
ではなく、rename_absolute()
を使うことができます。こちらはstatic
な関数なのでopen()
を使った初期化は不要で、DirAccess.rename_absolute(from, to)
のように書きます。ただし、絶対パスでしか動きません。
setgetの書き方
-
3.x
:変数の宣言後にsetget
と書いて、その後にsetter, getterの関数をそれぞれ指定する書き方でした。 -
4.0
:変数の宣言と併せて処理を書き込むことができます。
以下に、全く同じsetget処理をするスクリプトを引用します。
# Godot 3.x のsetget --------------------------
var foo = 100 setget _foo_set, _foo_get
func _foo_set(value):
print(value) # 値を代入したら、代入した値が出力される
foo = value
func _foo_get():
print(foo) # 値をgetしたら、 fooの値が出力される
return foo
# Godot 4.0+ のsetget -------------------------
var foo = 100:
set(mod_value):
print(mod_value) # 値を代入したら、代入した値が出力される
foo = mod_value
get:
print(foo) # 値をgetしたら、 fooの値が出力される
return foo
pause_mode
がprocess_mode
に変更に
ノードのpause_mode
プロパティが、process_mode
に変更になりました。それに伴い、SceneTree
のプロセスをポーズした際のノードの挙動が細かく設定できるようになりました。設定できる値は以下の通りです。
-
PROCESS_MODE_INHERIT
親ノードのプロセス状態を引き継ぐ(ルートノードに限り、PROCESS_MODE_PAUSABLE
と同じ挙動) -
PROCESS_MODE_PAUSABLE
SceneTree
がポーズされた場合にプロセスが止まり、ポーズが解除されると動きだす -
PROCESS_MODE_WHEN_PAUSED
SceneTree
がポーズされた場合にだけ動く -
PROCESS_MODE_ALWAYS
SceneTree
がポーズされたかどうかに関わらず常に動作する -
PROCESS_MODE_DISABLED
SceneTree
がポーズされたかどうかに関わらずプロセスが止まる
3.x
までと比較して、プロセスのポーズが簡単に細かく設定できるようになりました。SceneTree
がポーズされたときにだけ動くノードを実装できたり、非常に利便性が高まった印象です。
シーンの編集関連
画像 / スプライト / テクスチャのアンチエイリアス設定
3.5.x
までは、インポートの際に画像ごとにフィルタの設定をしましたが、4.0
からはプロジェクト設定
か、CanvasItem.texture_filter
プロパティから、CanvasItem
系のフィルタの挙動を設定するようになったようです。
基本的には、プロジェクト設定
でCanvasItem
系のノードの初期値を設定し、ノードごとに挙動を変更したい場合はCanvasItem.texture_filter
を設定する運用が良さそうです。
最初は戸惑いましたが、プロジェクトごとにまるっと管理できるので、3.x系
より便利な印象。
CanvasItemのアンチエイリアスの初期値を設定する
プロジェクト設定
から設定できます。以下の項目を探して変更するようにしてください。なお、プロジェクト設定
画面の右上にあるAdvanced Settings
を有効にするのを忘れないでください。
プロジェクト設定 > レンダリング > Textures > Default Texture Filter
テクスチャのアンチエイリアスを個別に設定する
個別にアンチエイリアスの設定を変更したい場合には、CanvasItem
のtexture_filter
プロパティから変更するのが良さそうです。
フォント
4.0
ではフォントの機能が大幅に拡張されています。大きなところだと例えばOpenType機能
が使えるようになったり、右→左で書き方向が設定できたり、フォントだけで記事が3, 4本書けそうな充実感です。ここでは、3.xからの移行でつまずいたポイントに絞って触れます。
DynamicFont
BitmapFont
は廃止
フォント関係はDynamicFont
BitmapFont
クラスが無くなり、SystemFont
FontFile
FontVariation
などのクラスが実装されました。3.x系
とはガラリと顔ぶれが変わっている印象です。まだそれぞれのクラスの役割を把握しきれていないので、改めて追記するかもしれません。
システムフォントが使えるSystemFont
クラスは、特定の環境では非常に便利そうです。
フォントの見た目に関する設定
3.5.x
までは、素のフォントデータとは別にDynamicFont
リソースを用意し、そこでフォントの描画に関するプロパティを設定していました。4.0
からはテクスチャと同じ感覚で、フォントデータ自体にさまざまなプロパティを付与できるように仕様変更されています。例えばアンチエイリアス
の設定も、フォントデータ自体に付与します。
そのほかの文字の見た目に関する細かいプロパティは、別途FontVariation
のリソースを用意して設定します。
FontVariation
クラス
FontVariation
では、フォントの描画に関するプロパティの設定ができます。具体的には任意の比率で太字にしたり、長体にしたり、斜体にしたりできますし、OpenType機能
を使うこともできます。extra spacing
の設定もここです。
なお、フォントデータをダブルクリックして開いたウィンドウのPre-render configurations
タブにあるconfiguration
からも、一部FontVariation
と同じ項目が設定できます。
フォントの設定画面。左の赤枠部分が、フォントデータをダブルクリックして開いたもので、右の緑枠がFontVariation
の設定画面。私がインポートしたフォントは、FontVariation
でのみOpenType機能
が使えます。(ちなみにRendering Options
タブにあるOpenType Features
の項目ですが、ここから設定できるOpenType機能
が無いフォントもあるそうなので、ご注意ください。今後のバージョンで設定項目がない場合は、ボタン自体が非表示になるそうです🙏)
Popup
のexclusive
の動作条件変更
Popup
系のクラスが、Control
ではなくWindow
を継承するクラスに変更になりました。それに伴って、exclusive
プロパティの動作条件が、親ウィンドウのtransient
プロパティがtrue
であることになったようです。
Popup
系のクラスのexclusive
をtrue
にするだけでは、想定した挙動にならないので、ポップアップを使う場合には注意が必要です。
Discussion