【Godot Engine】画面遷移時のシーンのローディングのやり方を検討してみる

公式ドキュメント

SceneTree — Godot Engine latest documentation

Background loading — Godot Engine latest documentation

公式ドキュメントを読んで ResourceLoader を使用すれば実現できるのはなんとなく理解できたけど、いまいちコレと言った決定的なやり方が示されていない印象。

読み込みスクリプト

公式ドキュメントの Background loading の章で説明されているサンプルスクリプトをベースにしています。

SceneLoader.gd

extends Node

# 読込進捗通知シグナル
signal _scene_loading(percent)
# 読込完了シグナル
signal _loaded_scene(scene)
# 読込失敗シグナル
signal _scene_load_error

# ローディング実行時間
const limit_msec = 100
# ローダー
var loader

# 対象シーンパス設定
func set_target_scene(path):
    # ローダー作成
    loader = ResourceLoader.load_interactive(path)
    if loader == null:
        return FAILED
    return OK

# ローディング処理
func process(delta):
    if loader == null:
        return
    var time = OS.get_ticks_msec()
    while OS.get_ticks_msec() < time + limit_msec:
        var ret = loader.poll()
        if ret == OK:
            # 読み込み実行
            continue
        elif ret == ERR_FILE_EOF:
            # 読み込み完了
            emit_signal('_loaded_scene', loader.get_resource())
            return
        else:
            # 読み込み失敗
            emit_signal('_scene_load_error')
            loader = null
            return
    # 進捗通知
    var p = float(loader.get_stage() + 1) / float(loader.get_stage_count())
    emit_signal('_scene_loading', p)

自動ロード

作成したスクリプトを自動読み込みに登録します。

f:id:erudoru:20180326232018p:plain

これで全てのシーンから SceneLoader という名称でアクセスできます。

サンプルシーン作成

3つのシーン(画面)を作成します。

  • FromScene.tscn ・・・ 遷移元画面
  • Loading.tscn ・・・ ローディング画面
  • ToScene.tscn ・・・ 遷移先画面

遷移元画面

ボタン一つだけのシンプルな画面です。

f:id:erudoru:20180326232538p:plain

スクリプト

extends Node

func _on_Button_pressed():
    # ターゲットに遷移先のパスを設定
    SceneLoader.set_target_scene('res://ToScene.tscn')
    # ローディング画面に遷移(軽量な画面なのでchange_sceneで遷移)
    get_tree().change_scene('res://Loading.tscn')

ローディング画面

ローディング中画面は背景を黒く塗りつぶして、ローディングの進捗をテキストで表示

f:id:erudoru:20180326232829p:plain

スクリプト

extends Control

func _enter_tree():
    SceneLoader.connect("_scene_loading", self, "_on_scene_loading")
    SceneLoader.connect("_loaded_scene", self, "_on_loaded_scene")
    SceneLoader.connect("_scene_load_error", self, "_on_scene_load_error")

func _process(delta):
    SceneLoader.process(delta)

func _exit_tree():
    SceneLoader.disconnect("_scene_loading", self, "_on_scene_loading")
    SceneLoader.disconnect("_loaded_scene", self, "_on_loaded_scene")
    SceneLoader.disconnect("_scene_load_error", self, "_on_scene_load_error")

func _on_scene_loading(p):
    # ローディング中の画面表示を更新
    $Label.text = "Loading... %d" % [int(p * 100)]

func _on_loaded_scene(scene):
    # 画面遷移
    get_tree().change_scene_to(scene)

func _on_scene_load_error(error_type):
    # エラーの場合の表示
    print('error:' + str(error_type))

遷移先画面

遷移元画面とほぼ同じ

f:id:erudoru:20180326232538p:plain

extends Node

func _on_Button_pressed():
    # ターゲットに遷移先のパスを設定
    SceneLoader.set_target_scene('res://FromScene.tscn')
    # ローディング画面に遷移(軽量な画面なのでchange_sceneで遷移)
    get_tree().change_scene('res://Loading.tscn')

動作確認

画面自体が軽量なのでほぼ一瞬で遷移してしましますが一応ローディング中の表示が行われます。

f:id:erudoru:20180326233718p:plain