Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

リソース

ノードとリソース

ここまでのチュートリアルではGodotの、エンジンのほとんどの機能が頼りにしている、Node(ノード)クラスについて主に紹介してきました。もうひとつ、同じくらい重要なデータ型はResource(リソース)です。

Node は、機能を提供します。例えばスプライトや3Dモデルの表示、物理演算、ユーザーインターフェースの配置などです。一方、Resourceデータの格納に使います。それ自身はなにもしませんが、代わりにノードが、データの入ったリソースを使用します。

Anything Godot saves or loads from disk is a resource. Be it a scene (a .tscn or an .scn file), an image, a script... Here are some Resource examples:

エンジンがリソースをディスクから読み込む際に、読み込むのは一度きりです。もしメモリ上にすでにリソースのコピーがあれば、読み込む代わりに毎回そのコピーを返します。リソースはデータのみを含むので、重複させても意味はないのです。

ノードとリソースにかかわらず、すべてのオブジェクトは、自身のプロパティをエクスポートできます。プロパティには、String、整数(int)、Vector2など、さまざまな種類がありますが、これらすべての型はリソースになることができます。つまり、ノードとリソースはいずれも、他のリソースをプロパティとして持てるのです。

../../_images/nodes_resources.webp

外部と組み込みの比較

リソースを保存する方法はふたつあります。それは:

  1. シーンの外部。個別のファイルとしてディスクに保存。

  2. 内蔵。使用する*.tscnあるいは*.scnファイルの中に保存。

To be more specific, here's a Texture2D in a Sprite2D node:

../../_images/spriteprop.webp

Clicking the resource preview allows us to view the resource's properties.

../../_images/resourcerobi.webp

Pathプロパティはリソースの元々の場所を表しています。この例の場合は、元は robi.png と名付けられたPNG画像です。このように、元がファイルであれば、外部リソースになります。Pathを消去するか、あるいはこの場所にない場合は、内部リソースになります。

リソースの内部と外部の切り替えは、シーンを保存するときに行われます。上記の例の場合、もしパス "res://robi.png" を消去してから保存すると、Godotは画像を .tscn シーンファイルの内部に保存します。

注釈

もし内部リソースを保存した場合でも、複数のシーンをインスタンス化したときは、エンジンがそのコピーを読み込むのは一度だけです。

コードからリソースを読み込む

コードにてリソースを読み込む方法は、ふたつあります。ひとつ目は load() 関数で、いつでも使えます:

func _ready():
    # Godot loads the Resource when it reads this very line.
    var imported_resource = load("res://robi.png")
    $sprite.texture = imported_resource

You can also preload resources. Unlike load, this function will read the file from disk and load it at compile-time. As a result, you cannot call preload with a variable path: you need to use a constant string.

func _ready():
    # Godot loads the resource at compile-time
    var imported_resource = preload("res://robi.png")
    get_node("sprite").texture = imported_resource

シーンの読み込み

Scenes are also resources, but there is a catch. Scenes saved to disk are resources of type PackedScene. The scene is packed inside a Resource.

To get an instance of the scene, you have to use the PackedScene.instantiate() method.

func _on_shoot():
        var bullet = preload("res://bullet.tscn").instantiate()
        add_child(bullet)

このメソッドは、シーンの階層どおりにノードを作成し、それらを設定してから、そのシーンのルートノードを返します。これは他のノードの子にすることができます。

The approach has several advantages. As the PackedScene.instantiate() function is fast, you can create new enemies, bullets, effects, etc. without having to load them again from disk each time. Remember that, as always, images, meshes, etc. are all shared between the scene instances.

リソースの解放

When a Resource is no longer in use, it will automatically free itself. Since, in most cases, Resources are contained in Nodes, when you free a node, the engine frees all the resources it owns as well if no other node uses them.

独自のリソースを作成

Godotの他のオブジェクトと同様に、ユーザーはリソースをスクリプト化することもできます。リソーススクリプトは、オブジェクトプロパティと、シリアル化されたテキストまたはバイナリデータ (*.tres, *.res) との間で、自由に変換できる機能を継承します。また同時に、参照型から参照カウントメモリ管理機能を継承します。

This comes with many distinct advantages over alternative data structures, such as JSON, CSV, or custom TXT files. Users can only import these assets as a Dictionary (JSON) or as a FileAccess to parse. What sets Resources apart is their inheritance of Object, RefCounted, and Resource features:

  • 定数を定義できるため、他のデータフィールドまたはオブジェクトの定数は必要ありません。

  • プロパティの設定(setter)と取得(getter )用のメソッドを含むメソッドを定義できます。これにより、基になるデータの抽象化とカプセル化が可能になります。(カプセル化する事によって)リソーススクリプトの構造を変更する必要が発生した場合でも、そのリソースを使用するゲームをその都度それに合わせて変更する必要が無くなります。

  • シグナルを定義できるため、リソースは管理するデータの変更に対する応答をトリガーできます。

  • プロパティが定義されているため、ユーザーは自分のデータが存在することを100%知っています。

  • リソースの自動シリアル化と逆シリアル化は、 Godot エンジンの組み込み機能です。ユーザーは、リソース ファイルのデータをインポート/エクスポートするためにカスタム ロジックを実装する必要はありません。

  • リソースはサブリソースを再帰的にシリアル化することもできるため、ユーザーはさらに高度なデータ構造を設計できます。

  • ユーザーは、リソースをバージョン管理に適したテキストファイル(*.tres)として保存できます。ゲームをエクスポートすると、Godotはリソースファイルをバイナリファイル(*.res)としてシリアル化し、読書きの速度と圧縮率を向上させます。

  • Godotエンジンのインスペクタは、すぐに使用できるリソースファイルをレンダリングおよび編集します。そのため、多くの場合、ユーザーはデータを視覚化または編集するためにカスタムロジックを自分で実装する必要はありません。リソースに関するこの作業を行うには、ファイルシステムドックでリソースファイルをダブルクリックするか、インスペクタのフォルダアイコンをクリックして、ダイアログでファイルを開きます。

  • 基本リソースだけでなく、その他のリソースタイプも拡張できます。

Godotを使用すると、インスペクタでカスタムリソースを簡単に作成できます。

  1. インスペクタでプレーンなリソースオブジェクトを作成します。これは、スクリプトがその型を拡張可能なら、新たなリソースを派生させる原型にもできます。

  2. インスペクタで script プロパティをスクリプトに設定します。

インスペクタにリソーススクリプトのカスタムプロパティが表示されます。これらの値を編集してリソースを保存すると、インスペクタはカスタム プロパティもシリアル化します。インスペクタからリソースを保存するには、インスペクタのツールメニュー(右上)をクリックし、「保存」または「名前を付けて保存」を選択します。

If the script's language supports script classes, then it streamlines the process. Defining a name for your script alone will add it to the Inspector's creation dialog. This will auto-add your script to the Resource object you create.

Let's see some examples. Create a Resource and name it bot_stats. It should appear in your file tab with the full name bot_stats.tres. Without a script, it's useless, so let's add some data and logic! Attach a script to it named bot_stats.gd (or just create a new script, and then drag it to it).

extends Resource

@export var health: int
@export var sub_resource: Resource
@export var strings: PackedStringArray

# Make sure that every parameter has a default value.
# Otherwise, there will be problems with creating and editing
# your resource via the inspector.
func _init(p_health = 0, p_sub_resource = null, p_strings = []):
    health = p_health
    sub_resource = p_sub_resource
    strings = p_strings

Now, create a CharacterBody3D, name it Bot, and add the following script to it:

extends CharacterBody3D

@export var stats: Resource

func _ready():
    # Uses an implicit, duck-typed interface for any 'health'-compatible resources.
    if stats:
        stats.health = 10
        print(stats.health)
        # Prints "10"

Now, select the CharacterBody3D node which we named bot, and drag&drop the bot_stats.tres resource onto the Inspector. It should print 10! Obviously, this setup can be used for more advanced features than this, but as long you really understand how it all worked, you should figure out everything else related to Resources.

注釈

リソーススクリプトは、UnityのScriptableObjectsに似ています。インスペクタは、カスタムリソースの組み込みサポートを提供します。ですが、必要に応じて、ユーザーは独自のコントロールベースのツールスクリプトを設計し、それらを EditorPlugin と組み合わせて、データ用のカスタムビジュアライゼーションとエディタを作成することもできます。

Unreal Engine's DataTables and CurveTables are also easy to recreate with Resource scripts. DataTables are a String mapped to a custom struct, similar to a Dictionary mapping a String to a secondary custom Resource script.

# bot_stats_table.gd
extends Resource

const BotStats = preload("bot_stats.gd")

var data = {
    "GodotBot": BotStats.new(10), # Creates instance with 10 health.
    "DifferentBot": BotStats.new(20) # A different one with 20 health.
}

func _init():
    print(data)

Instead of inlining the Dictionary values, one could also, alternatively:

  1. Import a table of values from a spreadsheet and generate these key-value pairs.

  2. Design a visualization within the editor and create a plugin that adds it to the Inspector when you open these types of Resources.

CurveTablesも同じですが、float値の配列または Curve/Curve2D リソースオブジェクトにマッピングされます。

警告

リソース ファイル (*.tres/*.res) は、使用するスクリプトのパスをファイルに格納します。リソース ファイルが読み込まれると、そのスクリプトをフェッチして型の拡張機能として読み込みます。スクリプトでサブクラス、つまりスクリプトの内部クラス (GDScript で class キーワードを使用するなど) を割り当てようとしても、それは機能しません。Godot は、スクリプト サブクラスのカスタム プロパティを正しくシリアル化しません。

以下の例では、Godotは Node スクリプトを読み込み、それが Resource を拡張していないことを確認して、互換性がないタイプなので、スクリプトがリソースオブジェクトのロードに失敗したと判断します。

extends Node

class MyResource:
    extends Resource
    @export var value = 5

func _ready():
    var my_res = MyResource.new()

    # This will NOT serialize the 'value' property.
    ResourceSaver.save(my_res, "res://my_res.tres")