Open11

Godot Engine / GDScript備忘録

ピン留めされたアイテム

これは何?

私がGodot Engineを使っていく中で、

  • 気になった挙動
  • ハマったポイント
  • たまに使うが、よく忘れてしまうTips

などのメモを取っていくスクラップです。

引数付シグナルは、接続のタイミングを考えるべし

  • シグナルに引数を設定した場合、シグナルを接続した時点の値が渡される
  • シグナルの接続後に参照元の変数に別の値を代入しても、接続時の値が参照される

ですので、例えば以下のコードでは、マウスオーバー時には bar ではなく _id の初期値である foo が出力されます。これは、シグナルの接続後に _id の値を変更しているためです。

extends Control
var _id = "foo"

func _ready():
  self.connect("mouse_entered", self, "_on_mouse_entered", [_id])
  _id = "bar"

func _on_mouse_entered(id):
  print(id) # 実行結果 → foo

デフォルト引数に計算式を指定してもOK

例として、以下のコードではインスタンスのサイズに1.25を乗算した数を、計算式ごとデフォルト引数として設定しています。

func set_new_size(transformed_size:Vector2 = rect_size * 1.25):
  self.rect_size = transformed_size

条件文でクラスタイプを比較する場合には「is」

Godotには、インスタンス型チェッカーとしてis演算子が用意されています[1]。条件文でクラスの比較をしたい場合にはとても便利ですね。

ただし、Godot 3.3.2時点ではカスタムクラス名にはtrueを返してくれません。継承元のクラス名を比較に使う必要があります。

extends GridContainer
class_name ExtendedGridContainer


func _ready():
  if self is ExtendedGridContainer:
    print("foo")
  elif self is GridContainer:
    print("bar")

# 実行結果は bar になります。

継承元のクラスと混同したくない場合

あまりスマートじゃないかも知れませんが、カスタムクラスのname変数を設定する方法があります。

extends GridContainer
class_name ExtendedGridContainer


func _ready():
  self.name = "ExtendedGridContainer"
  if self.name == "ExtendedGridContainer":
    print("foo")
  elif self is GridContainer:
    print("bar")

# 実行結果は foo になります。
脚注
  1. GDScriptの基本に書いてあるのにすぐ忘れてしまいます。 ↩︎

add_child()しないと、_ready()等は発生しない

Godot DocsのNodeのページにも記載の通り、_ready()はノードがツリーに加わると実行されます。

Object、Referene、Resourceを拡張して使用する場合には、add_child()ができません。つまり、必然的に_ready()_enter_tree()、そして_input(event)に書かれたコードは実行されないことになります。

Godotで内部クラスの継承をする

Godotでは内部クラスの継承が可能です。…が、ほとんど誰も使ってないのか、英語ですらあまり情報が出てきません。念の為、備忘録として情報を残しておきます。


例えば、以下のような構造の内部クラスがあったとします。

extends Node

class_name ParentClass

func _ready():
    #do something

# ParentClassの内部クラス
class InnerClass extends Reference:
    func _init():
        #do something

例えばParentClassを継承した上で、その内部クラスであるInnerClassを継承する場合には、以下のように書けば良いです[1]

extends ParentClass # クラスの継承

class_name ChildClass

func _ready():
    #do something

# ParentClassの「InnerClass」を継承した内部クラスを
# 親クラス名 + ドット + 親クラスの内部クラス名で指定し、継承
class ChildInnerClass extends ParentClass.InnerClass: 
    func _init():
        #do something

脚注
  1. 外側のクラスは必ずしもParentClassを継承する必要はなく、無関係なクラスの内部クラスを直接継承することも可能です。 ↩︎

.tresファイルの中身を変数として読み出す

公式のドキュメントやコミュニティにもあまり情報がなかったのですが、Godotのリソースファイルである.tresファイルは、スクリプト内で簡単に変数として読み出しができます。


以下に.tresファイルの中身を例示します。行ごとに変数名・値が書かれていて、.iniファイルなどに似ています。

example.tres
[resource]
bg_color = Color( 0.2, 0.2, 0.2, 1 )
border_width_left = 2
border_width_top = 2
border_width_right = 2
border_width_bottom = 2
anti_aliasing = false
position = Vector2(8, 8)

例えば上記の.tresファイルから、positionbg_colorを読み出ししたい場合、GDScript内ではこう書けばOKです。拍子抜けするくらい簡単。

var tres_variables = load("res://***/exapmle.tres")
var position = tres_variables.position
var bg_color = tres_variables.bg_color

print(position) # -> Vector2(8, 8)
print(bg_color) # -> Color(0.2, 0.2, 0.2, 1)

テーマファイルから特定の変数を読み出す場合には、以下のように書くことができます。

var theme_variables = load("res://***/exapmle_theme.tres")
var bezier_len_neg = theme_variables.get_theme_item(Theme.DATA_TYPE_CONSTANT, "bezier_len_neg", "GraphEdit")

print(bezier_len_neg) # -> GraphEditノードのTheme ConstantsであるBezier Len Negの値が出力されます。

ノードのプロパティに対してsetget

Godot 3.4時点では、rect_sizeや、positionなど、継承元のノードのプロパティに対しsetgetを定義することはできません。が、_set_getなどのメソッドをオーバーライドすることは可能です。これを利用して、プロパティに対してsetter、getter(のようなもの)を実装することが可能です[1]

サンプル
# self.rect_sizeに値を代入すると、その値がログに出力される
func _set(property, value):
    if property == "rect_size":
        print(rect_size) 

# positionの値が読み出されると、その値がログに出力される
func _get(property):
    if property == "position":
        print(position)

_setが反応するためには、rect_sizeではなくself.rect_sizeで値を代入しなければならない点には注意が必要。また、参照元のQ&Aには「_setを使って値を書き換えようとすると無限ループに陥るため、少し複雑な処理を要する」と、サンプルコードとともに書かれています(こちらは未検証)。

脚注
  1. 参照元:https://godotengine.org/qa/74149/add-setget-onto-existing-variable-from-inherited-class ↩︎

AtlasTextureのクセを知る

repeat, mirrored repeatは無視される

Godotのドキュメントにも記載があります[1]が、AtlasTextureflagsのうちrepeatmirrored repeatオプションは無視されます。つまりAtlasTextureを使って画像を反復させることは、基本的にできません。
無視されるflagオプション
これらのフラグはチェックを入れても無視されます


スクリプトで値を変更すると同期される

スクリプトからregionflagsの値などを変更すると、同じAtlasTextureを参照して表示されている画像全てに変更が反映されます[2]

脚注
  1. https://docs.godotengine.org/ja/stable/classes/class_atlastexture.html ↩︎

  2. AtlasTexture固有の挙動ではないと思うのですが、備忘録のために言及。 ↩︎

ログインするとコメントできます