静的型付けGDScript

このガイドでは、次の内容について学習します:

  • GDScriptで型を使用する方法
  • 静的型はバグの回避に役立ちます

この新しい言語機能をどこで、どのように使うかは完全にあなた次第です!

静的型は、変数、定数、関数、パラメータ、戻り値の型に使用できます。

注釈

型付きGDScriptはGodot 3.1から使用できます。

静的型付けの概要

型付きのGDScriptを使うことで、Godotはコードを書く際にさらに多くのエラーを検出することができます。メソッドを呼び出すと引数の型が表示されるため、作業中に詳細な情報が得られます。

あなたが在庫管理システムをプログラミングしていると想像してください。 Item ノード、次に Inventory をコーディングします。アイテムをインベントリに追加するには、コードを操作する人々は常に ItemInventory.add メソッドに渡す必要があります。型を設定すれば、これを強制できます:

# In 'Item.gd'.
class_name Item
# In 'Inventory.gd'.
class_name Inventory


func add(reference: Item, amount: int = 1):
    var item = find_item(reference)
    if not item:
        item = _instance_item_from_db(reference)

    item.amount += amount

型付きGDScriptのもう1つの重要な利点は、新しい警告システムです。バージョン3.1以降のGodotではコードを記述する際に警告が表示されます: 実行時に問題を引き起こす可能性のあるコードのセクションが識別されますが、コードをそのままにしておくかどうかを決めることができます。これについては後で説明します。

静的型を使用すると、コード補完オプションも改善されます。以下に、 PlayerController というクラスの動的型補完オプションと静的型補完オプションの違いを示します。

あなたはおそらく以前に変数にノードを格納していて、オートコンプリートの提案なしで残されるようにドットをタイプしました:

code completion options for dynamic

これは動的コードによるものです。Godotは、関数に渡されているノードまたは値のタイプを認識できません。ただし型を明示的に記述すると、すべてのpublicメソッドと変数がノードから取得されます:

code completion options for typed

将来的には、型付きGDScriptによってコードのパフォーマンスも向上します。ジャストインタイムコンパイルやその他のコンパイラの改善はすでにロードマップに盛り込まれています!

全体として、型付きプログラミングはあなたにもっと構造化された経験を与えます。それはエラーを防ぎ、あなたのスクリプトの自己文書化の側面を改善するのを助けます。これはチームや長期的なプロジェクトで作業している場合に特に役立ちます。開発者が他の人のコードや過去に書いたスクリプトを読んで忘れていたことがほとんどの時間を費やしていることが調査によってわかっています。コードがより明確でより構造化されているほど、理解するのが早くなるほど、早く進むことができます。

静的型付けの使用方法

変数または定数の型を定義するには、変数の名前の後にコロンを書き、その後に指定する型を書きます。例: var health: int これにより、変数の型は常に保持されます:

var damage: float = 10.5
const MOVE_SPEED: float = 50.0

コロンを書くと、Godotは型を推測しようとしますが、型を省略します:

var life_points := 4
var damage := 10.5
var motion := Vector2()

現在、3種類の…タイプを使用できます:

  1. ビルトイン
  2. コアクラスとノード ( ObjectNodeArea2DCamera2D など)
  3. 独自のカスタムクラス。新しい class_name 機能を調べて、型をエディタに登録します。

注釈

Godotは割り当てられた値から自動的に型を設定するので、定数の型ヒントを書く必要はありません。ただしコードの意図をより明確にするために、これを行うこともできます。

カスタム変数型

カスタムクラスを含む任意のクラスを型として使用できます。スクリプトで使用する方法は2つあります。最初の方法は、定数の型として使用するスクリプトをプリロードすることです:

const Rifle = preload("res://player/weapons/Rifle.gd")
var my_rifle: Rifle

2番目の方法は、作成時に class_name キーワードを使用することです。上記の例では、Rifle.gdは次のようになります:

extends Node2D
class_name Rifle

class_name を使用する場合、GodotはRifle型をグローバルにエディタに登録します。定数にプリロードすることなく、どこでも使用できます:

var my_rifle: Rifle

変数のキャスト

型キャストは型付き言語の重要な概念です。キャストは、ある型から別の型への値の変換です。

extends Area2D であなたのゲームに敵がいると仮定してください。あなたはそれを PlayerController と呼ばれるスクリプトが付いている KinematicBody2D と衝突させたいのです。衝突を検出するには on_body_entered シグナルを使用します。型付きコードでは、 _on_body_entered コールバックでは、検出したボディは一般的な PhysicsBody2D になり、 PlayerController にはなりません。

この PhysicsBody2D がプレイヤーであるかどうかを確認するには、 as キャストキーワードを使用し、再度コロン : を使用して変数にこの型を使用させます。これにより、変数は PlayerController タイプに固定されます:

func _on_body_entered(body: PhysicsBody2D) -> void:
    var player := body as PlayerController
    if not player:
        return

    player.damage()

ここではカスタム・タイプを扱っているため、 bodyPlayerController を拡張しない場合、 player 変数は null に設定されます。これを使って、体がプレイヤーかどうかを確認できます。このキャストのおかげで、player変数の完全なオートコンプリートもできるようになります。

注釈

組み込み型でキャストしようとして失敗すると、Godotはエラーをスローします。

セーフ・ライン

セーフ・ラインを確保するためにキャストを使用することもできます。セーフ・ラインは、はGodot 3.1の新しいツールで、あいまいなコード行がセーフな型であることを教えてくれます。型指定されたコードと動的なコードを混在させることができるため、Godotには実行時に命令がエラーを引き起こすかどうかを知るための十分な情報がない場合があります。

これは子ノードを取得したときに起こります。たとえばタイマーを考えてみましょう。動的コードでは、$Timer でノードを取得できます。GDScriptは ダック・タイピング <https://stackoverflow.com/a/4205163/8125343> をサポートしているので、あなたのタイマーが Timer 型であっても、それは Node であり Object でもあり、2つのクラスが拡張しています。動的GDScriptでは、呼び出す必要のあるメソッドがある限り、ノードの種類についても気にする必要はありません。

ノードを取得したときに期待される型をGodotに伝えるためにキャストを使用できます: ($Timer as Timer)($Player as KinematicBody2D) など。Godotは、そのタイプが機能することを確認し、機能する場合は、行番号がスクリプトエディタの左側で緑に変わります。

Safe vs Unsafe Line

セーフ・ラインVSセーフでないライン

注釈

セーフ・ラインをオフにするか、エディタ設定でカラーを変更することができます。

アロー(->)による関数の戻り値の定義

関数の戻り値の型を定義するには、宣言の後に -> を記述し、その後に戻り値の型を記述します:

func _process(delta: float) -> void:
    pass

void 型は、関数が何も返さないことを意味します。変数と同様に、任意の型を使用できます:

func hit(damage: float) -> bool:
    health_points -= damage
    return health_points <= 0

独自のノードを戻り値の型として使用することもできます:

# Inventory.gd

# Adds an item to the inventory and returns it.
func add(reference: Item, amount: int) -> Item:
    var item: Item = find_item(reference)
    if not item:
        item = ItemDatabase.get_instance(reference)

    item.amount += amount
    return item

静的と動的: どちらかのみを利用する

型付きGDScriptと動的GDScriptは、同じプロジェクト内に共存できます。しかし、コードベースの一貫性のためにも、仲間のためにも、どちらかスタイルに固定することをお勧めします。同じガイドラインに従うことで全員が協力しやすくなり、他の人のコードを素早く読んで理解できるようになります。

型定義されたコードはもう少し作成が必要ですが、上で説明したような利点があります。次に、同じ空のスクリプトを動的なスタイルで示します:

extends Node


func _ready():
    pass


func _process(delta):
    pass

そして静的型付けでは:

extends Node


func _ready() -> void:
    pass


func _process(delta: float) -> void:
    pass

このように、エンジンの仮想メソッドで型を使用することもできます。シグナルのコールバックも、他のメソッドと同様に型を使用できます。動的スタイルの body_entered シグナルは次のとおりです:

func _on_Area2D_body_entered(body):
    pass

同じコールバックをタイプヒントとともに使用します:

func _on_area_entered(area: CollisionObject2D) -> void:
    pass

パラメータを自動的にキャストするには、 CollisionObject2D などを独自の型に自由に置き換えます:

func _on_area_entered(bullet: Bullet) -> void:
    if not bullet:
        return

    take_damage(bullet.damage)

bullet 変数にはここで任意の CollisionObject2D を保持できますが、それが独自に作成したノードである Bullet であることを確認します。 Area2D など、 Bullet を拡張していないノードなど、それ以外のものがある場合、 bullet 変数は null になります。

警告システム

この警告システムは型付きGDScriptを補完します。これはコーディング中に発見しにくく、ランタイムエラーにつながる可能性のあるミスを回避するのに役立ちます。

プロジェクト設定 の GDScript という新しいセクションで警告を設定できます:

warning system project settings

警告システムプロジェクト設定

スクリプトエディタのステータスバーにアクティブなGDScriptファイルに関する警告の一覧が表示されます。次の例には、3つの警告があります:

warning system example

警報システム例

1つのファイル内の特定の警告を無視するには、 #warning-ignore:<警告ID> という形式の特別なコメントを挿入するか、警告の説明の右側にある無視リンクをクリックします。Godotは対応する行の上にコメントを追加し、対応する警告を表示しなくなります:

warning system ignore example

警告システム無視の例

またファイル内で、特定の種類の警告をすべて無視するには、# warning-ignore-all:<警告ID>を、すべての種類の警告を無視するには# warnings-disableのコメントを追加します。

警告によってゲームの実行が妨げられることはありませんが、必要に応じてエラーにすることができます。こうすると、すべての警告を修正しない限りゲームはコンパイルされません。このオプションをオンにするには、プロジェクト設定の GDScript セクションに移動します。前の例と同じファイルで、エラーとしての警告がオンになっているものを次に示します:

warnings as errors

エラーとしての警告

型を指定できない場合

この紹介の締めくくりに、タイプヒントを使用できないいくつかのケースを取り上げましょう。 以下の例はすべてエラーを引き起こします

Enumを型として使うことはできません:

enum MoveDirection {UP, DOWN, LEFT, RIGHT}
var current_direction: MoveDirection

配列の個々のメンバの種類を指定することはできません。これにより、エラーが発生します:

var enemies: Array = [$Goblin: Enemy, $Zombie: Enemy]

for キーワード・ループの各要素にはすでに異なる型があるため、 for ループで型の割り当てを強制することはできません。したがって、次のように書くことは**できません**:

var names = ["John", "Marta", "Samantha", "Jimmy"]
for name: String in names:
    pass

2つのスクリプトは、循環的に相互に依存することはできません:

# Player.gd

extends Area2D
class_name Player


var rifle: Rifle
# Rifle.gd

extends Area2D
class_name Rifle


var player: Player

概要

型付きGDScriptは強力なツールです。Godotのバージョン3.1から利用できるようになり、より構造化されたコードの記述、一般的なエラーの回避、スケーラブルシステムの作成に役立ちます。将来的には、コンパイラーの最適化によって静的型のパフォーマンスも大幅に向上するでしょう。