Up to date

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

Singletons (Autoload)

はじめに

Godotのシーンシステムは、強力で柔軟性がある一方、欠点があります: 複数のシーンに必要とされる情報を保存する為の方法が存在しません(例えばプレイヤーのスコアやインベントリ等)。

それを処理出来るにいくつかの代替方法がありますが、それらの方法はそれら自身の制限も伴います:

  • あなたは"master"シーンを使うことが出来、それの子供の他のシーンをロードもしくはアンロード出来ます。しかし、これの意味する所はこれらのシーンを個別にかつ、期待した様に正しく動作させる事が出来ないという事です。

  • 情報はディスクの user:// に保存が可能で、シーンが必要とするならばロード出来ますが、頻繁にデータをセーブとロードする事は面倒でさらに遅くもなります。

シングルトンパターンは、複数のシーン間で同じ情報を保つ必要があるという、一般的なケースにおいて非常に有用なツールです。私たちの場合では、同じシーンもしくはクラスを複数のシングルトンにて再利用する事は、それらシングルトンの名前が異なる限り可能です。

このコンセプトを使うと、オブジェクトを以下のように作る事が出来ます:

  • シーンが現在実行中でも問題なく、いつでもロードされます。

  • プレイヤー情報のようなグローバル変数を保管できます。

  • シーンの遷移の切り替えを操作する事ができます。

  • シングルトンのように動作します、デザインによりGDScript はグローバル変数をサポートしません。

自動読み込みされたノードとスクリプトは我々にこれらの特徴を与えます。

注釈

Godot won't make an Autoload a "true" singleton as per the singleton design pattern. It may still be instanced more than once by the user if desired.

ちなみに

If you're creating an autoload as part of an editor plugin, consider registering it automatically in the Project Settings when the plugin is enabled.

Autoload

You can create an Autoload to load a scene or a script that inherits from Node.

注釈

スクリプトを自動読み込みする時、Nodeが作られそれにスクリプトがアタッチされます。このノードは他のシーンがロードされる前にルートビューポートに追加されます。

../../_images/singleton.webp

To autoload a scene or script, select Project > Project Settings from the menu and switch to the Autoload tab.

../../_images/autoload_tab.webp

Here you can add any number of scenes or scripts. Each entry in the list requires a name, which is assigned as the node's name property. The order of the entries as they are added to the global scene tree can be manipulated using the up/down arrow keys. Like regular scenes, the engine will read these nodes in top-to-bottom order.

../../_images/autoload_example.webp

これの意味する所は以下のようにすれば"PlayerVariables"と名付けられたシングルトンにアクセス出来るという事です:

var player_vars = get_node("/root/PlayerVariables")
player_vars.health -= 10

If the Enable column is checked (which is the default), then the singleton can be accessed directly in GDScript, without requiring get_node():

PlayerVariables.health -= 10

自動読み込みオブジェクトはちょうどシーンツリーの中の他のノードの様にアクセスされる事を心に留めて下さい。実際には、もし実行中のシーンツリーを見たら、自動読み込みされたノードが現れるでしょう:

../../_images/autoload_runtime.webp

警告

Autoloads must not be removed using free() or queue_free() at runtime, or the engine will crash.

カスタムシーン・スイッチャー

This tutorial will demonstrate building a scene switcher using autoloads. For basic scene switching, you can use the SceneTree.change_scene_to_file() method (see シーンツリーの使用 for details). However, if you need more complex behavior when changing scenes, this method provides more functionality.

To begin, download the template from here: singleton_autoload_starter.zip and open it in Godot.

The project contains two scenes: scene_1.tscn and scene_2.tscn. Each scene contains a label displaying the scene name and a button with its pressed() signal connected. When you run the project, it starts in scene_1.tscn. However, pressing the button does nothing.

Creating the script

Open the Script window and create a new script called global.gd. Make sure it inherits from Node:

../../_images/autoload_script.webp

The next step is to add this script to the autoLoad list. Open Project > Project Settings from the menu, switch to the Autoload tab and select the script by clicking the browse button or typing its path: res://global.gd. Press Add to add it to the autoload list:

../../_images/autoload_tutorial1.webp

これでスクリプトはプロジェクトのシーンを実行する時は、毎回ロードされる様になりました。

Returning to the script, it needs to fetch the current scene in the _ready() function. Both the current scene (the one with the button) and global.gd are children of root, but autoloaded nodes are always first. This means that the last child of root is always the loaded scene.

extends Node

var current_scene = null

func _ready():
    var root = get_tree().root
    current_scene = root.get_child(root.get_child_count() - 1)

今、我々はシーンを遷移させる為の関数を必要としています。この関数はカレントシーンを開放し、要求されたものに置き換える必要があります。

func goto_scene(path):
    # This function will usually be called from a signal callback,
    # or some other function in the current scene.
    # Deleting the current scene at this point is
    # a bad idea, because it may still be executing code.
    # This will result in a crash or unexpected behavior.

    # The solution is to defer the load to a later time, when
    # we can be sure that no code from the current scene is running:

    call_deferred("_deferred_goto_scene", path)


func _deferred_goto_scene(path):
    # It is now safe to remove the current scene.
    current_scene.free()

    # Load the new scene.
    var s = ResourceLoader.load(path)

    # Instance the new scene.
    current_scene = s.instantiate()

    # Add it to the active scene, as child of root.
    get_tree().root.add_child(current_scene)

    # Optionally, to make it compatible with the SceneTree.change_scene_to_file() API.
    get_tree().current_scene = current_scene

Object.call_deferred()の使用時は、カレントシーンが完了してから、2つ目の関数のすべてのコードが1回だけ実行されます。従って、カレントシーンは使用されている間には削除されません (すなわち、カレントシーンのコードはまだ実行中です)。

最後に、2つのシーンの空のコールバック関数を満たさなければなりません。

# Add to 'scene_1.gd'.

func _on_button_pressed():
    Global.goto_scene("res://scene_2.tscn")

そして

# Add to 'scene_2.gd'.

func _on_button_pressed():
    Global.goto_scene("res://scene_1.tscn")

プロジェクトの実行とテストをするとボタンを押す事によりシーンの間を切り替えられます。

注釈

シーンが小さい時にはこの遷移は瞬時に行われます。しかし、シーンがより複雑な場合、表示されるのに大量の時間がかかります。これの操作を学ぶには、次のチュートリアルを見て下さい:バックグラウンド読み込み

また、読み込み時間が比較的短い場合 (3秒以下など) は、シーンが変わる直前に何らかの2D要素を表示して「ローディング中」画面を表示することもできます。そして、シーンが切り替わった直後にそれを隠すことができます。これは、シーンがロード中であることをプレイヤーに示すために使用できます。