Godot Custom scene switcher自定义场景切换器

本教程将演示使用自动加载功能构建场景切换器。 对于基本的场景切换,可以使用SceneTree.change_scene()方法(有关详细信息,请参见SceneTree)。 但是,如果在更改场景时需要更复杂的行为,则此方法可提供更多功能。

首先,请从此处下载模板:autoload.zip并在Godot中将其打开。

该项目包含两个场景:Scene1.tscn和Scene2.tscn。 每个场景都包含一个显示场景名称的标签和一个连接了其pressed()信号的按钮。 运行项目时,它从Scene1.tscn启动。 但是,按此按钮不起作用。

Global.gd

切换到“脚本”选项卡并创建一个名为Global.gd的新脚本。 确保它继承自Node:

cinemachine切换场景 场景切换软件_加载

下一步是将此脚本添加到autoLoad列表中。 从菜单中打开“项目”>“项目设置” ,切换到“自动加载”选项卡,然后通过单击浏览按钮或键入其路径来选择脚本:res://Global.gd。 按添加将其添加到自动加载列表中:

cinemachine切换场景 场景切换软件_自动加载_02

现在,无论何时在项目中运行任何场景,该脚本都将始终加载。

返回脚本,它需要在_ready()函数中获取当前场景。 当前场景(带有按钮的场景)和Global.gd都是root的子级,但是自动加载的节点始终是第一个。 这意味着root的最后一个孩子始终是加载的场景。

extends Node

var current_scene = null

func _ready():
    var root = get_tree().get_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.instance()

    # Add it to the active scene, as child of root.
    #将它添加到活动场景中,作为根的子级。
    get_tree().get_root().add_child(current_scene)

    # Optionally, to make it compatible with the SceneTree.change_scene() API.
    #(可选)使其与SceneTree.change_scene()API兼容。
    get_tree().set_current_scene(current_scene)

使用Object.call_deferred(),仅当当前场景中的所有代码完成后,第二个函数才会运行。 因此,当前场景仍在使用中(即其代码仍在运行)将不会被删除。

最后,我们需要在两个场景中填充空的回调函数:

#Add to 'Scene1.gd'.

func _on_Button_pressed():
    Global.goto_scene("res://Scene2.tscn")

and

#Add to 'Scene2.gd'.

func _on_Button_pressed():
    Global.goto_scene("res://Scene1.tscn")

运行该项目并测试您可以通过按下按钮在场景之间进行切换。

Note
当场景较小时,过渡是瞬时的。 但是,如果您的场景比较复杂,则可能需要花费相当长的时间才能显示出来。 要了解如何处理此问题,请参阅下一个教程:后台加载。

或者,如果加载时间相对较短(少于3秒左右),则可以在更改场景之前通过显示某种2D元素来显示“加载信息”。 然后,可以在场景更改后立即将其隐藏。 这可以用于向播放器指示正在加载场景。