🏃

【Godot Engine】シーンチェンジ先のシーンに引数を渡す その2

に公開

はじめに

SceneTree.change_scene()でシーンを変更する時は、変更先のシーンに引数を渡せません。
前回は、AutoLoadを使用して擬似的に引数を渡す方法を紹介しましたが、グローバル変数を使っているのが個人的に好みではなかったので他の方法を探してきました。
今回はRelayクラスを作って変数を中継する方法を紹介します。

方法

UseRelayNode.gd
extends Node2D
@onready var Line = $LineEdit 

func _on_button_pressed():
    var relay = Relay.new_relay(Line.text)
    var packed = PackedScene.new()
    packed.pack(relay)
    get_tree().change_scene_to_packed(packed)
Relay.gd
extends Node
class_name Relay
@export var text:String

static func new_relay(text:String) -> Relay:
    var relay = Relay.new()
    relay.text = text
    return relay

func _ready() -> void:
    var scene_file:PackedScene = load("res://UseRelayNode/NewScene.tscn")
    var scene_node = scene_file.instantiate()
    scene_node.text = text
    get_tree().root.add_child(scene_node)
    free()
NewScene.gd
extends Node2D
@onready var label = $Label
var text:String

func _ready() -> void:
    label.text = text

このコードでは、MainシーンのButtonを押下した時、
LineEdit.textの値をRelay.gd経由でNewScene.gdに渡しています。

Relay.gdstatic func new_relay(text:String)にてインスタンスを作成していますが、_init(text:String)を作って同様のことをしようとすると次のようなエラーが発生し、シーンチェンジ先のRelayに値を渡せなくなります。

error
E 0:00:04:0069   UseRelayNode.gd:9 @ _on_button_pressed(): Error constructing a GDScriptInstance: 'Node(Relay.gd)::_init': Method expected 1 arguments, but called with 0
  <C++ エラー>      Method/function failed. Returning: nullptr
  <C++ ソース>      modules/gdscript/gdscript.cpp:196 @ _create_instance()
  <スタックトレース>     UseRelayNode.gd:9 @ _on_button_pressed()

RelayはなくてもOK

NewScene.gdtext@exportをつけ、ボタンの挙動を次の実装にすると、Relayを噛ませなくても直接シーンチェンジすることはできます。

NotUseRelayNode.gd
extends Node2D
@onready var Line = $LineEdit 

func _on_button_pressed():
extends Node2D
@onready var Line = $LineEdit 

func _on_button_pressed():
    var scene_file:PackedScene = load("res://UseRelayNode/NewScene.tscn")
    var scene_node = scene_file.instantiate()
    scene_node.text = Line.text
    var packed = PackedScene.new()
    packed.pack(scene_node)
    get_tree().change_scene_to_packed(packed)

ただ、移動先のシーンが大きい場合PackedSceneinstantiate()した上でPack()し直す挙動で無駄にメモリを使っていそうな気がする(測ってない)ので基本はRelayを使い、移行先のファイルが小さいなら直接シーンチェンジするのが良いと思います。

Discussion